Garder l'humain dans la boucle : gates d'approbation Rego avant la remédiation par agent IA
OPA Rego encadre la validation humaine avant la remédiation par agent IA : isolation automatique, approbation obligatoire pour les actions destructrices.
Les éditeurs 2026 communiquent volontiers sur des temps de remédiation automatique inférieurs à dix secondes. Aqua Compass, Elastic Workflows et une poignée d'autres promettent qu'un agent détecte, décide et corrige avant que l'analyste n'ait fini de lire l'alerte. Sur le papier, c'est la promesse ultime de l'automatisation de la réponse à incident. Sur le terrain, c'est exactement ce qui inquiète un RSSI : un agent qui décide seul de désactiver un compte de service critique, de chiffrer un disque ou de couper un accès réseau ne fait pas gagner du temps, il déplace le risque ailleurs.
La question n'est donc pas « faut-il automatiser la remédiation ? » mais « comment poser un point de contrôle humain avant qu'un agent ne touche la production, sans pour autant renoncer à la vitesse sur ce qui ne le mérite pas ? ». La réponse tient dans un mécanisme précis : une policy as code qui classe chaque action par son rayon d'impact, et un point d'application qui interroge cette policy avant toute exécution.
Une distinction à faire : ce n'est pas du scoping d'outils
Ce sujet est souvent confondu avec le scoping statique des permissions d'outils (quels appels un agent a le droit de faire, définis une fois pour toutes dans sa configuration). Ici, il s'agit d'autre chose : une décision par action, au moment de l'exécution, qui tient compte de la cible réelle et du contexte. Un agent peut avoir techniquement le droit d'appeler l'API de désactivation de compte ; la question posée à chaque appel est de savoir si cette désactivation, sur ce compte, dans ce contexte, peut s'exécuter seule ou doit attendre un humain.
Classer les actions par rayon d'impact
Le point de départ n'est pas technique, il est doctrinal : toutes les actions de remédiation ne se valent pas. Deux axes suffisent à les classer.
Le premier axe est la réversibilité. Isoler un poste du réseau se défait en un clic. Chiffrer un disque, supprimer un compte ou révoquer des certificats ne se défait pas, ou seulement avec des heures de restauration. Le second axe est le périmètre : une action qui touche un seul actif isolé n'a pas le même poids qu'une action qui touche un compte de domaine, un groupe d'utilisateurs ou une plage réseau entière.
Ces deux axes ne restent pas dans la tête d'un architecte, ils sont encodés en données de policy, versionnées comme du code :
# policy/data/actions.yaml
low_risk:
- action: isolate_host
reversible: true
scope: single_asset
- action: block_ip
reversible: true
scope: single_asset
- action: quarantine_file
reversible: true
scope: single_asset
requires_approval:
- action: disable_account
reversible: false
scope: identity
- action: delete_account
reversible: false
scope: identity
- action: encrypt_disk
reversible: false
scope: single_asset
- action: revoke_all_sessions
reversible: false
scope: domainCette classification est la vraie décision métier. Tout ce qui suit n'est que de la mécanique pour la faire respecter.
OPA comme moteur de décision (PDP)
Open Policy Agent joue ici le rôle de PDP (Policy Decision Point) : l'agent lui soumet une requête structurée (l'action, sa cible, le contexte) et reçoit en retour une décision parmi trois : allow, require_approval, ou deny. Le moteur ne connaît rien de la logique métier de l'agent, il évalue une policy Rego indépendante :
package threatclaw.remediation
default decision := {"result": "deny", "reason": "action non classifiée"}
low_risk_actions := {"isolate_host", "block_ip", "quarantine_file"}
approval_required_actions := {"disable_account", "delete_account", "encrypt_disk", "revoke_all_sessions"}
decision := {"result": "allow", "reason": "action réversible, périmètre unitaire"} if {
input.action in low_risk_actions
input.target.scope == "single_asset"
}
decision := {"result": "require_approval", "reason": "action irréversible ou à impact étendu"} if {
input.action in approval_required_actions
}Le point le plus important tient dans le default de la première ligne : si l'action n'apparaît dans aucune des deux listes, la décision par défaut est deny. Une action non classifiée n'est jamais assimilée à une action à faible risque par omission. C'est un principe de sécurité positive classique (deny by default) appliqué à l'autonomie d'un agent.
Le point d'application : l'agent interroge, il ne décide plus seul
Concrètement, avant chaque appel de remédiation, l'agent interroge le PDP via une requête HTTP au serveur OPA :
curl -s -X POST http://opa.internal:8181/v1/data/threatclaw/remediation/decision \
-H "Content-Type: application/json" \
-d '{
"input": {
"action": "disable_account",
"target": {"type": "user", "id": "j.dupont", "scope": "identity"},
"context": {"initiator": "agent", "case_id": "INC-4821"}
}
}'La réponse est déterministe et lisible par l'orchestrateur de l'agent :
{"result": {"result": "require_approval", "reason": "action irréversible ou à impact étendu"}}Avant ce garde-fou, la logique était codée en dur dans l'agent, un simple aiguillage sans nuance :
# avant : décision codée en dur, aucun point de contrôle externe
if action == "isolate_host":
execute(action)
elif action == "disable_account":
execute(action) # aucune distinction de risque
Après intégration du PDP, l'agent ne décide plus rien seul : il exécute, met en file d'attente pour approbation, ou rejette, en fonction d'une réponse externe et auditable :
decision=$(curl -s -X POST http://opa.internal:8181/v1/data/threatclaw/remediation/decision \
-d @input.json | jq -r '.result.result')
case "$decision" in
allow) execute_action ;;
require_approval) queue_for_human_review ;;
*) reject_action ;;
esacCe changement de quelques lignes déplace la responsabilité : la logique de risque quitte le code de l'agent pour vivre dans une policy versionnée, relue en revue de code, et testable indépendamment.
L'anti-piège : une policy non testée est une régression silencieuse
Une policy Rego est du code. Non testée, elle casse en silence : un renommage d'action, une correction de typo dans une liste, un refactor de la structure input, et une action qui devait exiger une approbation se retrouve auto-approuvée sans que personne ne s'en aperçoive avant l'incident. C'est le piège le plus coûteux de cette approche, et le plus facile à éviter.
La parade est un jeu de tests unitaires sur la policy elle-même, exécutés par conftest, avec un fichier policy_test.rego dédié :
package threatclaw.remediation
test_isolate_host_est_autonome if {
decision.result == "allow" with input as {
"action": "isolate_host",
"target": {"type": "host", "id": "WKS-042", "scope": "single_asset"}
}
}
test_disable_account_exige_approbation if {
decision.result == "require_approval" with input as {
"action": "disable_account",
"target": {"type": "user", "id": "test", "scope": "identity"}
}
}
test_action_non_classifiee_est_refusee if {
decision.result == "deny" with input as {
"action": "wipe_disk",
"target": {"type": "host", "id": "WKS-042", "scope": "single_asset"}
}
}Ces tests s'intègrent directement à la CI, à côté des tests applicatifs classiques :
policy-tests:
stage: test
script:
- conftest verify --policy policy/Toute modification de policy qui casserait la classification (par exemple faire passer disable_account du côté des actions autonomes par erreur) fait échouer le pipeline avant merge, exactement comme un test unitaire cassé sur du code applicatif. La policy cesse d'être un fichier de configuration qu'on modifie à la main en production ; elle devient un artefact versionné, relu, testé.
Aligné sur la doctrine du contrôle humain
Cette architecture n'est pas un compromis technique isolé, elle traduit un principe simple : l'humain valide toute action d'écriture qui modifie un état de production, l'automatisation ne couvre que ce qui est à la fois réversible et de faible portée. Isoler un poste compromis peut se défaire en un geste ; désactiver un compte, chiffrer un volume ou révoquer des accès à l'échelle d'un domaine ne se rattrape pas de la même façon. Tant qu'une action n'a pas été explicitement classée comme réversible et unitaire par la policy, elle reste bloquée en attente d'un humain, jamais exécutée par défaut.
C'est cette classification par rayon d'impact, testée et appliquée à chaque décision de remédiation, que nous outillons dans le pack de policies ThreatClaw : des gates d'approbation prêts à l'emploi, couvrant les actions de remédiation les plus courantes, testés en CI avant chaque publication.
Articles liés
Nous avons détoné un échantillon Phobos vivant. Voici ce qu'il fait, suppression des clichés instantanés, coupure du pare-feu, et la règle Sigma qui l'attrape, validée sur plusieurs échantillons, zéro faux positif.
Emotet, le botnet et chargeur malveillant, refait surface. Découvrez ses techniques et comment ThreatClaw renforce votre détection avec 24 règles YARA validées.
Découvrez Drokbk, un cheval de Troie d'accès à distance (RAT) sophistiqué ciblant les PME. ThreatClaw renforce sa détection avec 26 règles YARA validées pour contrer cette menace persistante.
Découvrez Dosia, un logiciel malveillant sophistiqué ciblant les SMB. ThreatClaw renforce sa détection avec 3 règles YARA validées, couvrant T1027 et T1105 (MITRE ATT&CK).