When AWS launched Bedrock AgentCore, the runtime model became “deploy your agent in one account, invoke it from anywhere.” In practice, “from anywhere” hides a non-trivial IAM dance. I just walked through both supported patterns on a real enterprise deployment and want to share what the docs don’t quite spell out.

The problem

You have an AgentCore Runtime deployed on Account A (call it 111111111111, region eu-west-1). The agent ARN looks like:

arn:aws:bedrock-agentcore:eu-west-1:111111111111:runtime/agent-abcdefghij

You have a workload on Account B (say 222222222222) — an EC2 host running an internal tool, a Lambda, or a developer laptop — that needs to invoke this agent. Both accounts are in the same AWS Organization but no auto-trust exists between them.

Two patterns are supported. Both work. They are not equivalent.

AgentCore supports resource-based policies on the runtime and on its endpoint. Attach a policy on Account A, no role to create on Account B. Done.

Critical gotcha #1 — Hierarchical authorization

The AgentCore doc states it but most readers miss it: when authorizing bedrock-agentcore:InvokeAgentRuntime, AWS evaluates two resource policies, not one:

  • one on the runtime ARN
  • one on the endpoint ARN (e.g. …/runtime/agent-abcdefghij/runtime-endpoint/DEFAULT)

If either is missing or doesn’t match the caller, the request is denied.

So you attach two policies, identical except for the Resource field:

# On Account 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

Each policy:

{
  "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"
  }]
}

Critical gotcha #2 — Resource must be exact

AgentCore rejects wildcards in the Resource field of resource-based policies. "Resource": "*" returns a validation error. You must specify the exact ARN of the resource the policy is attached to.

Critical gotcha #3 — aws:SourceAccount is silently denying you

You’ll be tempted to add this defense-in-depth condition:

"Condition": {
  "StringEquals": { "aws:SourceAccount": "222222222222" }
}

Don’t. aws:SourceAccount is populated only when an AWS service principal (Lambda, S3, EventBridge…) calls on behalf of someone. When an IAM role from Account B calls cross-account directly via SigV4, this context key is not set, so the condition fails and the call is denied. The error message says “no resource-based policy allows the action,” which is technically true (the condition failed) but extremely misleading.

If you want defense-in-depth on the principal account, use aws:PrincipalAccount instead.

Critical gotcha #4 — The “no resource-based policy allows” lie

When AWS returns this error in a cross-account scenario, the resource policy is in fact often correct. The deny may actually originate from the caller’s identity policy missing a specific resource path. This was our case: the identity policy on the caller role had:

"Resource": [
  "arn:aws:bedrock-agentcore:eu-west-1:111111111111:runtime/*",
  "arn:aws:bedrock-agentcore:*:222222222222:runtime/*/runtime-endpoint/*"
]

The endpoint sub-path was wrong: scoped to Account B (the caller!) instead of Account A. AWS evaluated the runtime allow ✅, the endpoint allow ❌, and reported the deny as if the resource policy were missing.

Fix: both ARNs must point to Account A’s resources.

"Resource": [
  "arn:aws:bedrock-agentcore:eu-west-1:111111111111:runtime/*",
  "arn:aws:bedrock-agentcore:eu-west-1:111111111111:runtime/*/runtime-endpoint/*"
]

Pattern 2 — sts:AssumeRole chain

The classic cross-account pattern: create a role on Account A that Account B’s role can assume.

  • On Account A: a role with a trust policy that lets arn:aws:iam::222222222222:role/the-caller-role assume it, and an inline policy granting bedrock-agentcore:InvokeAgentRuntime.
  • On Account B: add sts:AssumeRole to the caller role’s identity policy.
  • On the caller machine: configure an AWS profile that chains:
[profile agent-invoker]
role_arn = arn:aws:iam::111111111111:role/CrossAccountAgentInvoker
credential_source = Ec2InstanceMetadata
region = eu-west-1

Works fine. Two roles to maintain on top of two identity policies. The SDK transparently chains the STS call before each invoke. CloudTrail shows the assumed-role session in userIdentity.

Which one should you pick?

AspectResource policyAssume-role
Roles to maintain0 extra2 (one each side)
Caller configStandard AWS credential chainCustom profile with role_arn chain
LatencyDirect invokeExtra STS round-trip (cached)
Audit trailCaller’s role appears directlyAssumed-role session ARN
MaintenanceOne PutResourcePolicy on Account ASync 2 policies in 2 accounts

For most “Account B invokes agent on Account A” use cases, resource policies win. They are simpler, more discoverable (the policy is on the resource you care about), and cheaper to maintain.

And about Memory (LTM/STM)?

AgentCore Memory has its own resource-policy story. If your agent runtime writes events to a Memory store and you want a cross-account principal to retrieve memory records, you need policies on the memory ARN too (arn:aws:bedrock-agentcore:…:memory/your-memory-id). The pattern is identical: actions like RetrieveMemoryRecords, CreateEvent, ListEvents are scoped to the memory ARN, both runtime and endpoint policies of the agent are unrelated. Memory permissions are a separate plane.

Recap — the 4 things to check first when your cross-account agent invoke fails

  1. Two resource policies (runtime + endpoint), not one.
  2. Exact ARN in Resource, no wildcards.
  3. No aws:SourceAccount condition on an IAM-principal cross-account call.
  4. Caller identity policy lists the runtime ARN and the endpoint sub-path, both on the resource owner’s account.

If you nail these four, cross-account AgentCore is a 10-minute setup. Miss any one, and you’ll spend a half-day chasing a misleading error message.

Building agents on a cloud foundation and hitting this kind of friction? Let’s compare notes.