
🌐 Aussi en: English · Deutsch · Español
Mon homelab compte trois contrôleurs de domaine, deux clients, trois cartes de gestion iLO et, jusqu’à la semaine dernière, exactement zéro certificat auquel qui que ce soit avait une raison de faire confiance. Chaque session RDP commençait par un avertissement, chaque iLO m’accueillait avec « Votre connexion n’est pas privée » (émetteur : Default Issuer (Do not trust), ce qui a au moins le mérite de l’honnêteté), et les contrôleurs de domaine ne parlaient pas du tout LDAPS.
Je n’héberge que peu de services web internes, alors pendant un moment j’ai considéré qu’une PKI privée était une solution en quête de problème. Erreur. Un domaine Windows regorge d’endroits où les certificats améliorent discrètement les choses. L’astuce consiste à laisser Active Directory les distribuer tout seul, pour ne plus jamais avoir à penser à leur renouvellement.
Même méthode que dans les précédents articles Windows : je décide, et mon co-admin IA (Claude, qui pilote PowerShell via WinRM et les iLO via Redfish) construit et vérifie chaque étape. Cette fois, la vérification incluait le contrôle de nos propres handshakes TLS depuis une machine Linux avec openssl s_client.
🎯 Ce qui profite vraiment des certificats
- Contrôleurs de domaine : avec un certificat « Kerberos Authentication », ils parlent LDAPS sur le port 636 et savent faire du Kerberos par certificat (un prérequis pour des choses comme Windows Hello for Business).
- Bureau à distance : RDP utilise un certificat auto-signé par machine. Avec un certificat émis par la CA, la boîte de dialogue « l’identité de l’ordinateur distant ne peut pas être vérifiée » disparaît, et un vrai avertissement d’attaque de l’homme du milieu signifierait de nouveau quelque chose.
- WinRM sur HTTPS (5986) : mon automatisation passait par HTTP avec le chiffrement des messages NTLM. Ça marche, mais un vrai TLS avec une identité de serveur vérifiable, c’est mieux.
- Interfaces web des iLO : les grands classiques du « cliquer pour ignorer l’avertissement ».
- Signature de code : un certificat pour moi, afin de pouvoir signer mes scripts de démarrage PowerShell et, à terme, n’autoriser que les scripts signés.
Absent de la liste : tout ce qui est public. Nextcloud et le blog restent chez Let’s Encrypt, car une racine privée n’est reconnue que par mes propres appareils, et c’est bien tout l’intérêt.
🏛️ Conception : un seul niveau, sur un DC, et pourquoi c’est un compromis
La PKI des manuels a deux niveaux : une CA racine hors ligne, éteinte dans un tiroir, qui ne signe que la CA émettrice, plus une CA émettrice qui fait le travail quotidien. Si la CA émettrice est compromise, on la révoque et la racine survit.
J’ai construit une Enterprise Root CA à un seul niveau : « Muench Homelab Root CA », RSA 4096, SHA-256, valable 10 ans, sur HP3. C’est un compromis assumé. Mes trois serveurs sont tous des contrôleurs de domaine, et une CA sur un DC a de vrais inconvénients : le serveur ne peut plus être renommé, et le rétrograder devient compliqué. Sans serveur membre et sans hyperviseur, il n’y a pour l’instant pas de meilleur foyer pour elle. Quand un hyperviseur arrivera, une architecture à deux niveaux avec une VM racine hors ligne sera l’étape suivante naturelle.
Trois décisions avant le premier clic :
CAPolicy.infavecLoadDefaultTemplates=0. Sans cela, une Enterprise CA toute neuve publie immédiatement une douzaine de modèles par défaut avec des droits d’inscription généreux. C’est dans ces paramètres par défaut que se cachent la plupart des chemins d’attaque AD CS connus. Ma CA a démarré avec zéro modèle publié.- Listes de révocation et certificat de la CA uniquement via LDAP. Les extensions CDP/AIA par défaut pointent aussi vers
http://<ca>/CertEnroll/, un serveur web qui n’existe pas ici. Les clients essaieraient et tomberaient en timeout. Tous les clients de ce domaine savent lire LDAP, donc HTTP dégage. - Pas d’inscription web. Les vieilles pages
/certsrvsont la cible de l’attaque par relais NTLM connue sous le nom d’ESC8. Pas installé, pas nécessaire.
Plus l’hygiène barbante : audit de la CA activé, certificats émis plafonnés à deux ans. Et la base de données de la CA fait partie de la sauvegarde nocturne de l’état système de HP3, qui existe depuis l’article précédent.
📜 Modèles : petits, serrés et explicites
Un modèle de certificat décide de ce que peut faire un certificat et de qui peut le demander. Se tromper sur le « qui », c’est ainsi que des domaines tombent : le célèbre ESC1 est un modèle où un utilisateur peu privilégié peut inscrire n’importe quel nom dans la demande, y compris celui d’un administrateur du domaine. Il y a donc quatre modèles, chacun avec les droits les plus restreints qui fonctionnent encore :
| Modèle | Usage | Sujet | Qui peut s’inscrire |
|---|---|---|---|
| Kerberos Authentication (intégré) | Certificats des DC : LDAPS, Kerberos | depuis AD | Domain Controllers (auto) |
| HomelabComputer | RDP, WinRM HTTPS | depuis AD (CN + SAN DNS = FQDN) | Domain Computers + DC (auto) |
| HomelabWebServer | iLO, plus tard Windows Admin Center | fourni dans la demande | Domain Admins uniquement, manuel |
| HomelabCodeSigning | signature de scripts PowerShell | depuis AD | moi (auto, à l’ouverture de session) |
Le modèle WebServer est le dangereux, car c’est le demandeur qui choisit le nom. C’est précisément pour cela que seuls les Domain Admins peuvent l’utiliser. Et le flag de CA EDITF_ATTRIBUTESUBJECTALTNAME2 (ESC6, « laisser les demandeurs ajouter n’importe quel SAN comme attribut de requête ») reste désactivé. Les noms viennent du CSR lui-même, ce qui suffit pour les iLO.
Créer des modèles sans interface graphique (et trois pièges)
PowerShell n’a pas de New-CATemplate. Le « Dupliquer le modèle » de la MMC n’est en réalité que la copie d’un objet AD : un pKICertificateTemplate sous CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration, plus un objet msPKI-Enterprise-Oid correspondant avec un OID tout neuf sous la base OID de la forêt. C’est donc ce que nous avons fait, attribut par attribut : version de schéma 2, flags de nom, flags d’inscription, EKU, puis l’ACL avec les droits étendus Enroll et AutoEnroll. En chemin :
- Les variables PowerShell ne sont pas sensibles à la casse.
$Econtenait le GUID Enroll,$eétait la variable de boucle. Devinez laquelle a gagné. - PowerShell déroule les tableaux à un seul élément.
@(@('512','manual'))n’est pas une liste contenant une paire, c’est la paire elle-même, donc la boucle a joyeusement tenté de résoudre l’utilisateur « 5 ». La solution, c’est la virgule unaire :@(,@('512','manual')). Add-CATemplatesoutenait mordicus que les tout nouveaux modèles « n’existent pas dans le domaine », alors quecertutil -templateles listait sans problème.certutil -SetCATemplates +HomelabComputer,…les a publiés du premier coup.
Et l’éternel classique : WinRM transmet les scripts en Base64 UTF-16 sur une ligne de commande plafonnée à 8191 caractères. Un script de modèle est passé de 2 970 à 3 170 caractères et a silencieusement cessé de faire quoi que ce soit. Pas d’erreur, pas de sortie. Mon co-admin compte désormais les caractères avant d’envoyer. Moi aussi.
🤖 Inscription automatique : le moment où AD fait le travail
Une GPO, homelab – PKI Auto-Enrollment, liée à la racine du domaine : inscription automatique pour les ordinateurs et les utilisateurs, avec « renouveler les certificats expirés » et « mettre à jour les certificats en attente » activés. Après un gpupdate et un certutil -pulse, chaque DC détenait en moins d’une minute deux nouveaux certificats : Kerberos Authentication et HomelabComputer, avec le bon FQDN, valables un an. Le renouvellement a lieu six semaines avant l’expiration, et personne n’a rien à retenir.
Les DC ont adopté automatiquement le certificat Kerberos pour LDAPS, sans aucune configuration : dès qu’un certificat adéquat se trouve dans le magasin de l’ordinateur, le port 636 répond.
RDP : la stratégie qui ne faisait rien
Il existe un paramètre de stratégie de groupe conçu exactement pour cela : Modèle de certificat d’authentification serveur. RDP est censé inscrire un certificat à partir de ce modèle et l’utiliser. Il était défini, vérifié dans le registre, SessionEnv redémarré, TermService redémarré sur les serveurs sans session, et RDP continuait de présenter son certificat auto-signé. Pas un seul événement dans aucun journal pour expliquer pourquoi.
Plutôt que de déboguer un mécanisme invisible, nous avons pris la voie déterministe : un petit script de démarrage dans la même GPO. À chaque démarrage, il choisit le certificat HomelabComputer valide le plus récent et le lie à RDP (Win32_TSGeneralSetting.SSLCertificateSHA1Hash). Le même script crée ou met à jour l’écouteur WinRM HTTPS avec ce certificat, et la GPO ajoute une règle de pare-feu pour le 5986, LAN uniquement. Les machines redémarrent chaque mois pour les correctifs et le renouvellement commence six semaines à l’avance, donc un certificat renouvelé est toujours lié à temps. Le script journalise dans %ProgramData%\homelab\pki-bind.log, parce que « il a sans doute tourné » n’est pas un statut.
🔌 Certificats iLO via Redfish
Les iLO ne sont pas membres du domaine, donc pas d’inscription automatique. Mais l’iLO 5 sait générer sa propre clé et son CSR, et tout cela se scripte via Redfish :
POST …/SecurityService/HttpsCert/Actions/HpeHttpsCert.GenerateCSRavec le FQDN comme nom commun etIncludeIP: true. Dix à trente secondes plus tard, le CSR apparaît dansCertificateSigningRequest. Il contient une clé de 2048 bits et des SAN pour le nom DNS et l’adresse IP. La clé privée ne quitte jamais l’iLO.- Sur la CA :
certreq -submit -attrib "CertificateTemplate:HomelabWebServer". …/HpeHttpsCert.ImportCertificateavec le PEM. L’iLO se réinitialise tout seul ; l’hôte ne s’en aperçoit pas.
Adieu, Default Issuer (Do not trust). Comme le certificat contient à la fois le nom et l’IP, l’iLO est reconnu dans les deux cas. C’est important quand le DNS est justement ce que vous essayez de réparer.
✅ La confiance n’exclut pas le contrôle (avec OpenSSL)
Les membres du domaine font automatiquement confiance à la nouvelle racine : une Enterprise CA publie son certificat dans AD, et la stratégie de groupe le distribue. Pour la preuve, j’ai exporté la racine vers la machine de sauvegarde Linux et vérifié chaque point de terminaison comme le ferait un client strict, avec vérification du nom :
openssl s_client -connect 192.168.10.30:636 -CAfile muench-homelab-root-ca.crt
\
-verify_hostname HP1-dc01.muench.home.arpa # Verify return code: 0 (ok)| Point de terminaison | HP1 | HP2 | HP3 |
|---|---|---|---|
| LDAPS :636 | ✅ | ✅ | ✅ |
| WinRM HTTPS :5986 | ✅ | ✅ | ✅ |
| Certificat RDP émis par la CA | ✅ | ✅ | ✅ |
| iLO :443 par nom et par IP | ✅ | ✅ | ✅ |
Neuf certificats émis jusqu’ici : trois pour Kerberos, trois pour les ordinateurs, trois pour les iLO. Les deux clients suivront à leur prochain démarrage, et mon certificat de signature de code à ma prochaine ouverture de session.
🧭 La suite
- Imposer la signature LDAP et le channel binding. Avec LDAPS en place, la dernière excuse est tombée. C’est une seule option de sécurité dans la Default Domain Controllers Policy, et cette option écrase discrètement toute valeur de registre posée de manière « astucieuse ».
- Signer les scripts de démarrage avec le nouveau certificat de signature de code, puis passer la stratégie d’exécution de Bypass à AllSigned.
- Windows Admin Center sur le poste d’administration, avec un certificat issu du modèle WebServer au lieu de son certificat auto-signé par défaut.
- Deux niveaux, dès qu’il y aura un hyperviseur : une VM racine hors ligne qui signe une nouvelle CA émettrice, puis retourne se coucher.
🎯 À retenir
Une PKI privée ressemblait à de l’overkill d’entreprise pour un homelab sans presque aucun service web interne. En pratique, le client, c’était le domaine lui-même : DC, RDP, WinRM, iLO. Le meilleur, c’est qu’une fois la mise en place terminée, plus rien ne demande d’attention. Les certificats apparaissent, se renouvellent et se lient tout seuls. Le difficile n’est pas d’installer une CA ; c’est ce que vous ne publiez pas, ceux que vous n’autorisez pas à s’inscrire, et les flags que vous laissez désactivés. La sécurité, comme d’habitude, c’est surtout l’art de dire non. 🔏





