Actualise la documentation de l'audit utilisateur et des groupes

This commit is contained in:
slaporte committed 2026-10-30 16:53:25 +01:00
1 parent be8cd468f6
commit f51c533ff2
1 file changed
+146 -103
+146 -103
View File
@@ -1,103 +1,146 @@
**form-gpresult-user**
Paquet WAPT d'audit des stratégies de groupe de l'utilisateur ayant une session active sur le poste. Il collecte les données GPResult et les expose sous forme structurée dans **`audit-gpresult.user-gpo`**.
**Identification dans le dépôt**
- **Nom du paquet :** `form-gpresult-user`
- **Libellé :** Audit GPO — Utilisateur actif
- **Description proposée pour le champ `description` de `WAPT/control` :**
```
Audit des GPO de l'utilisateur actif : identification du compte, listes des GPO appliquees et non appliquees et compteurs dans audit-gpresult.user-gpo.
 
```
Le fichier `WAPT/description.txt` contient cette ligne à reporter dans le fichier `WAPT/control` existant. Ce n'est pas un fichier de contrôle complet : conserver les autres métadonnées du paquet, notamment la version, les dépendances et les informations de signature.
**Fonctionnement**
1. L'installation appelle `install()`, volontairement vide.
2. L'audit recherche les sessions Windows actives avec les API WTS, via `win32ts`.
3. Il sélectionne l'unique compte actif et lance :
4.
```
gpresult.exe /USER "DOMAINE\utilisateur" /SCOPE USER /X "<fichier temporaire>" /F
 
```
5. Il analyse la section XML `UserResults`, puis classe les GPO et calcule les compteurs.
6. Il transmet directement un dictionnaire à `WAPT.write_audit_data_if_changed`, sans convertir le résultat en chaîne JSON.
7. Le dossier et le rapport XML temporaires sont supprimés à la sortie du bloc de collecte, y compris en cas d'exception.
L'audit s'exécute dans le contexte de l'agent WAPT et cible explicitement les données RSoP de l'utilisateur. Il n'utilise pas `session_setup()`. Il consulte les données disponibles sans lancer de `gpupdate` ni modifier les stratégies du poste.
**Prérequis**
- Poste Windows disposant de `gpresult.exe`, accessible depuis le contexte de l'agent.
- Agent WAPT fournissant `setuphelpers`, `win32ts` et `WAPT.write_audit_data_if_changed`.
- Une session utilisateur active et des données RSoP accessibles pour le compte ciblé.
- Droits suffisants dans le contexte d'exécution de l'agent pour lire ces données et créer un fichier temporaire.
La présence d'un compte actif ne garantit pas la disponibilité de ses données RSoP. Un compte local est détectable, mais ne dispose pas nécessairement de données de stratégies exploitables.
**Résultat d'audit**
**Catégorie :** `audit-gpresult` — **Clé :** `user-gpo`.
Exemple illustratif :
```
{
   "status": "OK",
   "summary": {
     "total_gpo_count": 2,
     "denied_gpo_count": 1,
     "applied_gpo_count": 1
   },
   "computer": {
     "name": "POSTE01"
   },
   "user": {
     "account": "DOMAINE\\utilisateur",
     "name": "utilisateur",
     "domain": "DOMAINE"
   },
   "denied_gpos": ["Local Group Policy"],
   "applied_gpos": ["GPO Utilisateurs"]
 }
 
```
| | |
| - | - |
| **Champ** | **Signification** |
| `status` | État de la collecte, pas un verdict de conformité des GPO. |
| `summary.total_gpo_count` | Nombre d'entrées GPO analysées dans `UserResults`. |
| `summary.applied_gpo_count` | Nombre d'entrées classées comme appliquées. |
| `summary.denied_gpo_count` | Nombre d'entrées classées comme non appliquées. |
| `computer.name` | Nom du poste remonté par `COMPUTERNAME`. |
| `user.account` | Compte complet sélectionné via WTS. |
| `user.name` | Nom d'utilisateur. |
| `user.domain` | Domaine fourni par WTS, généralement NetBIOS ; ce n'est pas nécessairement le nom DNS du domaine AD. |
| `applied_gpos` | Liste triée des noms des GPO appliquées. |
| `denied_gpos` | Liste triée des noms des GPO non appliquées. |
 
