Aller au contenu

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 :

  1. Ce qu'est la détection de dérive (et ce qu'elle n'est pas)
  2. Écrire une baseline en YAML
  3. Créer une baseline via l'API
  4. Assigner une baseline à des machines (tags ou un client spécifique)
  5. Lancer un scan et lire les résultats
  6. 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.

Comment obtenir le hash SHA-256 d'un fichier

sha256sum /etc/ssh/sshd_config

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 drift ne 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é.