If you build agents on AWS in a regulated industry, your security team has likely imposed an IAM permissions boundary on every role you create. Mine calls it BoundaryForLPMA — yours might be called something else. The principle is the same: even with admin credentials, you cannot escape what the boundary allows.
Bedrock AgentCore is a beautiful service in a clean account. In a boundary-constrained enterprise account, it is a sequence of IAM puzzles that the documentation does not connect for you. After deploying AgentCore Runtime, Memory, Gateway, Evaluations, Registry and cross-account access under an LPMA boundary, here are the patterns I would have wanted to read before starting.
Pattern 1 — Role naming is your gatekeeper
Most boundary-constrained roles delegate role creation to your team only when the role name starts with a specific prefix. In my world it’s LPMA_*. If you try to call iam:CreateRole for a role named CrossAccount-BedrockAgent-FromProd, you get an AccessDenied that does not mention the naming rule. The boundary on your IAM creator role limits iam:CreateRole by Resource: arn:aws:iam::*:role/LPMA_* and you don’t see the condition.
Convention I now use systematically:
- Runtime execution role:
LPMA_<App>_AgentCoreRuntime - Dispatcher Lambda role:
LPMA_<App>_AlertDispatcher - Evaluations execution role:
LPMA_<App>_EvaluationExecution - Cross-account invoker (new role, not a reused one):
LPMA_<App>_CrossAccount<Purpose>
Pick a project tag (<App>) and stick to it across all roles, queues, secrets, runtimes.
Pattern 2 — iam:PassRole to the AgentCore service principal is usually blocked
The boundary policy on a typical enterprise role allows iam:PassRole only to a hand-picked list of service principals: ec2.amazonaws.com, lambda.amazonaws.com, ecs-tasks.amazonaws.com, etc. The AgentCore service principal bedrock-agentcore.amazonaws.com is rarely on that list.
The practical consequence: automated CD that creates the runtime via your CI cannot pass the execution role. You have to either:
- Have someone with elevated, non-boundary rights pass the role one time, then the runtime exists and CI just runs
UpdateAgentRuntimeon it (which doesn’t need PassRole). - Or ask security to add
bedrock-agentcore.amazonaws.comto the boundary’s PassRole whitelist.
I went with option 1. CI never creates a runtime from scratch — it always rolls an existing runtime to a new image. The runtime itself is provisioned via a one-shot elevated-role script.
Pattern 3 — Runtime recreation is a two-place update
If you ever delete and recreate a runtime (e.g., to migrate from direct_code_deploy to a container artifact), the runtime ID changes. Two places need to be updated together:
- The Lambda environment variable (or wherever the consuming code stores the ARN) — easy, easy to remember.
- The IAM policy of the role that invokes the runtime, where the runtime ARN is scoped in
Resource. This one is easy to forget, and the symptom isAccessDeniedon a perfectly running runtime, hours after you thought you were done.
I lost an hour to this. Now I treat runtime recreation as a triple action: env vars + IAM policy + smoke test.
Pattern 4 — KMS key policy must explicitly allow each service that uses it
Regulated-account environments often require a project-scoped KMS CMK on Secrets Manager, SNS topics, SQS queues, CloudWatch logs, S3 buckets. The CMK key policy has to allow each service principal to use the key, scoped to your project.
A pattern that works well for an <app>-* resource family:
{
"Sid": "AllowSNSUsage",
"Effect": "Allow",
"Principal": { "Service": "sns.amazonaws.com" },
"Action": ["kms:GenerateDataKey", "kms:Decrypt", "kms:DescribeKey"],
"Resource": "*",
"Condition": {
"StringEquals": { "aws:SourceAccount": "<your-account-id>" },
"ArnLike": { "aws:SourceArn": "arn:aws:sns:<region>:<acct>:<app>-*" }
}
}
Add one statement per AWS service you want the CMK to encrypt for. The aws:SourceArn scope is your safety net against confused deputy. Without these statements, the create-SNS-topic call succeeds, but every subsequent Publish fails with a KMS access error.
Pattern 5 — Resource-based policy on the runtime is the cleanest cross-account pattern
I won’t repeat my other post but: when the caller is in another account, the resource-based policy on the runtime and its endpoint lets you avoid creating an intermediate role in the resource owner’s account. put-resource-policy is a bedrock-agentcore-control action, not an IAM action — so even under a boundary that blocks iam:CreateRole outside the LPMA_* namespace, you can attach a resource policy without negotiating with security.
That said, the resource ARN in the resource policy must be exact. No wildcards. AgentCore validates and rejects.
Pattern 6 — AgentCore Memory data plane permissions live in a separate policy
Identity policy on the runtime execution role typically grants control-plane actions like bedrock-agentcore:CreateAgentRuntime. The data-plane actions on Memory (bedrock-agentcore:CreateEvent, RetrieveMemoryRecords, ListEvents, etc.) are a separate matter. You scope them on the memory ARN of your store:
{
"Sid": "AgentCoreMemoryEvents",
"Effect": "Allow",
"Action": [
"bedrock-agentcore:CreateEvent",
"bedrock-agentcore:GetEvent",
"bedrock-agentcore:ListEvents",
"bedrock-agentcore:RetrieveMemoryRecords",
"bedrock-agentcore:BatchCreateMemoryRecords",
"bedrock-agentcore:BatchUpdateMemoryRecords",
"bedrock-agentcore:BatchDeleteMemoryRecords"
],
"Resource": "arn:aws:bedrock-agentcore:<region>:<acct>:memory/<memory-id>"
}
If you forget this, your agent runs fine but every LTM commit fails silently with a Parameter validation failed: AccessDenied that the SDK truncates. The agent appears to work, the memory store stays empty, and you only notice when you try to query it weeks later.
Pattern 7 — The Evaluations execution role has its own trust pattern
If you turn on AgentCore Evaluations (the LLM-as-judge quality scoring), the service needs a role to assume to read your traces, invoke judge models, and write results. The trust policy is:
{
"Effect": "Allow",
"Principal": { "Service": "bedrock-agentcore.amazonaws.com" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "<your-acct>",
"aws:ResourceAccount": "<your-acct>"
},
"ArnLike": {
"aws:SourceArn": [
"arn:aws:bedrock-agentcore:<region>:<acct>:evaluator/*",
"arn:aws:bedrock-agentcore:<region>:<acct>:online-evaluation-config/*"
]
}
}
}
This role names the AgentCore service as principal, scoped to evaluator/online-eval-config resources in your account. Under a boundary that limits iam:CreateRole, you still need this — and yes, the role name needs the boundary-compliant prefix.
Pattern 8 — SNS encryption is non-negotiable
If you create an SNS topic without KmsMasterKeyId, your security scanner (Prisma Cloud in our case) flags it HIGH within an hour. Always attach KMS encryption at create time, not after. The pattern I now use programmatically:
sns.create_topic(Name=name, Attributes={
"KmsMasterKeyId": "<your-project-cmk-id>",
})
Plus the AllowSNSUsage statement on the CMK key policy (pattern 4).
The five tags you cannot forget
Every resource gets these five tags or it gets retroactively flagged:
ApplicationId— your registered application UUID in the enterprise asset registryEnvironment—preprod/prodProject— short project identifierServiceLine— your business unitManagedBy— usually your CI/CD or platform team identifier
If you forget tags on one IAM role, the security scanner will tell you. If you forget tags on the Bedrock AgentCore runtime, it might take longer to notice — and a missing tag on a critical resource has caused programs to be paused for review.
Two service-level details
- VPC mode is mandatory for any MCP that needs to reach on-prem systems via the corporate TGW. The runtime can also be
PUBLIC, depending on whether it talks to public AWS APIs only or to on-prem. requireServiceS3Endpointcannot be set at agent creation time. It is configured at the org level. The boto3 API will reject the parameter with a ValidationException. Just leave it out of your CreateAgentRuntime call.
The mental model that ties it all together
Permissions boundaries are not your enemy. They are a forcing function that makes you express, in code, the privilege envelope of your application. The cost is real — a quarter to a half day of extra work the first time you deploy AgentCore — but the dividend is a deployment whose audit posture you can defend in front of a security committee without rewriting anything.
The eight patterns above cover ~90 % of the boundary-related friction I hit. The remaining 10 % was negotiation with security to add bedrock-agentcore.amazonaws.com to the PassRole whitelist for CI/CD automation. Worth pushing for.
If you’re starting an AgentCore deployment in a boundary-constrained account, save yourself the chase: name your roles LPMA_<App>_*, attach KMS at create time on everything, scope Memory data-plane actions on the memory ARN, and treat resource policies as your preferred cross-account pattern. Let’s talk.