**Convention :** `denied_gpos` inclut les GPO non appliquées pour toutes les causes reconnues par les indicateurs XML, notamment le filtrage, la désactivation ou l'invalidité. Cela peut inclure une GPO vide ; cette liste ne signifie donc pas uniquement « refus de sécurité ». Si le nom manque, l'identifiant XML est utilisé lorsqu'il est disponible.
Le classement conserve exactement la logique de la version retenue : un indicateur `Enabled`, `IsValid` ou `FilterAllowed` à faux, ou `AccessDenied` à vrai, classe la GPO comme non appliquée. Sinon, `IsValid` et `FilterAllowed` doivent être vrais pour la classer comme appliquée. Un état indéterminable déclenche une erreur.
**Statuts et cas particuliers**
| | |
| - | - |
| **Statut** | **Situation** |
| `OK` | Export XML et analyse terminés, résultat enregistré. Des GPO non appliquées peuvent être présentes. |
| `WARNING` | Aucun utilisateur avec une session active. |
| `ERROR` | Plusieurs comptes actifs, échec WTS/GPResult, XML absent ou inexploitable, ou état de GPO indéterminable. |
 
Les sessions déconnectées sont ignorées. Plusieurs sessions actives du même compte sont regroupées ; plusieurs comptes actifs distincts provoquent une erreur pour éviter une sélection arbitraire.
En cas de `WARNING` ou d'`ERROR`, le résultat de la même clé est remplacé par un objet de statut et un message. Les listes et compteurs du précédent succès ne sont pas recopiés. Le champ `user` vaut alors `null` ou contient le compte ciblé sous forme de chaîne, selon le cas ; les consommateurs doivent consulter `status` avant de lire les champs du résultat de succès.
Les paramètres d'enregistrement sont `keep_days=365` et `max_count=1`. La collecte ne crée pas une clé distincte par utilisateur : elle représente le résultat du dernier audit du poste, selon le compte actif au moment de l'exécution.
**Mise en place et exploitation**
1. Remplacer le `setup.py` du paquet existant par le fichier fourni.
2. Reporter la description proposée dans `WAPT/control` et incrémenter la version du paquet selon les conventions du dépôt.
3. Reconstruire, signer et téléverser le paquet dans le dépôt WAPT.
4. Déployer la nouvelle version sur un poste avec une session utilisateur active.
5. Lancer l'audit du paquet depuis WAPT et consulter `audit-gpresult.user-gpo`.
La fréquence de réexécution dépend de la configuration d'audit WAPT existante ; ce code n'ajoute aucun mécanisme de planification.
**Dépannage**
Le journal indique le compte ciblé, la commande et la présence du dossier temporaire. Le délai maximal de la commande est de 120 secondes.
- **Aucun utilisateur actif :** ouvrir une session, puis relancer l'audit.
- **Plusieurs utilisateurs actifs :** ne conserver qu'un seul compte actif sur le poste, puis relancer l'audit.
- **Erreur GPResult :** consulter la sortie de la commande dans le journal ; vérifier les droits, les données RSoP et l'accès au dossier temporaire.
- **Erreur XML ou état indéterminable :** récupérer un export XML produit dans les mêmes conditions pour examiner la structure avant de modifier le parseur.
L'appel direct à `gpresult.exe` est conservé dans cette version ; aucun chemin `Sysnative` n'est forcé.
**Contenu**
- `setup.py` : version retenue, enrichie uniquement de commentaires et de docstrings.
- `README.md` : identification, fonctionnement, données et exploitation.
- `WAPT/description.txt` : ligne de description à reporter dans le contrôle existant.
# Audit GPResult — Utilisateur actif
Paquet WAPT d'audit des GPO et des groupes de sécurité de l'utilisateur actif. Le résultat structuré est enregistré dans **`audit-gpresult.user-gpo`**.
## Fonctionnement
1. `install()` ne réalise aucune action.
2. `audit()` appelle `quser.exe` avec un délai maximal de 30 secondes. Le script retient le premier utilisateur dont la ligne contient l'état `Active` ou `Actif`.
3. Si aucun utilisateur n'est détecté, il enregistre `NO_USER` et retourne `OK` à WAPT.
4. Sinon, il supprime un éventuel rapport précédent et lance GPResult avec un délai maximal de 120 secondes :
```text
gpresult.exe /USER "<utilisateur détecté>" /SCOPE USER /X "<rapport.xml>" /F
```
5. Il analyse `UserResults`, extrait l'identité du compte, classe les GPO et les groupes de sécurité.
6. Il transmet un dictionnaire à `WAPT.write_audit_data_if_changed`, avec `keep_days=365` et `max_count=1`.
7. La suppression du rapport temporaire est tentée dans `finally`, après succès comme après erreur.
Le chemin de GPResult est construit avec `makepath(system32(), "gpresult.exe")`. L'audit s'exécute dans le contexte de l'agent WAPT et cible explicitement le RSoP utilisateur. Il n'utilise pas `session_setup()`, ne lance pas de `gpupdate` et ne modifie pas les stratégies.
## Prérequis et sélection de la session
- Poste Windows disposant de `quser.exe`, de GPResult et de données RSoP accessibles pour l'utilisateur ciblé.
- Agent WAPT fournissant `setuphelpers` et `WAPT.write_audit_data_if_changed`.
- Droits suffisants pour consulter les sessions et les données RSoP, ainsi que pour écrire dans le répertoire temporaire.
La détection utilise la sortie texte de `quser`, et non les API WTS ou `win32ts`. Seuls les libellés `Active` et `Actif` sont reconnus. Les sessions déconnectées sont ignorées. Si plusieurs utilisateurs sont actifs, le premier reconnu dans la sortie est sélectionné ; aucun contrôle d'unicité n'est effectué.
Seul le nom d'utilisateur détecté est transmis à `/USER`. Le script lit ensuite le premier texte `Name` de `UserResults` comme identité RSoP, avec repli sur le nom détecté si ce champ est absent. Sur un poste comportant des comptes homonymes, vérifier l'identité effectivement remontée.
Une erreur de `quser`, une sortie vide ou un format non reconnu aboutit aussi à `NO_USER`. Consulter le journal pour distinguer une erreur de détection d'une absence réelle de session. Une session active, locale ou de domaine, ne garantit pas que ses données RSoP soient disponibles.
## Données produites
Catégorie : `audit-gpresult` ; clé : `user-gpo`.
Exemple illustratif d'un résultat de succès :
```json
{
"status": "OK",
"user": {
"account": "EXEMPLE\\utilisateur",
"username": "utilisateur",
"account_domain": "EXEMPLE",
"account_type": "domain"
},
"summary": {
"applied_gpo_count": 1,
"denied_gpo_count": 1,
"total_gpo_count": 2,
"domain_group_count": 1,
"local_group_count": 1,
"system_group_count": 1,
"other_group_count": 0
},
"applied_gpos": ["GPO Utilisateurs"],
"denied_gpos": ["GPO non appliquee"],
"domain_groups": ["EXEMPLE\\Domain Users"],
"security_groups": {
"domain": ["EXEMPLE\\Domain Users"],
"local": ["BUILTIN\\Users"],
"system": ["NT AUTHORITY\\INTERACTIVE"],
"other": []
}
}
```
| Champ | Signification |
| --- | --- |
| `status` | État de la collecte ; ce n'est pas un verdict de conformité. |
| `user.account` | Identité lue dans le RSoP, ou nom détecté si elle est absente. |
| `user.username` | Partie du compte après le premier `\`, ou compte entier sans préfixe. |
| `user.account_domain` | Préfixe du compte, généralement NetBIOS pour un domaine ou nom du poste pour un compte local ; vide sans préfixe. |
| `user.account_type` | `local` si le préfixe est vide ou égal au nom du poste ; `domain` sinon. |
| `summary.applied_gpo_count` / `summary.denied_gpo_count` | Nombre de GPO retenues dans chaque liste. |
| `summary.total_gpo_count` | Somme des deux compteurs de GPO. |
| `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` / `denied_gpos` | Noms des GPO, dans l'ordre de collecte. |
| `domain_groups` | Même liste que `security_groups.domain`, pour faciliter le reporting. |
| `security_groups` | Groupes répartis entre `domain`, `local`, `system` et `other`. |
La recherche de texte est récursive et ignore les namespaces XML. Le type de compte est déduit du préfixe ; il n'est pas validé par une requête AD.
### Évolution du schéma
Les consommateurs de l'ancien résultat doivent utiliser `user.username` à la place de `user.name` et `user.account_domain` à la place de `user.domain`. Le résultat actuel ne contient plus de bloc `computer`. `user.account_type`, les listes de groupes et leurs compteurs sont ajoutés.
## Classement des GPO
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.
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. Aucun état indéterminable ne déclenche d'erreur spécifique dans cette version.
La recherche des balises `GPO` est récursive. Les entrées sans nom sont ignorées, sans repli sur un identifiant XML. 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.
## Classement des groupes de sécurité
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 :
| Catégorie | Règle |
| --- | --- |
| `system` | Préfixe `NT AUTHORITY\`. |
| `local` | Préfixe `BUILTIN\` ou nom du poste suivi de `\`. |
| `domain` | Préfixe du compte RSoP suivi de `\`, si ce préfixe est non vide et différent du nom du poste. |
| `other` | Toutes les autres identités. |
Un compte `POSTE01\utilisateur` ne fournit donc pas de préfixe AD pour classer les groupes de domaine. Les comparaisons et la déduplication ignorent la casse. Les entrées sans nom sont ignorées et chaque liste est triée alphabétiquement sans distinction de casse.
Ce classement repose sur les noms de l'export, sans validation 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 et cas particuliers
| 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. |
| `NO_USER` | `OK` | Aucun utilisateur actif reconnu, y compris en cas d'échec de détection capturé. |
| `ERROR` | `ERROR` | Exception capturée par l'audit : GPResult en échec, fichier absent, XML invalide, section `UserResults` absente, etc. |
Le résultat `NO_USER` contient `message`, `user: null`, des listes `applied_gpos`, `denied_gpos` et `domain_groups` vides, ainsi que les quatre catégories vides de `security_groups`. Il ne contient pas de bloc `summary`. Aucun statut `WARNING` n'est utilisé.
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. Les consommateurs doivent lire `status` avant d'accéder aux champs de succès.
La clé représente le dernier audit du poste, selon l'utilisateur sélectionné au moment de l'exécution ; aucune clé distincte par utilisateur n'est créée.
## 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.
4. Lancer l'audit avec une session active et consulter `audit-gpresult.user-gpo`.
La fréquence des audits dépend de la configuration WAPT ; le script ne crée pas de planification. Le journal indique l'utilisateur détecté, le compte RSoP, son type, les compteurs de GPO et de groupes de domaine ou l'erreur rencontrée.
- **`NO_USER` inattendu :** vérifier la sortie de `quser.exe`, les libellés reconnus et les éventuelles erreurs de détection dans le journal.
- **Compte inattendu :** vérifier l'ordre des sessions actives et comparer le nom détecté avec `user.account`.
- **Erreur GPResult ou XML :** vérifier les droits de l'agent, la disponibilité du RSoP pour ce compte, l'accès à GPResult et au répertoire temporaire.
Le rapport utilise le nom fixe `wapt-gpresult-user.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` : détection de session, collecte et analyse des GPO et groupes de sécurité utilisateur.
- `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.