Quand AWS a lancé Bedrock AgentCore, le modèle de runtime est devenu « déployez votre agent dans un compte, invoquez-le depuis n’importe où ». En pratique, ce « n’importe où » cache une chorégraphie IAM loin d’être triviale. Je viens de dérouler les deux patterns supportés sur un vrai déploiement d’entreprise, et je veux partager ce que la documentation ne dit pas tout à fait.
Le problème
Vous avez un runtime AgentCore déployé sur le compte A (appelons-le 111111111111, région eu-west-1). L’ARN de l’agent ressemble à :
arn:aws:bedrock-agentcore:eu-west-1:111111111111:runtime/agent-abcdefghij
Vous avez une charge de travail sur le compte B (disons 222222222222) — un hôte EC2 qui exécute un outil interne, une Lambda, ou le poste d’un développeur — qui doit invoquer cet agent. Les deux comptes sont dans la même organisation AWS, mais aucune relation de confiance automatique n’existe entre eux.
Deux patterns sont supportés. Les deux fonctionnent. Ils ne sont pas équivalents.
Pattern 1 — Politique basée sur la ressource (recommandé)
AgentCore supporte des politiques basées sur la ressource, sur le runtime et sur son endpoint. Vous attachez une politique sur le compte A, aucun rôle à créer sur le compte B. Terminé.
Piège critique n°1 — Autorisation hiérarchique
La doc AgentCore le mentionne, mais la plupart des lecteurs passent à côté : pour autoriser bedrock-agentcore:InvokeAgentRuntime, AWS évalue deux politiques de ressource, pas une :
- une sur l’ARN du runtime
- une sur l’ARN de l’endpoint (ex.
…/runtime/agent-abcdefghij/runtime-endpoint/DEFAULT)
Si l’une des deux manque ou ne correspond pas à l’appelant, la requête est refusée.
Vous attachez donc deux politiques, identiques à l’exception du champ Resource :
# Sur le compte A
aws bedrock-agentcore-control put-resource-policy \
--resource-arn arn:aws:bedrock-agentcore:eu-west-1:111111111111:runtime/agent-abcdefghij \
--policy file://runtime-policy.json
aws bedrock-agentcore-control put-resource-policy \
--resource-arn arn:aws:bedrock-agentcore:eu-west-1:111111111111:runtime/agent-abcdefghij/runtime-endpoint/DEFAULT \
--policy file://endpoint-policy.json
Chaque politique :
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowCallerRole",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::222222222222:root",
"arn:aws:iam::222222222222:role/the-caller-role"
]
},
"Action": [
"bedrock-agentcore:InvokeAgentRuntime",
"bedrock-agentcore:InvokeAgentRuntimeForUser",
"bedrock-agentcore:GetAgentCard"
],
"Resource": "arn:aws:bedrock-agentcore:eu-west-1:111111111111:runtime/agent-abcdefghij"
}]
}
Piège critique n°2 — Resource doit être exact
AgentCore rejette les wildcards dans le champ Resource des politiques basées sur la ressource. "Resource": "*" renvoie une erreur de validation. Vous devez indiquer l’ARN exact de la ressource à laquelle la politique est attachée.
Piège critique n°3 — aws:SourceAccount vous refuse silencieusement
Vous serez tenté d’ajouter cette condition de défense en profondeur :
"Condition": {
"StringEquals": { "aws:SourceAccount": "222222222222" }
}
Ne le faites pas. aws:SourceAccount n’est renseigné que lorsqu’un principal de service AWS (Lambda, S3, EventBridge…) appelle pour le compte de quelqu’un. Quand un rôle IAM du compte B appelle en cross-account directement via SigV4, cette clé de contexte n’est pas définie : la condition échoue et l’appel est refusé. Le message d’erreur dit « aucune politique basée sur la ressource n’autorise l’action », ce qui est techniquement vrai (la condition a échoué) mais extrêmement trompeur.
Si vous voulez de la défense en profondeur sur le compte du principal, utilisez plutôt aws:PrincipalAccount.
Piège critique n°4 — Le mensonge du « aucune politique de ressource n’autorise »
Quand AWS renvoie cette erreur dans un scénario cross-account, la politique de ressource est en fait souvent correcte. Le refus peut en réalité venir de la politique d’identité de l’appelant, à laquelle il manque un chemin de ressource précis. C’était notre cas : la politique d’identité du rôle appelant contenait :
"Resource": [
"arn:aws:bedrock-agentcore:eu-west-1:111111111111:runtime/*",
"arn:aws:bedrock-agentcore:*:222222222222:runtime/*/runtime-endpoint/*"
]
Le sous-chemin de l’endpoint était faux : restreint au compte B (l’appelant !) au lieu du compte A. AWS a évalué l’autorisation du runtime ✅, celle de l’endpoint ❌, et a signalé le refus comme si la politique de ressource manquait.
Correctif : les deux ARN doivent pointer vers les ressources du compte A.
"Resource": [
"arn:aws:bedrock-agentcore:eu-west-1:111111111111:runtime/*",
"arn:aws:bedrock-agentcore:eu-west-1:111111111111:runtime/*/runtime-endpoint/*"
]
Pattern 2 — Chaîne sts:AssumeRole
Le pattern cross-account classique : créer sur le compte A un rôle que le rôle du compte B peut assumer.
- Sur le compte A : un rôle avec une trust policy qui autorise
arn:aws:iam::222222222222:role/the-caller-roleà l’assumer, et une politique inline accordantbedrock-agentcore:InvokeAgentRuntime. - Sur le compte B : ajouter
sts:AssumeRoleà la politique d’identité du rôle appelant. - Sur la machine appelante : configurer un profil AWS qui enchaîne :
[profile agent-invoker]
role_arn = arn:aws:iam::111111111111:role/CrossAccountAgentInvoker
credential_source = Ec2InstanceMetadata
region = eu-west-1
Ça fonctionne. Deux rôles à maintenir, en plus de deux politiques d’identité. Le SDK enchaîne de façon transparente l’appel STS avant chaque invoke. CloudTrail montre la session de rôle assumé dans userIdentity.
Lequel choisir ?
| Aspect | Politique de ressource | Assume-role |
|---|---|---|
| Rôles à maintenir | 0 en plus | 2 (un de chaque côté) |
| Config appelant | Chaîne de credentials AWS standard | Profil custom avec chaîne role_arn |
| Latence | Invoke direct | Aller-retour STS supplémentaire (mis en cache) |
| Piste d’audit | Le rôle appelant apparaît directement | ARN de session de rôle assumé |
| Maintenance | Un PutResourcePolicy sur le compte A | Synchroniser 2 politiques dans 2 comptes |
Pour la plupart des cas « le compte B invoque l’agent du compte A », les politiques de ressource l’emportent. Elles sont plus simples, plus faciles à découvrir (la politique est posée sur la ressource qui vous intéresse) et moins coûteuses à maintenir.
Et la Memory (LTM/STM) ?
La Memory AgentCore a sa propre histoire de politiques de ressource. Si votre runtime d’agent écrit des événements dans un store Memory et que vous voulez qu’un principal cross-account récupère des memory records, il vous faut aussi des politiques sur l’ARN de la memory (arn:aws:bedrock-agentcore:…:memory/your-memory-id). Le pattern est identique : des actions comme RetrieveMemoryRecords, CreateEvent, ListEvents sont restreintes à l’ARN de la memory ; les politiques du runtime et de l’endpoint de l’agent n’ont rien à voir. Les permissions Memory sont un plan séparé.
Récapitulatif — les 4 choses à vérifier en premier quand l’invoke cross-account échoue
- Deux politiques de ressource (runtime + endpoint), pas une.
- ARN exact dans
Resource, pas de wildcards. - Pas de condition
aws:SourceAccountsur un appel cross-account par un principal IAM. - La politique d’identité de l’appelant liste l’ARN du runtime et le sous-chemin de l’endpoint, tous deux sur le compte propriétaire de la ressource.
Si vous maîtrisez ces quatre points, AgentCore cross-account se configure en 10 minutes. Ratez-en un seul, et vous passerez une demi-journée à courir après un message d’erreur trompeur.
Vous construisez des agents sur un socle cloud et rencontrez ce genre de friction ? Échangeons.