Sécurité IA
Agents IA qui appellent vos APIs : le moindre privilège, hop par hop
Un agent Bedrock avec un rôle IAM unique est un accès admin de fait. Identité de workload, échange de jeton OBO, autorisation par outil au Gateway : la méthode et les artefacts.
Dans la plupart des plateformes IA que j’audite, l’agent a un seul rôle d’exécution IAM, et ce rôle a le droit de faire à peu près tout ce dont l’agent aura un jour besoin : lire la base clients, écrire dans le CRM, appeler l’API de facturation. C’est plus simple à développer. C’est aussi, de fait, un accès admin partagé par tous les utilisateurs de l’agent — et par quiconque parvient à lui faire exécuter une instruction qu’il n’aurait pas dû suivre.
L’agent n’est plus un chatbot qui répond à une question. Il appelle des outils, des APIs internes, des bases de données, parfois d’autres agents. OWASP appelle ça l’« excessive agency » : trop de fonctions accessibles, trop de permissions par fonction, trop d’autonomie sans validation humaine sur les actions à fort impact — c’est l’une des catégories les plus étoffées du Top 10 LLM 2025, et OWASP a publié en décembre 2025 un référentiel dédié, le Top 10 pour les applications agentiques, qui traite spécifiquement l’identité et les abus d’outils dans les chaînes multi-agents.
Cet article documente le contrôle que je mets en place en mission : une identité propre à l’agent, un jeton scopé à chaque saut de la chaîne, une autorisation par outil, et la preuve à produire pour un auditeur ou un client. Le fil conducteur technique est AWS Bedrock AgentCore Identity, qui a justement gagné en avril 2026 la brique qui manquait pour faire ça proprement sur AWS.
La menace : un rôle IAM unique pour tout l’agent
Le schéma classique d’un agent en production a trois maillons, et chacun a un rayon d’impact différent s’il est compromis :
Utilisateur → Agent. L’utilisateur envoie une requête, éventuellement accompagnée d’un document, d’un e-mail ou d’une page web que l’agent va lire. C’est le point d’entrée de l’injection de prompt — indirecte la plupart du temps, cachée dans un contenu que l’agent traite comme donnée mais que le modèle interprète en partie comme instruction. Un chercheur OWASP le rappelait encore lors d’Infosecurity Europe 2026 : le problème n’est pas résolu au niveau fondamental, parce qu’un LLM traite tout comme une séquence de tokens sans frontière de privilège native.
Agent → Outil A. L’agent traduit une intention (légitime ou injectée) en appel d’outil : une requête SQL, un appel API, une écriture dans un ticket. Si l’agent tourne avec un rôle IAM unique et large — le cas le plus fréquent que je constate — cet appel s’exécute avec les droits du service, pas ceux de l’utilisateur qui a initié la conversation.
Outil A → Outil B. Les agents modernes chaînent les appels : lire un ticket, puis appeler une API de paiement, puis écrire dans un CRM. Chaque saut supplémentaire multiplie le rayon d’impact d’une seule identité compromise en amont.
Le point commun des incidents que je vois en mission n’est pas un exploit technique sophistiqué. C’est un agent avec un seul rôle de service, capable d’agir pour n’importe quel utilisateur avec les mêmes droits — donc capable, sous injection, d’accéder aux données de n’importe quel utilisateur ou de déclencher n’importe quelle action que ce rôle autorise.
Le contrôle : une identité par agent, un jeton scopé à chaque saut
Étape 1 — une identité de workload, distincte du rôle d’exécution
Amazon Bedrock AgentCore Identity sépare l’identité de l’agent (le workload identity) du rôle d’exécution IAM qui fait tourner le code. Le rôle d’exécution n’a plus besoin d’accéder directement à DynamoDB, à une API interne ou à un service tiers : il n’a que le droit d’échanger un jeton via sts:AssumeRoleWithWebIdentity et GetWorkloadAccessTokenForJWT. Concrètement, même si le code de l’agent est manipulé par injection de prompt, il ne peut pas improviser un accès qui ne passe pas par cet échange.
Étape 2 — échanger le jeton utilisateur contre un jeton scopé (On-Behalf-Of)
C’est la pièce qui manquait sur AWS jusqu’à avril 2026 : AgentCore Identity supporte désormais l’échange de jeton On-Behalf-Of (RFC 8693). Le principe : l’agent ne détient jamais les identifiants du service cible. Il présente son jeton de workload à AgentCore Identity, qui va chercher le secret client dans Secrets Manager et effectue l’échange RFC 8693 avec le service — l’agent ne voit que le jeton scopé final, cryptographiquement lié au sub de l’utilisateur authentifié. Il ne peut pas demander un jeton pour un autre utilisateur que celui qui a initié l’appel.
from bedrock_agentcore.identity.auth import requires_access_token
@requires_access_token(
provider_name="internal-billing-api",
scopes=["invoices:read"],
auth_flow="ON_BEHALF_OF_TOKEN_EXCHANGE",
)
def _get_billing_token(*, access_token: str) -> str:
return access_token
@tool
def get_customer_invoices(customer_id: str) -> str:
token = _get_billing_token()
resp = requests.get(
f"{BILLING_API_URL}/customers/{customer_id}/invoices",
headers={"Authorization": f"Bearer {token}"},
timeout=30,
)
return resp.json()
Côté IAM, le rôle d’exécution de l’agent n’a que le strict nécessaire pour opérer l’échange — jamais un accès direct large aux données. Sur les ressources AWS accessibles directement (DynamoDB, S3), on scope en plus par condition sur une claim du JWT, par exemple le département de l’utilisateur propagé depuis Cognito :
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["dynamodb:GetItem", "dynamodb:Query"],
"Resource": "arn:aws:dynamodb:eu-west-1:123456789012:table/CustomerRecords",
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["${aws:PrincipalTag/department}"]
}
}
}
]
}
Résultat : un agent RH ne peut structurellement pas lire les enregistrements du département finance, quelle que soit l’instruction qu’un prompt injecté essaie de lui faire exécuter — la décision est appliquée par IAM, pas par le prompt système.
Étape 3 — autoriser chaque outil, pas juste chaque agent
Un agent qui a accès à un AgentCore Gateway exposant dix outils ne doit pas pouvoir tous les appeler avec la même identité. Les interceptors de Gateway s’exécutent avant (REQUEST) ou après (RESPONSE) l’appel à la cible, et permettent de filtrer par scope JWT au niveau de l’outil, pas seulement du gateway :
def lambda_handler(event, context):
body = event["mcp"]["gatewayRequest"]["body"]
token = event["mcp"]["gatewayRequest"]["headers"].get("Authorization", "").replace("Bearer ", "")
scopes = decode_jwt_payload(token).get("scope", "").split()
target, tool = body.get("params", {}).get("name", "__").split("___")
authorized = target in scopes or f"{target}:{tool}" in scopes
if not authorized:
return {
"interceptorOutputVersion": "1.0",
"mcp": {"transformedGatewayResponse": {
"statusCode": 403,
"headers": {},
"body": {"error": f"scope manquant pour {target}:{tool}"},
}},
}
return {
"interceptorOutputVersion": "1.0",
"mcp": {"transformedGatewayRequest": {"headers": event["mcp"]["gatewayRequest"]["headers"], "body": body}},
}
Avec ce filtre, un agent qui a le scope billing-api:getInvoices mais pas crm-api:deleteContact se voit refuser le second appel avant même qu’il atteigne le CRM — la vérification n’est plus laissée au bon vouloir du prompt système.
Étape 4 — confirmation humaine sur les actions à fort impact
Le troisième pilier de l’« excessive agency » côté OWASP est l’autonomie non bornée : un agent qui peut effacer, transférer ou publier sans validation. En pratique, ça se traduit par une liste explicite d’outils marqués requires_human_review: true (suppression, paiement, envoi externe), interceptés côté Gateway pour déclencher un état d’attente au lieu d’un appel direct, et une confirmation portée par un canal hors du contrôle du modèle (UI, Slack, ticket) — jamais une simple question posée dans la même conversation que le prompt potentiellement injecté.
La preuve pour l’auditeur
Ce que je livre en fin de mission, exploitable tel quel :
# Rôle d'exécution de l'agent : aucun accès direct large, uniquement l'échange de jeton
aws iam get-role-policy --role-name agentcore-billing-agent-exec --policy-name workload-token-exchange
# Vérifier qu'aucune policy attachée ne donne un accès *-large aux données
aws accessanalyzer list-findings \
--analyzer-arn arn:aws:access-analyzer:eu-west-1:123456789012:analyzer/agents-prod \
--filter '{"resource":{"contains":["agentcore-billing-agent-exec"]}}'
# Traçabilité par invocation : remonter la chaîne complète user -> agent -> outil
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=InvokeAgentRuntime \
--start-time "$(date -u -d '24 hours ago' +%FT%TZ)" \
| jq '.Events[] | {eventTime, username, requestParameters}'
Attendu : le rôle d’exécution ne porte que l’échange de jeton, IAM Access Analyzer ne remonte aucun accès cross-tenant sur ce rôle, et chaque invocation dans CloudTrail est reliée à un utilisateur identifié — pas à un compte de service générique. C’est ce triptyque, pas une capture d’écran du prompt système, qui répond à la question d’un auditeur SOC2 ou d’un client sur « qui peut faire quoi avec cet agent ».
Conclusion
Le moindre privilège sur un agent IA n’est pas une checklist de prompt engineering — c’est une architecture d’identité : un workload identity par agent, un jeton scopé et lié à l’utilisateur à chaque saut, une autorisation par outil, une confirmation humaine sur les actions à fort impact. Si votre plateforme Bedrock ou RAG est en production et que personne n’a encore répondu précisément à « que peut faire cet agent, et pour qui », l’offre Audit Sécurité IA & Bedrock couvre exactement ce périmètre en deux semaines.
Sources : AWS Security Blog — Propagate user authorization context in AI agents with Amazon Bedrock AgentCore, AWS — Bedrock AgentCore Identity OBO token exchange (avril 2026), AWS ML Blog — Fine-grained access control with AgentCore Gateway interceptors, OWASP Top 10 pour les applications agentiques (2026), OWASP Top 10 for LLM Applications (2025), RFC 8693 — OAuth 2.0 Token Exchange.
Cet article vous a été utile ? Partagez-le.
Aller plus loin
Un sujet, une mission, une question ?
Distribuée accompagne des PME exigeantes sur la sécurité cloud, la supply chain CI/CD et la sécurité IA.
Réserver 15 min