Durcissement Active Directory (ad-hardening)¶
Rôle¶
Package de scripts PowerShell de durcissement du domaine Active Directory
infra.indio (INFRA.INDIO), basé sur le modèle de tiering Microsoft
(Tier0/Tier1/Tier2) : OU dédiées, groupes d'administration isolés, GPO de
sécurité, comptes de service applicatifs, et depuis le 2026-07-16 un volet
PKI/RDP qui s'appuie sur le cluster Vault interne. Le dépôt est livré comme un
package à revoir puis appliquer manuellement (RSAT AD-PowerShell + GPMC
requis, compte Domain Admins/Enterprise Admins) — rien n'est exécuté
automatiquement contre les contrôleurs de domaine par un agent.
Architecture¶
Contrairement aux autres dépôts identité, ad-hardening ne contient ni
Terraform ni Ansible : c'est un ensemble de scripts PowerShell organisés
comme suit.
config/TieringConfig.psd1 configuration centrale (DN, noms, tiers, comptes de service, bloc VaultPKI)
common/Common-Functions.ps1 logging, helpers idempotents, écriture GptTmpl/audit.csv, fonctions Vault/PKI
scripts/00-Deploy-All.ps1 orchestrateur complet
scripts/01-04 OU, groupes de tiering, délégation, GPO deny-logon croisée
scripts/05-06 renommage Administrator, rotation krbtgt (FORT IMPACT)
scripts/10-15 GPO de durcissement (password/PSO, Kerberos, NTLM/SMB, audit avancé+WEF, LAPS, AppLocker)
scripts/16-Link-GPOsToOUs.ps1 liaison effective des GPO aux OU
scripts/20/22/23 comptes de service (bind LDAP Horizon/NSX/vCenter/GitLab, GPO deny-logon dédiée, jointure vSAN File Service)
scripts/21 compte admin nominatif paramétrable (1 par personne et par tier)
scripts/30-33 PKI Vault : publication des CA + certificat KDC, durcissement transport RDP, auto-enrollment certificat RDP, exigence smart-card T0 (FORT IMPACT, gate)
payload/trust/ copies statiques des CA publiques (bootstrap Vault + Indio Root/Intermediate)
payload/*.ps1 scripts déployés par GPO (RDP) ou à exécuter manuellement (smart-card)
external-package/Deploy-ADOrganization.ps1 script tiers : structure d'OU/groupes type PME, adaptée à l'organisation Indio (Direction/Infrastructure/SOC/Support/RnD)
gpo-backups/ destination des exports Backup-GPO
ACCOUNTS.md inventaire exhaustif des comptes créés + procédures de raccordement produit
Modèle de tiering (OU=Tiering,DC=infra,DC=indio) : Tier0 (Admins, Groups,
PAW, ServiceAccounts), Tier1 (Servers, Admins, Groups, PAW, ServiceAccounts,
File-Services), Tier2 (Workstations, Users, Groups, PAW, ServiceAccounts),
plus OU=GPO-Staging pour tester avant liaison large. OU=Domain Controllers
est conservée telle quelle (Tier 0 intégré, non déplacé).
Un compte/groupe d'un tier n'administre que son propre tier (délégation
d'OU) et ne peut pas ouvrir de session sur un autre tier (GPO deny-logon
croisées). Les comptes T0 sont membres de Protected Users.
Le fichier de configuration note explicitement que la structure d'OU réelle
et vivante du domaine, depuis son rebuild du 2026-07-15, ne correspond plus
entièrement à l'arborescence OU=Tiering de ce dépôt (le domaine utilise une
autre organisation, OU=Indio/OU=Admin, déployée par ailleurs) — les GPO
RDP/PKI (30-33) sont donc liées via une liste distincte d'OU cibles réelles
(RDPLinkTargets), pas via Get-TierOUPath.
Structure d'OU réellement vivante sur le domaine aujourd'hui (constatée
par audit LDAP le 2026-07-16), à ne pas confondre avec l'arborescence
OU=Tiering du dépôt décrite plus haut :
flowchart TD
ROOT["DC=infra,DC=indio"] --> INDIO["OU=Indio (racine réelle du domaine)"]
INDIO --> ADMIN["OU=Admin"]
INDIO --> UTIL["OU=Utilisateurs"]
INDIO --> GRP["OU=Groupes"]
INDIO --> ORD["OU=Ordinateurs (Fixes/Portables)"]
INDIO --> CS["OU=Comptes-Service"]
ADMIN --> T0["OU=Tier0 (Accounts/Groups + PAW)"]
ADMIN --> T1["OU=Tier1 (Accounts/Groups) + Servers-T1"]
ADMIN --> T2["OU=Tier2 (Accounts/Groups) + Workstations-T2"]
UTIL --> DIR["Direction"]
UTIL --> INFRA["Infrastructure"]
UTIL --> SOC["SOC"]
UTIL --> SUP["Support"]
UTIL --> RND["RnD"]
T0 -. GPO deny-logon croisée .-> T1
T1 -. GPO deny-logon croisée .-> T2
T2 -. GPO deny-logon croisée .-> T0
Flux d'émission d'un certificat RDP/KDC via Vault (scripts 30/32)¶
Les deux enrôlements (certificat KDC sur un DC, certificat serveur RDP)
suivent exactement le même schéma sign-only, constaté directement dans
scripts/30-Deploy-VaultPKITrust.ps1 et payload/Invoke-VaultRDPCertEnrollment.ps1 :
sequenceDiagram
participant W as certreq (CSP local, poste/DC)
participant AD as AD (ticket Kerberos machine)
participant V as Vault (auth/kerberos + pki_int)
W->>W: certreq -new (CSR local, clé privée non exportable)
W->>AD: ticket Kerberos (identité SYSTEM du compte machine)
W->>V: POST /v1/auth/kerberos/login (-UseDefaultCredentials, SPNEGO)
V-->>W: client_token (policies mappées via identity group AD)
W->>V: POST /v1/pki_int/sign/ROLE {csr, common_name, ttl}
Note over V: role = infra-indio (RDP) ou infra-indio-kdc (KDC)<br/>jamais pki_int/issue/* (principe sign-only)
V-->>W: certificat signé (PEM)
W->>W: certreq -accept (import, associe la clé privée locale en attente)
W->>W: Win32_TSGeneralSetting.SSLCertificateSHA1Hash = thumbprint ; .Put()
Note over W: bind listener RDP-Tcp (script 32 uniquement — le cert KDC<br/>n'a besoin que d'être présent dans LocalMachine\My)
Provisioning Terraform¶
Non applicable — ce dépôt ne provisionne aucune VM ; il s'exécute contre des contrôleurs de domaine déjà existants (gérés ailleurs dans l'IaC).
Configuration Ansible¶
Non applicable — durcissement 100% PowerShell/GPO côté Windows, sans Ansible.
Procédure de déploiement¶
Ordre recommandé (détaillé dans README.md) :
- Valider chaque GPO sur
OU=GPO-Stagingavant toute liaison large (idéalement sur un AD de lab/snapshot). 01→ OU ;02→ groupes de tiering (ajout automatique des groupes T0 àProtected Users) ;03→ délégation par OU ;04→ GPO deny-logon croisées (créées, non liées).10à15→ GPO de durcissement (password/PSO, Kerberos, NTLM/SMB, audit avancé + WEF, LAPS, AppLocker en mode audit) — créées, non liées.- Revue manuelle des GPO créées, puis
16→ liaison effective aux OU (l'impact réel commence ici). 20→ comptes de service bind LDAP (Horizon/NSX/vCenter/GitLab) ;23→ compte de jointure de domaine du vSAN File Service ;22→ GPO deny-logon pour ces comptes de service, puis re-liaison via16.21→ comptes admin nominatifs, à invoquer une fois par personne et par tier (aucune création en masse).- Étapes séparées à fort impact, après confirmation explicite :
05(renommage/désactivation du compte Administrator intégré) puis06(rotation krbtgt en 2 phases espacées d'au moins 24h). - Volet PKI/RDP (ajouté le 2026-07-16, prérequis Vault réalisés hors de ce
repo) :
30publie les 3 CA (bootstrap Vault + Indio Root + Indio Intermediate) dans les conteneurs AD distribués (Trusted Root, AIA, NTAuth) et enrôle le certificat KDC sur le DC courant (à rejouer sur chaque DC) ;31GPO de durcissement du transport RDP (NLA, TLS, chiffrement fort) ;32GPO d'auto-enrollment/renouvellement du certificat RDP via Vault (Kerberos/SPNEGO, policy sign-only) ;16relie 31/32 aux OU réelles ;33(gate, fort impact) exige la carte à puce pourT0-Admins— jamais exécuté automatiquement. - Configuration côté produit (Horizon/NSX/vCenter/GitLab/vSAN) des comptes
de service créés : manuelle, procédures détaillées dans
ACCOUNTS.md.
00-Deploy-All.ps1 enchaîne automatiquement 1-4, 10-16, 20, 22-23 et 30-31-32
(-SkipHighImpact vrai par défaut : n'exécute jamais 05 ni la rotation
krbtgt). Les comptes admin nominatifs (21) et l'exigence smart-card (33)
restent volontairement hors de l'orchestrateur. L'ensemble est idempotent
(vérifications d'existence systématiques dans Common-Functions.ps1) ; un
compte déjà existant ne voit jamais son mot de passe réinitialisé par une
ré-exécution.
Contrôle de santé (2026-07-17)¶
Un contrôle de santé complet du domaine (dcdiag /q + repadmin
/replsummary + statut des services core NTDS/DNS/Netlogon/KDC/
W32Time) a été réalisé sur les deux contrôleurs de domaine actuels —
INDIDEN008 (primaire, tous les rôles FSMO) et INDIDEN009 (promu 2ᵉ DC
le 2026-07-16, Global Catalog). Cœur AD sain : 0/5 échec de réplication
dans les deux sens, tous les services core RUNNING, SYSVOL identique sur
les deux DC (9 dossiers GPO, mêmes GUID).
Trois points relevés dans les avertissements dcdiag, dont deux résolus :
| Point | État | Détail |
|---|---|---|
Relation d'approbation cassée sur INDSERV015 |
Connu, non bloquant | Machine jamais rejointe depuis le rebuild du domaine du 2026-07-15 (nouveau SID) — comportement AD normal (rejet d'un secret de canal obsolète), pas un défaut du domaine. Fix hors périmètre de ce dépôt : rejoindre le domaine ou Reset-ComputerMachinePassword sur cette VM si elle redevient pertinente. |
| Blip DFSR à la promotion d'INDIDEN009 | Auto-résolu | Événement 1202 transitoire au moment du Install-ADDSDomainController, normal dans les premières minutes avant stabilisation Netlogon/DNS SRV. Aucune action nécessaire. |
| URL OCSP Vault erronée (event Schannel 36928 en boucle) | Corrigé | pki_int/config/urls/pki/config/urls pointaient vers l'IP brute du nœud Vault backend plutôt que vault.infra.indio — cosmétique (LDAPS/KDC/RDP restaient fonctionnels, Windows soft-fail sur OCSP injoignable) mais polluait le journal System en continu sur les deux DC. |
Fix OCSP appliqué (vault write pki_int/config/urls
issuing_certificates=... crl_distribution_points=...
ocsp_servers=https://vault.infra.indio:8200/v1/pki_int/ocsp, config
équivalente sur pki). L'URL étant embarquée dans chaque certificat au
moment de l'émission (pas relue dynamiquement), les certificats KDC, RDP et
LDAPS des deux DC ont été réenrôlés de force après le fix plutôt que
d'attendre le renouvellement naturel. Vérifié par extension X.509 réelle
(AIA/CDP) sur les nouveaux certificats et par handshake TLS réel (openssl
s_client -connect <ip>:636) pour confirmer le certificat LDAPS effectivement
servi — une vérification par simple présence dans le store aurait été
ambiguë (plusieurs certificats ServerAuth de même Subject cohabitent sur
un DC multi-rôles PKI).
NTAuth résolu sur les deux DC : la cause profonde était la confusion
entre deux magasins distincts fusionnés à l'affichage — l'objet AD
NTAuthCertificates (source « Enterprise », peuplé correctement depuis le
07-16) et le registre local
HKLM\SOFTWARE\Microsoft\SystemCertificates\NTAuth\Certificates (source que
PKINIT consulte réellement côté DC), que la synchronisation automatique
attendue ne remplissait jamais. Fix : certutil -f -addstore NTAuth
<fichier> (sans -enterprise) écrit directement la seconde source ;
Publish-CertToNTAuth dans Common-Functions.ps1 corrigée en conséquence
(commit 47eb21a) pour que tout futur DC traité par le script 30 obtienne
NTAuth peuplé localement dès le premier passage. Plus aucun gap bloquant
connu côté infrastructure PKI pour un futur script 33 (smart-card) — il
reste néanmoins gaté par design.
Points d'attention¶
Étapes irréversibles à fort impact
Quatre opérations nécessitent une confirmation humaine explicite et ne sont jamais déclenchées automatiquement :
- 05 renommage/désactivation du compte Administrator intégré.
- 06 rotation krbtgt (2 phases espacées ≥24h, invalide tous les tickets Kerberos en circulation).
- 33 exigence de logon par carte à puce pour
T0-Admins—SmartcardLogonRequiredréinitialise automatiquement le mot de passe du compte (comportement natif AD) : l'accès par mot de passe est perdu tant qu'un certificat carte valide n'a pas été enrôlé au préalable pour chaque compte concerné. - Toute liaison de GPO deny-logon croisée (04/16) sans test préalable sur
OU=GPO-Staging.
- Volet PKI/RDP (30-33) : la CA vit entièrement dans Vault (pas d'AD CS
natif). Principe central — Vault ne fait que signer des CSR générés
localement par
certreq(clé privée jamais transmise sur le réseau), jamais émettre. Plusieurs prérequis doivent être réalisés une fois, hors de ce dépôt, sur l'environnement Vault/AD vivant : DNSvault.infra.indio, certificats TLS des nœuds Vault avec le bon SAN, LDAPS actif sur les DC, compte de service Kerberos dédié + keytab, groupes AD dédiés aux rôles de signature, mountauth/kerberosconfiguré. Chacun de ces prérequis a fait l'objet d'un blocage réel documenté lors de la mise en œuvre du 2026-07-16 — voir le README du dépôt pour le détail. - NTAuth nécessite une double publication (conteneur AD et store
registre local de chaque DC individuellement) — la propagation
automatique ne s'est jamais déclenchée en pratique dans cet environnement.
Résolu le 2026-07-17 (voir « Contrôle de santé » ci-dessous) :
Publish-CertToNTAuthécrit désormais explicitement les deux sources. - Mots de passe générés (comptes de service, comptes admin nominatifs,
compte leurre Administrator) : jamais commités ni journalisés, écrits une
seule fois dans un fichier local hors dépôt (chemin configurable via
ServiceAccountSecretsPath), à basculer immédiatement dans le coffre-fort de secrets Indio puis à supprimer. - Comptes de service bind LDAP (
svc-horizon-bind,svc-nsx-bind,svc-vcenter-bind,svc-gitlab-bind) : lecture seule stricte surOU=Tieringet descendants, aucune appartenance à un groupe privilégié, logon interactif/RDP refusé par GPO dédiée. Détail complet des comptes et procédures de raccordement produit dansACCOUNTS.md. - Windows Event Forwarding (13) : ne configure que la GPO côté clients (pointeur vers le collecteur) ; le serveur WEC et le pont vers ELK/syslog-ng restent à construire séparément.
- AppLocker (15) est déployé en mode audit uniquement — aucune application n'est bloquée tant que le mode Enforce n'est pas activé manuellement après analyse des logs.
external-package/Deploy-ADOrganization.ps1est un script distinct (structure d'OU/groupes générique type PME, modèle AGDLP), adapté à l'organisation réelle Indio mais non intégré à l'orchestrateur00-Deploy-All.ps1ni au modèle de tiering du reste du dépôt.