Détection de dérive de configuration : définir et utiliser des baselines¶
Repod peut détecter quand la configuration réelle d'une machine diverge d'un état de référence déclaré (« baseline ») — des paquets qui devraient être à une version spécifique, des services qui devraient être en cours d'exécution, des fichiers qui devraient correspondre à un hash connu, des permissions qui devraient être définies d'une certaine façon. Ce guide couvre :
- Ce qu'est la détection de dérive (et ce qu'elle n'est pas)
- Écrire une baseline en YAML
- Créer une baseline via l'API
- Assigner une baseline à des machines (tags ou un client spécifique)
- Lancer un scan et lire les résultats
- Limitations connues dans cette version
1. Ce qu'est la détection de dérive (et ce qu'elle n'est pas)¶
| Détection de dérive | Scan CVE | Conformité CIS/STIG | |
|---|---|---|---|
| Question à laquelle ça répond | « Cette machine correspond-elle toujours à l'état que j'ai déclaré ? » | « Cette machine a-t-elle des vulnérabilités connues ? » | « Cette machine suit-elle un référentiel de sécurité publié ? » |
| Référence | Une baseline que vous rédigez | La base de données CVE (NVD/Grype) | Un profil CIS/STIG publié |
| Portée | Paquets, services, fichiers, permissions | Versions des paquets installés | Ce que le référentiel définit |
La détection de dérive est détection et alerte uniquement — elle ne
modifie jamais la machine. Il n'y a pas de remédiation automatique dans
cette version ; si une règle rapporte drift, la corriger est une action
manuelle (ou scriptée séparément).
Les règles de type paquet sont comparées aux paquets que Repod a déjà en
dossier pour cette machine (scan SSH ou check-in de l'agent — aucun appel
réseau supplémentaire). Les règles de type service, fichier et permission
nécessitent une connexion SSH au moment du scan et ne sont pas
disponibles pour les clients en mode agent — l'agent est conçu pour être
push-only (il n'accepte jamais de commande venant du backend), il n'existe
donc aucun canal pour exécuter une vérification arbitraire dessus. Une
baseline mélangeant des règles de paquet et des règles service/fichier/
permission fonctionne quand même pour un client en mode agent ; les
règles service/fichier/permission rapporteront simplement not_applicable
pour lui.
2. Écrire une baseline en YAML¶
name: webservers
description: Reference configuration for production web servers
rules:
- id: nginx-version
type: package
target: nginx
expected: "1.18.*" # exact string, a glob ("1.18.*"), "present", or "absent"
severity: high
- id: telnet-absent
type: package
target: telnet-server
expected: absent
severity: critical
- id: sshd-running
type: service
target: sshd
expected_state: active # active | inactive | enabled | disabled
severity: critical
- id: sshd-config-hash
type: file
path: /etc/ssh/sshd_config
expected_sha256: "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde"
severity: high
- id: shadow-permissions
type: permission
path: /etc/shadow
expected_mode: "640"
expected_owner: root
expected_group: shadow
severity: high
Référence des champs par type de règle :
| Type | Champ cible | Champs de comparaison | Notes |
|---|---|---|---|
package |
target (nom du paquet) |
expected : version exacte, glob (1.18.*), present, ou absent |
Comparé aux données de paquets déjà collectées — aucun aller-retour SSH/agent |
service |
target (nom de l'unité systemd) |
expected_state : active|inactive|enabled|disabled |
active/inactive vérifie systemctl is-active ; enabled/disabled vérifie systemctl is-enabled — vérifications indépendantes, choisissez celle pertinente pour votre règle |
file |
path |
expected_sha256 (empreinte hex), et/ou expected: absent |
Omettre expected_sha256 sans expected: absent vérifie simplement l'existence du fichier |
permission |
path |
N'importe lequel de expected_mode (chaîne octale, ex. "640"), expected_owner, expected_group |
Seuls les champs que vous spécifiez sont vérifiés — une règle avec uniquement expected_mode ne se préoccupe pas du propriétaire du fichier |
Chaque règle a besoin d'un id unique au sein de la baseline (utilisé
pour l'identifier dans les résultats de scan et sachant que réexécuter
import de façon idempotente n'est pas pris en charge — importer deux
fois crée deux baselines ; supprimez ou modifiez plutôt la baseline
existante) et d'une severity : critical, high, medium, ou low.
3. Créer une baseline via l'API¶
Importez le document YAML directement (nécessite le rôle maintainer ou admin) :
curl -X POST http://YOUR_HOST:8000/api/v1/drift/baselines/import \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d "$(python3 -c 'import json,sys; print(json.dumps({"yaml": open(sys.argv[1]).read()}))' webservers.yaml)"
Ou construisez-la règle par règle via l'API :
curl -X POST http://YOUR_HOST:8000/api/v1/drift/baselines \
-H "Authorization: Bearer YOUR_TOKEN" -H "Content-Type: application/json" \
-d '{"name": "webservers", "description": "Reference configuration"}'
# → {"baseline": {"id": "...", ...}}
curl -X POST http://YOUR_HOST:8000/api/v1/drift/baselines/BASELINE_ID/rules \
-H "Authorization: Bearer YOUR_TOKEN" -H "Content-Type: application/json" \
-d '{"rule_key": "nginx-version", "type": "package", "target": "nginx",
"params": {"expected": "1.18.*"}, "severity": "high"}'
Exportez à tout moment une baseline existante vers YAML :
curl http://YOUR_HOST:8000/api/v1/drift/baselines/BASELINE_ID/export \
-H "Authorization: Bearer YOUR_TOKEN"
4. Assigner une baseline à des machines¶
Une baseline ne prend effet qu'une fois assignée — soit à un tag de machine (s'applique à chaque machine portant ce tag), soit à un client spécifique (une surcharge qui remplace toute baseline dérivée d'un tag pour cette seule machine, elle ne s'y ajoute pas). Ceci nécessite le rôle admin :
# Appliquer à chaque machine taguée "web"
curl -X POST http://YOUR_HOST:8000/api/v1/drift/baselines/BASELINE_ID/assignment \
-H "Authorization: Bearer YOUR_TOKEN" -H "Content-Type: application/json" \
-d '{"principal_type": "tag", "principal_id": "web"}'
# Ou surcharger pour une machine spécifique
curl -X POST http://YOUR_HOST:8000/api/v1/drift/baselines/BASELINE_ID/assignment \
-H "Authorization: Bearer YOUR_TOKEN" -H "Content-Type: application/json" \
-d '{"principal_type": "client", "principal_id": "CLIENT_ID"}'
Une machine sans correspondance de tag et sans surcharge de client n'a tout simplement aucune baseline — c'est un état normal et attendu, pas une erreur. Contrairement à la conformité CIS (qui retombe toujours sur un profil intégré), il n'existe pas de baseline par défaut : une baseline est votre propre état déclaré, pas une politique de sécurité universelle, donc rien n'est supposé silencieusement.
Si une machine correspond à plusieurs tags, toutes leurs baselines s'appliquent ensemble (l'union de leurs règles).
5. Lancer un scan et lire les résultats¶
# Déclencher un scan (s'exécute en arrière-plan)
curl -X POST http://YOUR_HOST:8000/api/v1/drift/clients/CLIENT_ID/scan \
-H "Authorization: Bearer YOUR_TOKEN"
# Lire les derniers résultats
curl http://YOUR_HOST:8000/api/v1/drift/clients/CLIENT_ID/results \
-H "Authorization: Bearer YOUR_TOKEN"
Chaque résultat porte un status (match, drift, error, ou
not_applicable), expected_value, actual_value, et severity. Un
statut drift signifie que la cible de la règle a divergé de ce que la
baseline déclare — c'est le signal sur lequel agir.
Les scans forment aussi un historique en ajout seul — chaque scan ajoute un nouveau lot de résultats plutôt que d'écraser le précédent, ce qui permet de suivre la dérive dans le temps :
curl http://YOUR_HOST:8000/api/v1/drift/clients/CLIENT_ID/history \
-H "Authorization: Bearer YOUR_TOKEN"
Un scan planifié s'exécute aussi quotidiennement (06:30 UTC par défaut,
configurable sous settings.json["drift"]) sur chaque client activé
disposant d'au moins une baseline résolue.
6. Limitations connues dans cette version¶
- Détection uniquement, aucune remédiation automatique. Un résultat
driftne déclenche jamais de changement sur la machine — c'est un choix délibéré pour éviter le risque qu'une « correction » automatisée cause des dégâts non intentionnels lors d'un premier déploiement de cette fonctionnalité. - Les règles service/fichier/permission nécessitent SSH. Les clients en mode agent n'ont que la couverture des règles paquet ; étendre la charge utile push de l'agent pour prendre en charge davantage de types de faits est un ajout futur possible, non implémenté aujourd'hui.
- Les règles fichier comparent un hash SHA-256, pas des diffs complets de contenu. Suffisant pour détecter qu'un fichier a changé, pas ce qui a changé à l'intérieur.
- Aucun support Windows. L'exécution à distance de Repod est SSH/Linux uniquement — il n'existe pas de type de règle « clé de registre » et aucun n'est prévu sans qu'un transport Windows soit d'abord ajouté.