Gouverner les appels d'outils MCP d'un agent IA avec OPA/Rego
OPA Rego permissions agent IA MCP : comment interposer une décision de politique-as-code avant chaque appel d'outil, selon le rôle, la sensibilité et l'heure.
Un serveur MCP (Model Context Protocol) donne à un agent l'accès à des outils réels : lecture de fichiers, appels d'API internes, requêtes en base de données. C'est précisément ce qui rend l'agent utile, et c'est précisément ce qui rend la question du contrôle d'accès non négociable. Le protocole MCP décrit comment un outil est exposé et appelé ; il ne décrit pas qui a le droit de l'appeler, dans quel contexte, ni avec quelles données. Cette responsabilité reste entièrement à la charge de celui qui déploie le serveur.
Open Policy Agent (OPA) et son langage Rego répondent à ce manque avec un principe simple : la politique d'autorisation devient du code, versionné, testé, séparé de la logique métier. Appliqué aux appels d'outils MCP, cela permet de poser une question précise avant chaque exécution : ce rôle, sur cette donnée, à cette heure, a-t-il le droit d'appeler cet outil ?
Le problème : des outils réels sans autorisation contextuelle
La plupart des intégrations MCP livrées en configuration par défaut appliquent un contrôle binaire : le serveur est accessible ou non, l'outil est enregistré ou non. Une fois la connexion établie, l'agent peut appeler n'importe quel outil exposé, sur n'importe quelle ressource, à n'importe quel moment. Il n'existe pas de notion native de rôle, de sensibilité de la donnée manipulée, ou de fenêtre horaire autorisée.
Le risque concret : un agent conversationnel qui dispose d'un outil query_database générique peut, en théorie, exécuter une requête sur une table contenant des données RH ou des secrets applicatifs, simplement parce que l'outil existe et que rien n'en limite l'usage selon qui pose la question. Le sandboxing applicatif (isolation du code exécuté, limitation des appels systèmes) protège contre l'exécution de code arbitraire, mais il ne répond pas à la question métier : cet appel-là, dans ce contexte-là, est-il légitime ?
Le point d'application : interposer une décision avant l'exécution
La réponse tient en une phrase : chaque appel d'outil MCP doit passer par un point de décision avant d'atteindre l'outil lui-même. Concrètement, le serveur MCP (ou un proxy placé devant lui) interroge un moteur OPA avec le contexte de l'appel, et n'exécute l'outil que si la réponse est allow: true.
Avant (sans point d'application) :
agent -> serveur MCP -> outil "query_database" -> exécution directeAprès (avec OPA en coupure) :
agent -> serveur MCP -> requête de decision OPA (rôle, outil, sensibilité, heure)
-> allow == true -> exécution de l'outil
-> allow == false -> refus + journalisationL'important est que ce point d'application soit incontournable : il ne s'agit pas d'un contrôle optionnel côté agent (que l'agent pourrait contourner en reformulant sa demande), mais d'une barrière côté serveur, entre la réception de l'appel et son exécution effective.
Écrire la politique Rego
Une politique Rego pour ce cas d'usage prend en entrée un objet input décrivant l'outil demandé, le rôle de l'utilisateur ou du contexte d'exécution de l'agent, la sensibilité de la ressource ciblée, et l'heure de l'appel :
# Exemple d'input évalué par OPA à chaque appel d'outil
input:
tool: "query_database"
user:
role: "analyst"
resource:
sensitivity: "internal"
timestamp: "2026-07-17T14:32:00Z"La politique elle-même, en Rego :
package mcp.authz
import future.keywords.in
default allow := false
# Un analyste peut lire un fichier, sauf si la ressource est classée critique.
allow if {
input.tool == "read_file"
input.user.role in {"analyst", "admin"}
input.resource.sensitivity != "critical"
}
# Un administrateur peut interroger la base, uniquement en heures ouvrées.
allow if {
input.tool == "query_database"
input.user.role == "admin"
business_hours
}
business_hours if {
hour := time.clock(time.now_ns())[0]
hour >= 7
hour < 20
}Chaque règle allow combine explicitement l'outil demandé (input.tool), le rôle, et une condition contextuelle (sensibilité ou fenêtre horaire). Rien n'est autorisé par défaut : c'est la construction volontaire de la règle suivante qui compte.
Deny-by-default, journalisation, tests avec opa test
Le default allow := false n'est pas un détail stylistique : c'est la propriété qui garantit que tout outil nouvellement exposé, toute combinaison de rôle non anticipée, se traduit par un refus plutôt que par un accès silencieux. C'est l'inverse d'une liste noire, qui oublie toujours un cas.
Chaque décision, positive ou négative, doit être journalisée avec son contexte complet (outil, rôle, ressource, résultat, motif) pour permettre l'audit a posteriori. Une politique sans traçabilité de ses propres décisions est aussi risquée qu'une absence de politique : personne ne peut vérifier ce qui a réellement été autorisé.
Enfin, une politique Rego se teste comme du code applicatif, avec opa test :
package mcp.authz_test
import data.mcp.authz.allow
test_analyst_can_read_internal_file if {
allow with input as {
"tool": "read_file",
"user": {"role": "analyst"},
"resource": {"sensitivity": "internal"}
}
}
test_analyst_cannot_read_critical_file if {
not allow with input as {
"tool": "read_file",
"user": {"role": "analyst"},
"resource": {"sensitivity": "critical"}
}
}opa test policies/ -vCe cycle de test doit tourner en intégration continue, au même titre que n'importe quel test unitaire : une modification de la politique qui casse un cas couvert doit être détectée avant le déploiement, pas après un incident.
Complémentarité avec le sandboxing applicatif
OPA ne remplace pas le sandboxing applicatif, il le complète, et les deux barrières répondent à des questions différentes. Le sandboxing (isolation de l'exécution, restriction des appels systèmes et réseau disponibles au code exécuté) répond à la question : que peut techniquement faire ce code, quoi qu'il arrive ? La politique OPA répond à une question distincte : cette action précise, pour ce rôle précis, sur cette donnée précise, est-elle autorisée maintenant ?
Confondre les deux crée un doublon de barrière inutile ou, pire, un faux sentiment de sécurité : un sandbox bien conçu n'a pas vocation à connaître la sensibilité métier d'une donnée, et une politique de haut niveau n'a pas vocation à réimplémenter l'isolation d'exécution. Chaque couche reste sur son terrain, et c'est cette séparation qui rend l'ensemble auditable plutôt que redondant.
Un pack de politiques prêtes à l'emploi
Écrire ces politiques depuis zéro pour chaque scénario MCP (lecture de fichiers, requêtes en base, appels d'API sortants, actions d'écriture) est un travail répétitif que peu d'équipes ont le temps de refaire correctement, avec les tests et la journalisation qui vont avec. C'est exactement ce que nous livrons dans le pack de politiques OPA/Rego pour agents MCP : des règles de contrôle contextuel (rôle, sensibilité, horaire, outil) déjà rédigées, testées avec opa test, et prêtes à s'interposer devant vos serveurs MCP.
Articles liés
Google observe des clusters attaqués en 18 minutes et des évasions via pods privilégiés. Voici la détection Falco au runtime et les garde-fous OPA à l'admission.
Red team serveur MCP injection prompt indirecte : vérifier qu'un document piégé ne déclenche pas un appel d'outil ou une exécution non autorisée.
Le policy as code OPA Rego Kubernetes permet de refuser un pod privilégié avant qu'il ne démarre. OPA/Rego vs Kyverno, exemples, tests, et preuve NIS2/DORA.
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.