Une alerte Tenable “Primary Group ID Integrity” (plugin 150480) s’affiche sur vos 24 contrôleurs de domaine : des comptes AD ont un primaryGroupID
positionné à 6604. Voici un guide concret, prêt à l’emploi, pour identifier, corriger et prévenir ce type d’écart.
Contexte et impact
Lors d’un scan Tenable sur les contrôleurs de domaine, le plugin AD Starter Scan – Primary Group ID Integrity remonte des objets Active Directory dont l’attribut primaryGroupID
est positionné sur une valeur non standard : 6604. L’équipe souhaite savoir à quel groupe correspond ce RID (Relative Identifier), comment retrouver les comptes affectés et comment corriger l’attribut.
Points essentiels à retenir :
primaryGroupID
est un entier qui représente le RID du groupe primaire d’un objet. Le SID complet du groupe primaire est<DomainSID>-<primaryGroupID>
.- Les valeurs « saines » les plus communes sont : 513 = Domain Users (comptes utilisateurs), 515 = Domain Computers (comptes ordinateurs), 516 = Domain Controllers (contrôleurs de domaine). 512 = Domain Admins n’est pas le défaut d’un utilisateur ; l’utiliser comme groupe primaire est atypique et risqué.
- Une valeur exotique (comme 6604) indique en général un script ou outil qui a modifié l’attribut de manière involontaire.
Ce que signifie vraiment primaryGroupID
Historiquement, le groupe primaire servait surtout à la compatibilité POSIX/SMB. Sur Windows, même si le groupe primaire n’apparaît pas forcément dans l’attribut memberOf
de l’utilisateur, le SID du groupe primaire est quand même ajouté au jeton d’accès de l’utilisateur à l’ouverture de session. Conséquence : si vous fixez le groupe primaire sur un groupe à privilèges (ex. 512 = Domain Admins), vous conférez de fait ces privilèges, même si l’utilisateur n’est pas listé comme membre « classique » du groupe.
Type d’objet | Valeur par défaut du primaryGroupID | Groupe concerné | Remarques |
---|---|---|---|
Utilisateur standard | 513 | Domain Users | Valeur « saine » et attendue. Recommandée pour la quasi-totalité des comptes. |
Ordinateur | 515 | Domain Computers | Pour les comptes machine. À ne pas confondre avec des comptes utilisateurs de service. |
Contrôleur de domaine | 516 | Domain Controllers | À ne jamais écraser ; sinon démarrages et réplications peuvent être affectés. |
Compte à privilèges | 513 recommandé | Domain Users | Évitez 512 = Domain Admins comme groupe primaire : cas très particulier et dangereux. |
Pourquoi Tenable remonte la valeur 6604
Le RID 6604 n’est pas un RID « bien connu » d’Active Directory. Plusieurs origines possibles :
- Un script d’intégration ou de migration (ADMT, provisioning, outil tiers IAM) a utilisé
Set-ADUser -Replace @{primaryGroupID=<valeur>}
avec un paramètre incorrect. - Une procédure de test a défini un groupe primaire personnalisé, puis le groupe cible a été supprimé. Les comptes gardent alors un
primaryGroupID
orphelin. - Erreur humaine via ADUC : bouton « Définir comme groupe principal » sur un groupe inadapté.
Identifier précisément les comptes affectés
Avant toute modification, faites l’inventaire : qui a primaryGroupID = 6604
? De quel type d’objets s’agit-il (utilisateurs, ordinateurs, gMSA, etc.) ? À quel groupe correspond le RID 6604 dans votre domaine (s’il existe) ?
Lister tous les objets avec primaryGroupID = 6604
# Module requis : ActiveDirectory
# Utilisateurs
Get-ADUser -LDAPFilter "(primaryGroupID=6604)" -Properties primaryGroupID,Enabled,memberOf |
Select-Object SamAccountName, Enabled, primaryGroupID, memberOf
# Ordinateurs
Get-ADComputer -LDAPFilter "(primaryGroupID=6604)" -Properties primaryGroupID,Enabled |
Select-Object SamAccountName, Enabled, primaryGroupID
# Tous objets (utile pour voir des types inattendus)
Get-ADObject -LDAPFilter "(primaryGroupID=6604)" -Properties primaryGroupID,objectClass,objectSid |
Select-Object Name, objectClass, primaryGroupID, objectSid
Trouver à quel groupe correspond le RID 6604
Le groupe primaire est le groupe dont le SID se termine par le RID stocké dans primaryGroupID
. Construisez le SID complet de domaine et cherchez un groupe dont le SID se termine par -6604
:
$domainSid = (Get-ADDomain).DomainSID.Value
$rid = 6604
$targetSid = "$domainSid-$rid"
Get-ADGroup -Filter * | Where-Object { $_.SID.Value -eq $targetSid } |
Select-Object Name, DistinguishedName, SID
Cas 1 : un groupe est trouvé — vous avez identifié la cible « réelle ».
Cas 2 : aucun groupe n’existe avec ce RID — vos comptes portent un groupe primaire orphelin ; il faut rétablir une valeur valide (513, 515, 516 selon le cas).
Exporter une preuve et préparer le rollback
Avant modification, exportez les objets concernés, leurs attributs clés et la date de dernière modification :
Get-ADObject -LDAPFilter "(primaryGroupID=6604)" -Properties * |
Select-Object ObjectClass, SamAccountName, DistinguishedName, primaryGroupID, SID, whenChanged |
Export-Csv .\PGID-6604-inventory.csv -NoTypeInformation -Encoding UTF8
Corriger de manière sûre et reproductible
Bonnes pratiques avant d’écrire
- Fenêtre de changement approuvée et sauvegarde/export des objets ciblés.
- Compte opérateur avec droits suffisants et session PowerShell en Run as domain admin.
- Test sur un échantillon représentatif (1–3 comptes) avant exécution en masse.
Rétablir le groupe primaire des utilisateurs sur 513 = Domain Users
En plus d’ajuster primaryGroupID
, vérifiez que le compte est bien membre de Domain Users (utile pour certains workflows et outils). Le script ci-dessous est idempotent :
$targets = Get-ADUser -LDAPFilter "(primaryGroupID=6604)" -Properties primaryGroupID
foreach ($u in $targets) {
try {
Add-ADGroupMember -Identity "Domain Users" -Members $u -ErrorAction SilentlyContinue
Set-ADUser -Identity $u -Replace @{primaryGroupID = 513}
Write-Host "OK - $($u.SamAccountName) → primaryGroupID=513"
} catch {
Write-Warning "NOK - $($u.SamAccountName): $($_.Exception.Message)"
}
}
Rétablir le groupe primaire des ordinateurs sur 515 = Domain Computers
$targets = Get-ADComputer -LDAPFilter "(primaryGroupID=6604)" -Properties primaryGroupID
foreach ($c in $targets) {
try {
Add-ADGroupMember -Identity "Domain Computers" -Members $c -ErrorAction SilentlyContinue
Set-ADComputer -Identity $c -Replace @{primaryGroupID = 515}
Write-Host "OK - $($c.SamAccountName) → primaryGroupID=515"
} catch {
Write-Warning "NOK - $($c.SamAccountName): $($_.Exception.Message)"
}
}
Que faire pour des comptes à privilèges ?
- Recommandation : conserver 513 = Domain Users comme groupe primaire, même pour des administrateurs. L’appartenance au groupe Domain Admins doit rester gérée via l’attribut
memberOf
, pas via le groupe primaire. - À éviter : définir 512 = Domain Admins comme groupe primaire d’un compte non critique ; c’est atypique, source de confusion et potentiellement dangereux.
Contrôleurs de domaine
Pour les objets computer qui sont des DC, la valeur doit être 516 (Domain Controllers). Ne touchez pas aux DC si l’alerte concerne uniquement des comptes utilisateurs ; limitez votre périmètre aux objets inventoriés.
Validation post-correction
- Réplication AD : forcer une réplication inter-sites si nécessaire (
repadmin /syncall /AdeP
depuis un DC de référence). - Jeton de l’utilisateur : ouvrez une session avec un compte corrigé et exécutez
whoami /all
pour vérifier les SIDs de groupes inclus dans le jeton. - Relancer l’analyse Tenable : ciblez le domaine ou lancez un Rescan complet. Le plugin 150480 doit disparaître pour les objets corrigés.
- Journalisation : contrôlez vos logs (événements 4738/5136) pour tracer les changements d’attribut.
Automatiser la prévention
Mettez en place une surveillance récurrente (tâche planifiée) qui alerte dès qu’un primaryGroupID
sort des bornes attendues par type d’objet :
# Paramétrage des valeurs "autorisées"
$allowed = @{
user = @(513) # Domain Users
computer = @(515, 516) # Domain Computers, Domain Controllers (rare côté computer)
msDSGroupManagedServiceAccount = @(513) # gMSA assimilé à "user" côté logique
}
$bad = @()
# Collecte globale
$objs = Get-ADObject -LDAPFilter "(&(primaryGroupID=*)(!(isDeleted=*)))" -Properties objectClass, primaryGroupID, SamAccountName
foreach ($o in $objs) {
$cls = $o.objectClass.ToLower()
$pg = [int]$o.primaryGroupID
if ($allowed.ContainsKey($cls)) {
if ($allowed[$cls] -notcontains $pg) { $bad += $o }
} else {
# Pour les classes non prévues, on considère "suspect"
$bad += $o
}
}
if ($bad.Count -gt 0) {
$bad | Select-Object objectClass, SamAccountName, DistinguishedName, primaryGroupID |
Export-Csv ".\PGID-outliers-$(Get-Date -Format yyyyMMdd-HHmm).csv" -NoTypeInformation
Write-Warning ("{0} objet(s) avec primaryGroupID inattendu. Rapport généré." -f $bad.Count)
} else {
Write-Host "Aucun écart détecté."
}
Ajoutez ensuite une étape d’envoi (mail/Teams/Webhook) si le CSV contient des enregistrements.
Diagnostic avancé et causes racines
Pour comprendre l’origine de la valeur 6604 :
- Audit Directory Service Changes : activez l’audit avancé si ce n’est pas déjà fait.
- Recherche d’événements :
# Événements 4738 (user account changed) et 5136 (modification d'objet AD) Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4738} | Where-Object { $_.Message -like "*Primary Group ID*" } | Select-Object TimeCreated, Id, Message | Out-GridView Get-WinEvent -FilterHashtable @{LogName="Directory Service"; Id=5136} | Where-Object { $_.Message -like "*primaryGroupID*" } | Select-Object TimeCreated, Id, Message | Out-GridView
- CIAM/IAM : vérifiez les connecteurs (ServiceNow, SailPoint, scripts de provisioning) qui pourraient écrire l’attribut directement.
- Migration inter-domaines : certains outils copient des attributs tels quels ; après bascule, le RID peut ne plus référencer un groupe existant.
Tableau récapitulatif des actions
Objectif | Actions recommandées | Commentaires pratiques |
---|---|---|
Identifier les comptes affectés | Rechercher les objets où primaryGroupID = 6604 . | Ex. PowerShell : Get-ADUser -Filter 'PrimaryGroupID -eq 6604' -Properties PrimaryGroupID |
Comprendre la valeur sûre | Utilisateurs : 513 = Domain Users. Ordinateurs : 515 = Domain Computers. DC : 516 = Domain Controllers. | Évitez 512 sauf cas très spécifiques et entièrement maîtrisés. |
Rétablir l’ID de groupe primaire | Set-ADUser -Identity <UserDN> -Replace @{primaryGroupID=513} | Exécuter sous un compte ayant des droits d’administration du domaine. |
Valider la correction | Forcer la réplication AD, tester whoami /all , relancer un scan Tenable. | Attendez la convergence avant de conclure. |
Documentation et prévention | Documenter la cause racine et déployer une alerte automatique sur les outliers de primaryGroupID . | Réduit fortement le risque de régression. |
Exemples « copier-coller » prêts pour l’exploitation
Inventaire rapide (utilisateurs) + export
Get-ADUser -LDAPFilter "(primaryGroupID=6604)" -Properties * |
Select-Object SamAccountName, Name, Enabled, primaryGroupID, whenChanged, lastLogonDate, memberOf |
Export-Csv .\PGID-6604-users.csv -NoTypeInformation -Encoding UTF8
Correction en lot avec sauvegarde des valeurs initiales
$snapshot = Get-ADUser -LDAPFilter "(primaryGroupID=6604)" -Properties primaryGroupID |
Select-Object SamAccountName, DistinguishedName, primaryGroupID
$snapshot | Export-Csv .\PGID-6604-users-backup.csv -NoTypeInformation
foreach ($u in $snapshot) {
try {
Add-ADGroupMember -Identity "Domain Users" -Members $u.DistinguishedName -ErrorAction SilentlyContinue
Set-ADUser -Identity $u.DistinguishedName -Replace @{primaryGroupID=513}
Write-Host "OK - $($u.SamAccountName) réparé"
} catch {
Write-Warning "NOK - $($u.SamAccountName): $($_.Exception.Message)"
}
}
Vérification post-changement
Get-ADUser -LDAPFilter "(primaryGroupID=513)" -Properties primaryGroupID |
Where-Object {$_.whenChanged -gt (Get-Date).AddHours(-4)} |
Select-Object SamAccountName, primaryGroupID, whenChanged
Questions fréquentes
Changer primaryGroupID
modifie-t-il l’appartenance aux groupes ?
L’attribut ne met pas à jour l’attribut memberOf
des groupes, mais le SID du groupe primaire est injecté dans le jeton. Fonctionnellement, il est donc traité comme une appartenance pour le contrôle d’accès. D’où la prudence : ne définissez pas un groupe primaire à privilèges par inadvertance.
Pourquoi ne pas mettre 512 pour un administrateur ?
Même pour des admins, il est plus simple, sûr et auditable de conserver 513 comme primaire et de gérer les privilèges via memberOf
(Domain Admins). La valeur 512 comme primaire rend les analyses et audits plus confus et n’apporte aucun bénéfice concret.
Que faire si le groupe au RID 6604 n’existe plus ?
Rétablissez le primaire sur une valeur valide (513/515/516 selon l’objet). Vous ne pouvez pas recréer un groupe avec un RID précis : les RID sont attribués par le RID Master.
Est-ce que l’alerte ciblant les DC signifie que les DC sont en cause ?
Pas forcément. Tenable interroge l’annuaire en s’appuyant sur les DC ; l’alerte met en évidence des objets du domaine (utilisateurs/ordinateurs) avec une valeur non standard, pas nécessairement les comptes machine des DC.
Runbook express
- Inventorier les objets avec
primaryGroupID=6604
et exporter la liste. - Identifier le groupe cible via le SID
<DomainSID>-6604
(s’il existe). - Corriger : utilisateurs → 513, ordinateurs → 515, DC → 516. Ne pas utiliser 512 sauf justificatif.
- Forcer la réplication et retester (whoami /all, rescan Tenable).
- Documenter la cause racine et déployer la surveillance automatisée.
Résultat attendu
- Après remise sur 513 (ou 515/516 selon l’objet) et rescan, le plugin 150480 n’apparaît plus.
- La cause racine est consignée (script, outil tiers, migration) et une alerte empêche la réapparition de valeurs exotiques.
Exemples supplémentaires utiles
Identifier tous les groupes « bien connus » pour votre domaine
Utile pour créer une matrice de valeurs autorisées adaptée à votre environnement :
$knownRids = 512..521 + 513 + 515 + 516
$domainSid = (Get-ADDomain).DomainSID.Value
$knownGroups = foreach ($rid in ($knownRids | Select-Object -Unique)) {
$sid = "$domainSid-$rid"
Get-ADGroup -Filter * | Where-Object { $_.SID.Value -eq $sid } |
Select-Object Name, SID
}
$knownGroups | Format-Table -Auto
Repérer des comptes dominants par erreur
Détecte les comptes dont le groupe primaire serait à privilèges (ex. 512) :
Get-ADUser -LDAPFilter "(primaryGroupID=512)" -Properties SamAccountName,primaryGroupID |
Select-Object SamAccountName, primaryGroupID
Restaurer une valeur incohérente au cas par cas
Réglage manuel pour un compte utilisateur précis :
Set-ADUser -Identity "CN=Jean Dupont,OU=Users,DC=exemple,DC=local" `
-Replace @{primaryGroupID=513}
Checklist de qualité avant clôture
- Inventaire initial archivé et daté.
- Scripts, journaux d’exécution et éventuels messages d’erreur conservés.
- Preuve de réplication OK (
repadmin
sans erreur). - Preuve fonctionnelle (
whoami /all
sur un compte corrigé). - Rapport Tenable après rescan avec statut « remédié ».
- Surveillance planifiée en place (tâche planifiée, alerting).
Conclusion
Un primaryGroupID
non standard (ex. 6604) signale une anomalie de configuration. La correction est simple : remettre la valeur par défaut selon le type d’objet, forcer la réplication et valider par scan. Le volet essentiel est la prévention : outillez la détection d’outliers et clarifiez vos procédures de provisioning pour éviter qu’un script ne réécrive l’attribut par erreur.
Annexe – valeurs typiques des RID utiles (rappel, non exhaustif)
RID | Groupe | Usage |
---|---|---|
512 | Domain Admins | Groupe à privilèges élevés (éviter comme groupe primaire). |
513 | Domain Users | Défaut des utilisateurs. |
515 | Domain Computers | Défaut des comptes machine. |
516 | Domain Controllers | Défaut des DC. |
517 | Cert Publishers | Comptes liés à l’AD CS. |
520 | Group Policy Creator Owners | Gestion avancée des GPO (utilisation rare). |
521 | Denied RODC Password Replication Group | RODC – liste de déni de réplication de mots de passe. |
En appliquant ces étapes — inventaire, correction ciblée, validation et prévention — vous éliminez l’alerte Tenable 150480 de manière durable tout en renforçant la sécurité et la maintenabilité de votre annuaire.