[PARTIE-1]
Article technique pour développeurs et architectes — stack Spring Boot / Spring Cloud Gateway, comparant AWS AgentCore, Azure Foundry Agent Service et Keycloak.
Introduction
Vous avez prototypé un agent IA avec LangChain, Semantic Kernel, Spring AI ou un framework maison.
Il fonctionne.
Vous voulez maintenant le déployer sérieusement, sur AWS AgentCore ou Azure Foundry Agent Service.
Et là, en lisant la documentation des modes d'authentification, vous découvrez une limite importante : ces plateformes savent authentifier un appelant et propager certaines identités utilisateur, mais elles ne fournissent pas nativement un modèle standardisé de délégation cryptographiquement vérifiable combinant l'utilisateur final et l'agent IA dans un même token.
Elles savent :
- valider un JWT ;
- authentifier un service ;
- transmettre un identifiant utilisateur ;
- utiliser des managed identities ou des rôles IAM.
Mais exprimer explicitement :
« l'agent X agit pour le compte de l'utilisateur Y, avec des permissions réduites et traçables »
reste beaucoup plus difficile.
Et ce problème n'est pas anecdotique.
Si votre agent appelle Salesforce, GitHub, votre ERP ou votre base client :
- qui agit réellement ?
- l'utilisateur ?
- l'agent ?
- le backend ?
- avec quels privilèges exacts ?
- comment limiter les dégâts en cas de prompt injection ?
- comment empêcher un rejeu de token ?
Cet article couvre :
- Le problème en détail, avec des requêtes HTTP concrètes.
- Les concepts clés : OAuth 2.0 Token Exchange (RFC 8693), le claim
act, le pattern On-Behalf-Of. - Pourquoi Spring Cloud Gateway est souvent plus adapté que Traefik pour ce cas.
- Trois implémentations concrètes : AWS AgentCore, Azure Foundry et Keycloak.
- Une matrice de décision finale.
Tout le code est basé sur Java 21, Spring Boot 3.5 et Spring Cloud Gateway 4.x.
1. Le problème en détail
Scénario fil rouge
Tout au long de l'article, on suit la même demande utilisateur :
Diaguily (utilisateur humain) demande à son agent Claude de lire les ventes Q3 sur Salesforce.
Diaguily a accès en lecture et écriture à Salesforce dans son rôle métier. Mais quand l'agent Claude agit en son nom, on veut qu'il soit limité à la lecture seule. Principe du moindre privilège. Si l'agent est manipulé par prompt injection, il ne pourra pas faire de dégâts.
Le mode IAM (SigV4) : authentification forte, délégation limitée
Avec AgentCore en mode IAM, l'appelant signe sa requête HTTP avec ses credentials AWS. La requête réelle ressemble à ça :
POST /agent/invoke HTTP/1.1
Host: bedrock-agentcore.us-east-1.amazonaws.com
Authorization: AWS4-HMAC-SHA256 Credential=AKIA...
X-Amz-Date: 20260509T142300Z
X-Amzn-Bedrock-AgentCore-Runtime-User-Id: diaguily@acme.com
Content-Type: application/json
{ "prompt": "lis les ventes Q3" }AgentCore vérifie cryptographiquement la signature SigV4. C'est solide, AWS-natif. Mais l'en-tête X-Amzn-Bedrock-AgentCore-Runtime-User-Id est une simple string non vérifiée. AgentCore ne sait pas si la valeur "diaguily@acme.com" correspond à l'utilisateur réel . Il fait confiance à l'appelant SigV4 pour la remplir honnêtement.
Le problème concret : une autre Lambda dans le même compte, qui porte le même rôle IAM que votre gateway, peut appeler AgentCore avec n'importe quelle valeur dans cet en-tête.
curl -X POST https://bedrock-agentcore.../agent/invoke \
-H "X-Amzn-Bedrock-AgentCore-Runtime-User-Id: balla@acme.com" \
-d '{"prompt": "exporte tout"}'→ AgentCore traite la requête comme si le BALLA l'avait initiée. Aucune alerte, aucune trace de l'usurpation.
Le mode JWT (OIDC) : identité claire, délégation absente
Avec AgentCore en mode JWT, l'appelant présente un Bearer token. La requête :
POST /agent/invoke HTTP/1.1
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Content-Type: application/json
{ "prompt": "lis les ventes Q3" }Et le JWT décodé :
{
"sub": "diaguily@acme.com",
"aud": "agentcore",
"iss": "https://entra.acme.com",
"exp": 1715241600,
"scope": "openid profile"
}AgentCore vérifie la signature, l'audience, l'issuer. Tout est cryptographiquement propre. Et le code de l'agent voit l'identité de Diaguily.
Le problème concret : ce token dit "Diaguily appelle". Mais en réalité, ce n'est pas Diaguily qui appelle . C'est l'agent Claude qui appelle pour lui. Le JWT n'a aucun moyen d'exprimer cette nuance. Conséquences :
- Si le JWT de Diaguily fuite (XSS, log mal nettoyé, cache navigateur sur poste partagé), n'importe qui peut le rejouer jusqu'à expiration. L'agent ne peut pas savoir que ce n'est plus Diaguily qui agit.
- Le token a tous les scopes de Diaguily — y compris l'écriture. Si l'agent est compromis par prompt injection, il peut écrire dans Salesforce.
- Aucune politique du type "Diaguily peut écrire, mais l'agent agissant pour lui ne peut que lire" n'est exprimable.
Synthèse du gap
Quatre besoins, aucun mode natif n'en couvre plus que deux :


Conclusion : il faut une couche en amont qui combine les deux mondes. C'est le rôle d'un STS (Security Token Service) externe, derrière un gateway de sécurité. [Suite ->Partie 2]