Sécurité MCP
Cette page liste ce que la passerelle MCP du Control Plane applique à chaque appel MCP, comment les identifiants, la provenance et la suspension sont traités, les menaces ainsi couvertes, et les étapes qu'un développeur et un administrateur du tenant suivent pour durcir un serveur MCP. Elle s'adresse aux développeurs, aux administrateurs du tenant et aux responsables sécurité.
Contrôles de la passerelle
POST /v1/mcp/gateway/{server_id} applique les contrôles ci-dessous dans cet ordre, pour chaque message d'un lot. Un refus n'atteint jamais le serveur et est audité.
| Ordre | Contrôle | Refus |
|---|---|---|
| 1 | Authentification de l'appelant, relation OpenFGA can_invoke sur le serveur, rôle d'exploitation | HTTP 401 ou 403 |
| 2 | Message JSON-RPC 2.0 | -32600 |
| 3 | Serveur active | -32003 "MCP server disabled" |
| 4 | Isolation par projet (ADR-0165) | -32003 mcp_server_project_mismatch |
| 5 | Liste d'accès du serveur (allowed_principals ; propriétaire et agents pour une instance du Runtime MCP) | -32003 mcp_principal_not_allowed |
| 6 | Identifiant lié à une application : le serveur doit faire partie de ses mcp_servers | -32003 avec le code du refus |
| 7 | Méthode parmi initialize, tools/list, tools/call, resources/list, resources/read, prompts/list, ping | -32601 |
| 8 | tools/call : outil dans allowed_tools (glob), portée tools:invoke | -32003 |
| 9 | tools/call : DLP des arguments avec les règles du tenant ; une règle de blocage refuse | -32003 dlp_blocked |
| 10 | Décision de politique mcp.call (OPA) avec method et target, coupe-circuits du SOC | HTTP 403 |
| 11 | tools/call : réservation de quota d'un appel d'outil | HTTP 429 quota_exceeded |
| 12 | resources/read : URI dans allowed_resources (glob) | -32003 |
| 13 | Sortie réseau : adresse interne uniquement, revérifiée à la connexion | HTTP 403 mcp_online_forbidden |
| 14 | Réponse : tools/list et resources/list filtrés par les listes d'autorisation ; résultat de tools/call masqué par la DLP ; résultats de tools/call et resources/read analysés contre l'injection de prompt | -32003 dlp_blocked ou prompt_injection_blocked |
| 15 | Événement d'usage (appel d'outil, durée) et événement d'audit mcp.<method> avec la cible et les détections de la DLP |
Quand la Tool Gateway appelle un outil MCP (POST /v1/tools/{name}/invoke), elle évalue tool.invoke et compte
l'appel elle-même ; la passerelle MCP saute alors sa propre décision de politique, son quota et son événement
d'usage.
Sortie réseau : serveurs internes uniquement
- Un serveur n'est atteint qu'à une adresse interne (ADR-0170) : un hôte interne de
EAI_MCP_INTERNAL_HOSTS, un serveur hébergé par le Navin Manager (ses instances nommées dansEAI_EGRESS_PRIVATE_ALLOWLIST), ou une instance du Runtime MCP à l'adresse de son proxy dans le cluster. - L'adresse est vérifiée à l'enregistrement du serveur et de nouveau à chaque appel : chaque adresse vers laquelle
l'hôte se résout doit être privée. Une destination publique répond 403
mcp_online_forbidden, est auditée ensecurity.egress.deniedet comptée danseai_mcp_online_refused_total. - La restriction de sortie du tenant (hôtes autorisés) s'applique toujours.
- L'adresse d'une instance du Runtime MCP est écrite par le contrôleur de cycle de vie, jamais par un tenant, et doit correspondre au motif des proxys du cluster ; la CiliumNetworkPolicy de l'instance limite qui atteint le proxy et où le conteneur MCP peut aller.
Identifiants par le broker
- L'enregistrement ne prend que des références :
credential_refvautopenbao://...ouenv://...;auth.typeconnectornomme un connecteur dont le Credential Broker détient les identifiants. - La passerelle résout le secret au moment de l'appel, côté serveur, et le place uniquement dans l'en-tête
(
bearer,api_key) ou dans le paramètre de requête (query_param) de la requête sortante. Les réponses renvoientauth.type,header,param,credential_refetconnector, jamais une valeur. - Un serveur hébergé par le Navin Manager reçoit son propre jeton, gardé à
openbao://mcp/hosted/<id>; aucune réponse et aucun événement d'audit ne le contient. - Une instance du Runtime MCP reçoit un JWT court par appel (sujet l'appelant, audience l'instance) et ses propres identifiants temporaires, révoqués quand elle se met en veille ou se termine. Voir Runtime MCP par utilisateur et par projet.
Signature et provenance
| Contenu | Preuve |
|---|---|
| Schémas des outils | sha256 de la description, des schémas d'entrée et de sortie par outil ; chaque schéma nouveau ou modifié est une version du catalogue avec une approbation (mcp_tool_version) |
| Packs de la marketplace avec des serveurs MCP | Contrôles de publication : signature, SBOM, analyse de vulnérabilités, provenance, licence, permissions, tests (Marketplace) |
| Images du Runtime MCP | Registre interne de EAI_MCP_RUNTIME_IMAGE_REGISTRIES, épinglées par empreinte ; Kyverno refuse un MCPServer sans empreinte |
| Préréglages de la bibliothèque Navin | Empreinte sha256 de chaque élément dans catalog/navin/index.json, vérifiée par python tools/navin_library/sync.py --check |
Quarantaine et suspension
| Mécanisme | Effet | Comment |
|---|---|---|
| Désactiver un serveur | Les appels répondent "MCP server disabled" tout de suite ; la réactivation est une demande de promotion approuvée par une seconde personne | POST /v1/mcp/servers/{server_id}/status |
| Suspendre une installation de la marketplace | Ses outils bloqués, ses agents suspendus, ses serveurs MCP désactivés ; la reprise demande une approbation à quatre yeux | POST /v1/marketplace/installations/{installation_id}/status |
| Coupe-circuit d'un paquet | Toutes les installations du paquet suspendues | POST /v1/marketplace/packages/{name}/status |
Ordre SOC DISABLE_TOOL sur la cible mcp | Décisions de politique qui touchent le serveur refusées, y compris après le redémarrage de chaque réplica | POST /v1/soc/orders (procédure SOC) |
Détection mcp_compromised | Sévérité sev1, playbook DISABLE_TOOL sur la cible MCP | Détections du SOC |
| Serveur hébergé qui ne l'est plus | Désactivé à la synchronisation suivante | POST /v1/mcp/hosted/sync |
| Instance du Runtime MCP en panne | Détruite tout de suite, identifiants révoqués | Contrôleur de cycle de vie |
Menaces
| Menace | Contrôle | Preuve |
|---|---|---|
| Données d'un projet envoyées à un service MCP en ligne | Adresses internes uniquement, vérifiées à l'enregistrement et à chaque appel | Audit security.egress.denied, eai_mcp_online_refused_total |
| Agent d'un projet qui appelle un serveur d'un autre projet | Isolation par projet, refus avant tout appel au serveur | Audit mcp.call avec deny et la raison |
| Membre d'un projet qui utilise les identifiants d'un autre membre | Liste d'accès par serveur, une instance du Runtime MCP par utilisateur avec ses propres identifiants et sa politique Cedar | Audit mcp.call principal_not_allowed |
| Rug pull : un serveur change la description ou le schéma d'un outil | Nouvelle version du catalogue avec approbation à chaque découverte ; allowed_tools appliqué par la passerelle | new_versions de la découverte, approbations |
| Empoisonnement d'outil ou injection de prompt dans un résultat | Analyse du contenu non fiable des résultats de tools/call et resources/read | prompt_injection_blocked |
| Exfiltration de données sensibles dans les arguments ou les résultats | DLP avec les règles du tenant : arguments inspectés (règles de blocage), résultats masqués | Champ dlp de l'événement d'audit |
| Fuite de secret par le registre | Références uniquement ; secrets résolus côté serveur au moment de l'appel | auth des réponses sans valeur |
| Rejeu d'un jeton sur une autre instance | Une audience par instance, durée de vie courte | EAI_MCP_RUNTIME_TOKEN_TTL_SECONDS |
| Abus d'appels | Réservation de quota par appel d'outil, événements d'usage | 429 quota_exceeded, usage |
| Serveur compromis | Désactivation, coupe-circuit du SOC, suspension de la marketplace | État du coupe-circuit, audit |
| Image ou pack falsifié | Épinglage par empreinte, contrôles de signature et de provenance | Contrôles de la marketplace, Kyverno |
Durcir un serveur et son projet
-
Garder des listes d'autorisation courtes. Enregistrez le serveur avec les
allowed_toolsetallowed_resourcesexacts dont il a besoin, jamais*en production.Résultat attendu : GET /v1/mcp/servers/{server_id}/tools ne liste que ces outils.
En cas d'échec : la liste ne se modifie pas en place ; supprimez le serveur et enregistrez-le de nouveau.
-
Restreindre les appelants. PUT /v1/mcp/servers/{server_id}/access avec les utilisateurs et les agents qui en ont besoin.
client.mcp.set_access("files-server", ["agent:support-bot", "user:alice"])Résultat attendu : tout autre appelant reçoit
mcp_principal_not_allowed.En cas d'échec : 409
mcp_instance_access_managedpour une entrée du Runtime MCP (propriétaire et agents uniquement). -
Rattacher le serveur à son projet. Enregistrez-le avec
project; un serveur sans projet est partagé par tout le tenant.Résultat attendu : le serveur n'est pas listé depuis un autre projet.
En cas d'échec : 403
mcp_project_forbiddenquand le corps et la requête nomment des projets différents. -
Fixer des règles DLP de blocage pour les données que l'outil ne doit jamais recevoir. Utilisez les règles DLP du tenant (GET /v1/dlp/rules, POST /v1/dlp/rules) ; la passerelle les applique aux arguments et aux résultats.
Résultat attendu : un tools/call avec une valeur bloquée répond
dlp_blocked.En cas d'échec : testez la règle avec POST /v1/dlp/inspect.
-
Écrire une politique pour
mcp.call. Refus par défaut, autorisez les méthodes et les outils dont le projet a besoin, testez chaque règle (Développement de politiques).Résultat attendu : un outil non listé est refusé en HTTP 403 par la décision de politique.
En cas d'échec : lancez les tests de politique (
enterprise-ai test authz). -
Approuver les versions d'outils après une revue. Lisez les schémas de chaque version
pending_approvaldans GET /v1/mcp/catalog avant d'approuver.Résultat attendu : chaque version utilisée est
approved.En cas d'échec : rejetez la version et désactivez le serveur jusqu'à sa correction.
-
Surveiller les signaux. Suivez
eai_mcp_calls_totalpar résultat,eai_mcp_online_refused_totalet les événements d'auditmcp.*; vérifiez l'intégrité de la chaîne d'audit avecenterprise-ai audit verify.Résultat attendu : les refus s'expliquent par une modification connue.
En cas d'échec : ouvrez un incident et suivez la procédure SOC.
Ne mettez jamais une valeur secrète dans un corps d'enregistrement, un manifeste ou un champ de préréglage : les champs secrets n'acceptent que des références, et une valeur écrite là serait lisible par chaque lecteur du registre.
Vérifier
- Un appel à un outil hors de
allowed_toolsrépond -32003 et GET /v1/audit/events contientmcp.tools.callavecdenyetnot in allow list. - Un enregistrement avec une URL publique répond 403
mcp_online_forbidden.
Étapes suivantes
Dépannage
| Symptôme | Cause | Correction |
|---|---|---|
-32003 dlp_blocked sur un appel légitime | Une règle de blocage du tenant correspond aux arguments ou au résultat | Lisez les détections dans l'événement d'audit ; ajustez la règle avec le responsable sécurité |
-32003 prompt_injection_blocked | Le résultat du serveur contient des instructions destinées au modèle | Corrigez le contenu servi par l'outil |
| HTTP 403 sur chaque appel après un incident | Coupe-circuit du SOC ou suspension actif | Lisez GET /v1/soc/kill-switches ; le rétablissement suit la procédure SOC |
HTTP 403 mcp_online_forbidden | Hôte public | Hébergez le serveur en interne |
| -32003 "scope tools:invoke required" | Clé ou jeton sans la portée | Émettez une clé avec tools:invoke |