Documente les groupes de sécurité et le résultat de l'audit machine

This commit is contained in:
slaporte committed 2026-10-30 16:53:24 +01:00
1 parent b48c4c5412
commit 5f1d3438a2
1 file changed
+117 -89
+117 -89
View File
@@ -1,99 +1,127 @@
**form-gpresult-computer** # Audit GPResult — Ordinateur
Paquet WAPT d'audit des stratégies de groupe appliquées à l'ordinateur. Il collecte un export XML de GPResult et enregistre un résultat structuré dans **`audit-gpresult.computer-gpo`**.
Le nom `form-gpresult-computer` est proposé pour identifier ce paquet dans le dépôt, en complément de `form-gpresult-user`. Si le paquet machine existe déjà sous un autre nom, conserver son identité actuelle. Paquet WAPT d'audit des GPO et des groupes de sécurité de l'ordinateur. Le résultat structuré est enregistré dans **`audit-gpresult.computer-gpo`**.
**Description pour le dépôt**
**Libellé proposé :** Audit GPO — Ordinateur ## Fonctionnement
Ligne à reporter dans le champ `description` du fichier `WAPT/control` existant :
1. `install()` ne réalise aucune action.
2. `audit()` supprime un éventuel rapport temporaire précédent, puis lance GPResult avec un délai maximal de 120 secondes :
```text
gpresult.exe /SCOPE COMPUTER /X "<rapport.xml>" /F
``` ```
description: Audit des GPO machine : domaine, site, listes des GPO appliquees et non appliquees et compteurs dans audit-gpresult.computer-gpo.
  3. Le script analyse la section `ComputerResults`, collecte l'identité du poste, classe les GPO et les groupes de sécurité.
``` 4. Il transmet un dictionnaire à `WAPT.write_audit_data_if_changed`, avec `keep_days=365` et `max_count=1`.
Cette ligne est également fournie dans `WAPT/description.txt`. Ce fichier n'est pas un contrôle WAPT complet : conserver les autres métadonnées du paquet existant. 5. La suppression du rapport est tentée dans `finally`, après succès comme après erreur.
**Fonctionnement**
1. L'installation appelle `install()`, volontairement vide. Le chemin de GPResult est construit avec `makepath(system32(), "gpresult.exe")`. L'audit consulte les données RSoP disponibles, sans lancer de `gpupdate` ni modifier les stratégies. Aucune session utilisateur active n'est nécessaire. Les GPO et groupes du contexte utilisateur sont collectés par le paquet utilisateur séparé.
2. L'audit supprime, s'il existe, le rapport temporaire précédent.
3. Il lance GPResult depuis le chemin construit avec `makepath(system32(), "gpresult.exe")`, avec les options `/SCOPE COMPUTER /X "<rapport.xml>" /F` et un délai maximal de 120 secondes. ## Prérequis
4. Il recherche la section XML `ComputerResults`, extrait les informations et classe les GPO.
5. Il enregistre directement un dictionnaire avec `WAPT.write_audit_data_if_changed`. - Poste Windows disposant de GPResult et de données RSoP machine accessibles.
6. Il tente de supprimer le rapport temporaire dans un bloc `finally`.
Le paquet consulte les données RSoP disponibles. Il ne lance pas de `gpupdate` et ne modifie pas les stratégies de groupe. Il n'a pas besoin d'une session utilisateur active et ne collecte pas les GPO utilisateur.
**Prérequis**
- Poste Windows disposant de GPResult au chemin construit par les fonctions WAPT utilisées.
- Agent WAPT fournissant `setuphelpers` et `WAPT.write_audit_data_if_changed`. - Agent WAPT fournissant `setuphelpers` et `WAPT.write_audit_data_if_changed`.
- Données RSoP machine disponibles et droits suffisants dans le contexte de l'agent pour les consulter. - Droits suffisants pour consulter le RSoP machine et écrire dans le répertoire temporaire du contexte d'exécution.
- Accès en lecture et écriture au répertoire temporaire du contexte d'exécution.
**Données produites** ## Données produites
**Catégorie :** `audit-gpresult` — **Clé :** `computer-gpo`.
Exemple illustratif : Catégorie : `audit-gpresult` ; clé : `computer-gpo`.
```
Exemple illustratif d'un résultat de succès :
```json
{ {
   "status": "OK", "status": "OK",
   "computer": { "computer": {
     "name": "POSTE01", "name": "POSTE01",
     "domain": "exemple.lan", "account": "EXEMPLE\\POSTE01$",
     "site": "Default-First-Site-Name" "account_domain": "EXEMPLE",
   }, "domain": "exemple.lan",
   "summary": { "site": "Default-First-Site-Name"
     "applied_gpo_count": 2, },
     "denied_gpo_count": 1, "summary": {
     "total_gpo_count": 3 "applied_gpo_count": 2,
   }, "denied_gpo_count": 1,
   "applied_gpos": [ "total_gpo_count": 3,
     "Local Group Policy", "domain_group_count": 1,
     "Default Domain Policy" "local_group_count": 1,
   ], "system_group_count": 1,
   "denied_gpos": [ "other_group_count": 0
     "GPO non appliquee" },
   ] "applied_gpos": ["Local Group Policy", "Default Domain Policy"],
 } "denied_gpos": ["GPO non appliquee"],
  "domain_groups": ["EXEMPLE\\Domain Computers"],
"security_groups": {
"domain": ["EXEMPLE\\Domain Computers"],
"local": ["BUILTIN\\Users"],
"system": ["NT AUTHORITY\\Authenticated Users"],
"other": []
}
}
``` ```
| | | | Champ | Signification |
| - | - | | --- | --- |
| **Champ** | **Signification** | | `status` | État de la collecte ; ce n'est pas un verdict de conformité. |
| `status` | État de la collecte, pas un verdict de conformité. |
| `computer.name` | Nom du poste issu de `COMPUTERNAME`. | | `computer.name` | Nom du poste issu de `COMPUTERNAME`. |
| `computer.domain` | Premier texte `DomainName` trouvé dans le sous-arbre machine, sinon premier texte `Domain`. | | `computer.account` | Premier texte `Name` trouvé dans `ComputerResults`, utilisé comme compte RSoP machine. |
| `computer.account_domain` | Préfixe du compte avant `\`, généralement au format NetBIOS ; vide si aucun préfixe n'est présent. |
| `computer.domain` | Premier texte `DomainName`, sinon premier texte `Domain`, dans le sous-arbre machine. |
| `computer.site` | Premier texte `Site` trouvé dans le sous-arbre machine. | | `computer.site` | Premier texte `Site` trouvé dans le sous-arbre machine. |
| `summary.applied_gpo_count` | Nombre d'entrées retenues comme appliquées. | | `summary.applied_gpo_count` / `summary.denied_gpo_count` | Nombre de GPO retenues dans chaque liste. |
| `summary.denied_gpo_count` | Nombre d'entrées retenues comme non appliquées. | | `summary.total_gpo_count` | Somme des deux compteurs de GPO. |
| `summary.total_gpo_count` | Somme des deux compteurs. | | `summary.domain_group_count` / `summary.local_group_count` / `summary.system_group_count` / `summary.other_group_count` | Nombre de groupes retenus dans chaque catégorie. |
| `applied_gpos` | Noms des GPO classées comme appliquées, dans l'ordre de collecte. | | `applied_gpos` / `denied_gpos` | Noms des GPO, dans l'ordre de collecte. |
| `denied_gpos` | Noms des GPO classées comme non appliquées, dans l'ordre de collecte. | | `domain_groups` | Même liste que `security_groups.domain`, pour faciliter le reporting. |
| `security_groups` | Groupes de sécurité répartis entre `domain`, `local`, `system` et `other`. |
  La recherche de texte est récursive et ignore les namespaces XML. Les informations non trouvées restent des chaînes vides. Le champ `computer.domain` peut contenir un nom DNS lorsqu'il est fourni par l'export ; le repli sur `Domain` ne garantit pas ce format.
Les champs de domaine et de site restent des chaînes vides si aucune valeur n'est trouvée. La recherche de texte est récursive ; elle conserve le comportement du script fourni.
**Règles de classement conservées**
Une GPO est considérée comme appliquée si `Enabled`, `IsValid` et `FilterAllowed` sont vrais et si `AccessDenied` est faux. Toutes les autres entrées retenues sont placées dans `denied_gpos`.
Les valeurs `true`, `1`, `yes` et `oui`, sans distinction de casse, sont interprétées comme vraies. Toute autre valeur, y compris un champ absent, est interprétée comme fausse. Un `AccessDenied` absent est donc considéré comme faux, tandis qu'un `Enabled`, `IsValid` ou `FilterAllowed` absent empêche le classement en GPO appliquée.
**`denied_gpos` signifie ici « GPO non appliquées »**, et pas uniquement « refus de sécurité ». La liste peut notamment inclure des entrées filtrées, désactivées ou invalides.
La recherche des balises `GPO` est récursive. Les doublons sont éliminés selon le triplet `(nom, version annuaire, version SYSVOL)` ; un même nom peut donc apparaître plusieurs fois si les versions diffèrent. Les entrées sans nom sont ignorées. Les compteurs décrivent les entrées retenues par cet algorithme, pas un inventaire de toutes les GPO du domaine.
**Statuts**
| | | ## Classement des GPO
| - | - |
| **Retour d'audit** | **Situation** |
| `OK` | Export, analyse et enregistrement terminés, même si des GPO non appliquées sont présentes. |
| `ERROR` | Échec de la commande, fichier absent, XML invalide, section machine absente ou autre exception capturée. |
  Une GPO est appliquée si `Enabled`, `IsValid` et `FilterAllowed` sont vrais et si `AccessDenied` est faux. Toutes les autres entrées retenues vont dans `denied_gpos` : cette liste couvre les GPO non appliquées, y compris les GPO filtrées, désactivées ou invalides.
En cas d'erreur, la même clé reçoit un objet contenant `status: ERROR` et `message`. Les champs du précédent succès ne sont pas recopiés. Les consommateurs doivent lire `status` avant d'accéder aux listes et compteurs.
Les paramètres d'enregistrement sont `keep_days=365` et `max_count=1`. Aucun statut `WARNING` n'est utilisé dans cette version. Une section `ComputerResults` présente mais sans GPO retenue produit un résultat `OK` avec des compteurs à zéro. Les valeurs `true`, `1`, `yes` et `oui`, sans distinction de casse, sont vraies. Toute autre valeur ou un champ absent est faux. Un indicateur positif absent empêche donc le classement comme GPO appliquée ; un `AccessDenied` absent est considéré comme faux.
**Déploiement**
1. Copier le `setup.py` fourni dans les sources du paquet existant. La recherche des balises `GPO` est récursive. Les entrées sans nom sont ignorées et les doublons sont éliminés selon `(nom, VersionDirectory, VersionSysvol)`. Un nom peut apparaître plusieurs fois si les versions diffèrent. Les listes de GPO ne sont pas triées. Les compteurs décrivent les entrées retenues, sans constituer un inventaire de toutes les GPO du domaine.
2. Reporter la description dans `WAPT/control` et incrémenter la version selon les conventions du dépôt.
3. Reconstruire, signer et téléverser le paquet. ## Classement des groupes de sécurité
4. Déployer la version, puis lancer l'audit depuis WAPT.
5. Consulter `audit-gpresult.computer-gpo`. Les groupes sont extraits des balises `SecurityGroup` du RSoP, sans requête LDAP supplémentaire. Le classement utilise les préfixes des noms, dans cet ordre :
La fréquence des audits dépend de la configuration WAPT existante ; le script ne crée pas de planification.
**Dépannage et limites de cette version** | Catégorie | Règle |
- Consulter le journal de l'audit pour connaître l'erreur GPResult ou XML. | --- | --- |
- Vérifier l'accès à GPResult, les droits de collecte machine et les données RSoP. | `system` | Préfixe `NT AUTHORITY\`. |
- Le rapport temporaire utilise un nom fixe : `wapt-gpresult-computer.xml` dans `tempfile.gettempdir()`. Éviter des exécutions concurrentes de ce même audit dans le même répertoire temporaire. | `local` | Préfixe `BUILTIN\` ou nom du poste suivi de `\`. |
- Le nettoyage est tenté dans tous les cas ; un échec de suppression est ignoré et peut laisser le rapport sur disque. | `domain` | Préfixe du compte RSoP suivi de `\`, si ce préfixe est non vide et différent du nom du poste. |
- La collecte restitue les données disponibles, sans forcer leur actualisation. | `other` | Toutes les autres identités. |
**Contenu**
- `setup.py` : code fourni, enrichi de commentaires et de docstrings, sans modification de logique. Les comparaisons et la déduplication des noms ignorent la casse. Les entrées sans nom sont ignorées ; chaque liste est triée alphabétiquement sans distinction de casse.
- `README.md` : fonctionnement, interprétation, prérequis et exploitation.
- `WAPT/description.txt` : ligne de description pour le contrôle existant Ce classement repose sur les noms présents dans l'export, sans validation du domaine par SID ou LDAP. Les noms localisés ou les groupes d'un autre domaine peuvent rester dans `other`. Les listes reflètent les données RSoP collectées ; elles ne constituent pas un inventaire exhaustif des groupes AD ou locaux.
## Statuts
| Statut enregistré | Retour WAPT | Situation |
| --- | --- | --- |
| `OK` | `OK` | Export, analyse et enregistrement terminés, même avec des GPO non appliquées ou des listes vides. |
| `ERROR` | `ERROR` | Exception capturée : commande en échec, rapport absent, XML invalide, section `ComputerResults` absente, etc. |
En cas d'erreur, la même clé reçoit uniquement `status: ERROR` et `message`. Les listes et compteurs du précédent succès ne sont pas recopiés. Consulter `status` avant d'exploiter le résultat. Aucun statut `WARNING` n'est utilisé.
## Déploiement et dépannage
1. Mettre à jour `setup.py` dans les sources du paquet existant.
2. Adapter si nécessaire la description de `WAPT/control` pour mentionner les groupes de sécurité, en conservant l'identité et les autres métadonnées du paquet ; incrémenter sa version selon les conventions du dépôt.
3. Reconstruire, signer, téléverser et déployer le paquet, puis lancer l'audit depuis WAPT.
4. Consulter `audit-gpresult.computer-gpo` et le journal, qui indique les compteurs de GPO et de groupes de domaine ou l'erreur rencontrée.
La fréquence des audits dépend de la configuration WAPT ; le script ne crée pas de planification. En cas d'échec, vérifier les droits de l'agent, les données RSoP, l'accès à GPResult et au répertoire temporaire.
Le rapport utilise le nom fixe `wapt-gpresult-computer.xml` dans `tempfile.gettempdir()`. Éviter les audits simultanés partageant ce répertoire. Un échec de nettoyage est ignoré et peut laisser le fichier sur disque.
## Contenu du dépôt
- `setup.py` : collecte et analyse des GPO et groupes de sécurité machine.
- `README.md` : fonctionnement, schéma de données et exploitation.
- `WAPT/description.txt` : description fournie pour le contrôle existant ; elle décrit les GPO et ne mentionne pas encore les groupes de sécurité. Ce fichier ne remplace pas un `WAPT/control` complet.