Connect your AWS Bedrock environment to Capsule Security for complete visibility into your AI agents, flows, knowledge bases, guardrails, and runtime activity.
This integration uses an IAM role to sync into your Bedrock resources and capture runtime telemetry:
| Category | What Gets Captured |
|---|---|
| Agents | Bedrock Agents and AgentCore agents with configuration and metadata |
| Action Groups | Lambda functions and OpenAPI schemas attached to agents |
| Knowledge Bases | Vector stores, data sources, and chunking configurations |
| Guardrails | Content filters, denied topics, and PII handling policies |
| Flows | Prompt flows with node configurations and connections |
| Runtime Activity | Agent invocations, traces, tool calls, and session history |
To block tool calls, model requests, and agent invocations at runtime, add AgentCore Gateway Prevention after the integration is connected.
Before you begin, ensure you have:
- An AWS account with Bedrock Agents or AgentCore deployed
- IAM permissions to deploy CloudFormation stacks (or
AdministratorAccess) - CloudTrail enabled in your account (for runtime activity capture)
- Access to the Capsule Security portal
Deploy the Capsule IAM role using the provided CloudFormation template.
- Log in to the Capsule Security portal
- Click Integrations in the left sidebar
- Find the AWS Bedrock card and click Set up Integration
- Click Open CloudFormation

- You'll be redirected to the AWS CloudFormation console
- Review the stack details:
- Stack name:
CapsuleSecurityBedrockIntegration(or customize) - Capabilities: Acknowledge IAM resource creation
- Stack name:
- Click Create stack
| Resource | Purpose |
|---|---|
| IAM Role | Cross-account role assumed by Capsule for read-only access |
| IAM Policy | Permissions scoped to Bedrock, CloudTrail, and CloudWatch |
| Trust Policy | Restricts assumption to Capsule's AWS account with external ID |
Once the stack completes, retrieve the IAM role ARN from the Outputs tab.
- Wait for the stack status to show CREATE_COMPLETE
- Click the Outputs tab
- Copy the value for RoleArn

Provide the Role ARN to Capsule to establish the connection.
- Return to the Capsule Security portal
- Paste the Role ARN into the input field
- Click Save
- Capsule validates the role and its ability to communite with your AWS Account
- First sync may take several minutes
- View synced agents in Inventory → Agents
- View runtime activity in Observability
| Entity Type | Category | Description |
|---|---|---|
| Agents | Model Agent | Agent configuration, foundation model, instructions |
| Agent Aliases | Version | Deployed versions and routing configuration |
| Action Groups | Tool | Lambda functions and API schemas |
| Knowledge Bases | Data Source | Vector stores with embedding models and data sources |
| Guardrails | Guardrail | Content filters, word blocklists, PII policies |
| Flows | Flow | Prompt flow definitions with node graphs |
| Prompts | Prompt | Managed prompts with versions |
| Entity Type | Category | Description |
|---|---|---|
| AgentCore Runtimes | Model Agent | Agent runtime configurations |
| Tools | Tool | Registered tools and function definitions |
| Memory | Memory | Session and long-term memory configurations |
| Identity | Identity | Workload identity configurations |
When CloudTrail and model invocation logging are enabled:
- Agent invocations - Input prompts and final responses
- Tool invocations - Action group calls with inputs and outputs
- Session history - Multi-turn conversation threads
For full runtime visibility, ensure model invocation logging is enabled.
- Open the Amazon Bedrock console
- Navigate to Settings → Model invocation logging
- Enable logging and configure your destination (S3 or CloudWatch)
- For AgentCore, ensure OpenTelemetry export is configured
To update the CloudFormation Stack, following these steps:
- Head over to CloudFormation / Stacks in your AWS Account
- Select our integration stack (named
CapsuleSecurityBedrockIntegrationby default) - Click Update stack → Create a change set
- Select Standard change set → Replace existing template
- Provide the CloudFormation Template URL (default:
https://capsule-security-us-east-1-public-demo.s3.us-east-1.amazonaws.com/cf-capsule-security-bedrock-integration.yaml) - Click upcoming Nexts, review the terms and agree to them
- This will create a ChangeSet, review the changes and click Execute change set
Block tool calls, model requests, and agent invocations that violate your prevention policies before they reach their target. An AgentCore gateway fronts MCP tools, model providers (inference targets), and agents or HTTP services (AgentCore Runtime and passthrough targets). A second CloudFormation stack registers a Capsule interceptor Lambda on the gateway. Before the gateway forwards a request, the interceptor asks Capsule for a decision:
Agent ──► AgentCore gateway ──► Capsule interceptor (Lambda)
MCP tools/call │
model request (/inference) │ tool call, prompt, or agent input, plus the caller
agent invocation (/<target>) ▼
Capsule ── allow ──► gateway forwards the request to the target
└─ deny ──► gateway answers the caller without calling the target- Only a Capsule deny blocks. If Capsule is unreachable, slow, or answers with an error, the request goes through as if the stack were not installed
- Capsule identifies the calling AgentCore Runtime by its execution role (gateways with
AWS_IAMinbound auth) or by the caller token'ssuband client ID (gateways withCUSTOM_JWTinbound auth). Requests from a runtime Capsule has not discovered yet go through unevaluated - Bedrock Agents (non-AgentCore) and model or agent calls that never pass through an AgentCore gateway are not covered. See Routing model and agent traffic through the gateway
| Target type | Evaluated before the target is called | Passes through untouched |
|---|---|---|
| MCP targets (Lambda, OpenAPI, Smithy, MCP server) | tools/call: tool name and arguments | initialize, tools/list, other MCP methods |
| Inference targets | The prompt in /inference/v1/chat/completions, /inference/v1/responses, /inference/v1/messages, /inference/model/<model>/invoke, and /inference/model/<model>/invoke-with-response-stream requests, streaming or not | GET /inference/v1/models |
| AgentCore Runtime targets | The payload of POST /<target>/invocations | Other requests |
Passthrough targets (MCP, A2A, INFERENCE) | MCP tools/call, A2A message/send and message/stream, and inference requests in the formats above | Other requests |
Passthrough targets (CUSTOM) | Nothing | Every request |
Capsule checks requests only. Tool results, model output, and agent responses are not evaluated, so response streaming works as it does without the stack.
Deploy one stack per gateway, in the gateway's region. A stack stays bound to the gateway it was created for. AgentCore Runtime and passthrough targets can only be added to gateways created without the MCP protocol type, so they usually sit on a different gateway from your MCP targets and need a stack of their own.
| Resource | Purpose |
|---|---|
| Secrets Manager secret | Holds the Capsule token. The token never appears in Lambda configuration or stack events |
| Interceptor Lambda | capsule-agentcore-interceptor-<suffix>. Called by the gateway on every request; sends the requests above to Capsule |
| Interceptor IAM role | Writes its own logs and reads the token secret, nothing else |
| Lambda permission | Lets the gateway's service role invoke the interceptor |
| Registration Lambda | capsule-agentcore-register-<suffix>. Runs on stack create, update, and delete to add or remove the interceptor on the gateway |
| Registration IAM role | GetGateway and UpdateGateway on this gateway only, and iam:PassRole on the gateway's existing service role |
<suffix> is the first 8 characters of the stack ID, so stacks for several gateways coexist in one account. The registration role needs iam:PassRole because UpdateGateway replaces the whole gateway definition; the stack passes back the role the gateway already has and never changes it.
- Connect the AWS account with the integration stack above, and wait until the AgentCore Runtimes that call the gateway appear in Capsule. The two stacks can be deployed in either order, but enforcement starts once the runtime is in Capsule
- Create at least one policy in Prevention mode. Without one, every request is allowed
- Note the gateway's ID (for example
acme-tools-abcdef1234, not the ARN), name, and service role ARN from AgentCore console → Gateways → your gateway - Confirm the gateway has no other REQUEST interceptor. AWS allows one per gateway, and the stack never replaces an existing one
- Make sure the gateway's service role allows
lambda:InvokeFunctionon the interceptor (see below) - Route the model and agent traffic you want covered through the gateway (see below)
Capsule sees only requests that reach the gateway. Point model clients at the gateway's /inference path:
| Client | Setting |
|---|---|
| OpenAI SDK | base_url="https://<gateway-id>.gateway.bedrock-agentcore.<region>.amazonaws.com/inference/v1" |
| Anthropic SDK | base_url="https://<gateway-id>.gateway.bedrock-agentcore.<region>.amazonaws.com/inference" |
AWS SDK bedrock-runtime (InvokeModel) | AWS_ENDPOINT_URL_BEDROCK_RUNTIME=https://<gateway-id>.gateway.bedrock-agentcore.<region>.amazonaws.com/inference |
From the Bedrock Runtime API, inference targets serve InvokeModel and InvokeModelWithResponseStream. Agents that call Converse or ConverseStream need to switch to one of the clients above. For common agent frameworks:
| Framework | Model class | Through the gateway |
|---|---|---|
| Strands Agents | BedrockModel (default) | Not supported, it calls ConverseStream. Use AnthropicModel or OpenAIModel |
| Strands Agents | AnthropicModel, OpenAIModel | Set base_url in client_args |
| LangChain / LangGraph | ChatBedrockConverse | Not supported, it calls Converse. Use ChatBedrock or ChatAnthropic |
| LangChain / LangGraph | ChatBedrock | Set endpoint_url |
| LangChain / LangGraph | ChatAnthropic, ChatOpenAI | Set base_url |
| LiteLLM, CrewAI | OpenAI or Anthropic provider | Set base_url (CrewAI passes it to LiteLLM) |
| OpenAI Agents SDK | OpenAIResponsesModel (default) | Set base_url. Needs a target that serves the OpenAI Responses API |
Claude models on Bedrock stay reachable from Anthropic and OpenAI clients: the gateway translates those requests to InvokeModel for a Bedrock Runtime target. On a gateway with CUSTOM_JWT inbound auth, pass the caller's token as the SDK's API key. On a gateway with AWS_IAM inbound auth, requests must be SigV4-signed for the bedrock-agentcore service, so add a signing hook to the OpenAI or Anthropic SDK's HTTP client.
Invoke agents behind AgentCore Runtime targets at https://<gateway-id>.gateway.bedrock-agentcore.<region>.amazonaws.com/<target-name>/invocations, and passthrough targets at /<target-name>/<path> on the same host. Callers of an AWS_IAM gateway need bedrock-agentcore:InvokeGateway on it.
To keep agents from bypassing the gateway, let inference targets hold the provider credentials (GATEWAY_IAM_ROLE for Bedrock, an API key in the AgentCore token vault for OpenAI and Anthropic) and remove direct model access from the agents' roles. For AgentCore Runtime targets, restrict the runtime to gateway traffic.
The gateway invokes the interceptor with its own service role. The stack grants the Lambda side, but cannot edit your role. If the role does not already allow it, add:
{
"Effect": "Allow",
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:capsule-agentcore-interceptor-*"
}Replace us-east-1 with the gateway's region and 123456789012 with your account ID. The prefix is needed only because the function name is not known before the stack exists. After CREATE_COMPLETE, replace it with the exact InterceptorFunctionArn stack output.
The IAM user or role deploying the stack needs:
cloudformation:CreateStack, cloudformation:UpdateStack, cloudformation:DeleteStack, cloudformation:DescribeStacks,
cloudformation:CreateChangeSet, cloudformation:DescribeChangeSet, cloudformation:ExecuteChangeSet,
iam:CreateRole, iam:GetRole, iam:PutRolePolicy, iam:DeleteRolePolicy, iam:DeleteRole, iam:PassRole,
lambda:CreateFunction, lambda:UpdateFunctionConfiguration, lambda:UpdateFunctionCode, lambda:DeleteFunction,
lambda:AddPermission, lambda:RemovePermission, lambda:InvokeFunction, lambda:TagResource, lambda:GetFunction,
secretsmanager:CreateSecret, secretsmanager:UpdateSecret, secretsmanager:DeleteSecret, secretsmanager:TagResource- In Capsule, open Integrations, select your AWS Bedrock integration, and find AgentCore gateway prevention. It lists the gateways Capsule reads from your AWS account. The list can be up to five minutes old
- Click Set up on the gateway
- Click Create token and copy the token. Capsule does not store it and shows it only once. One token serves every gateway in the same AWS account and region. Treat it as a secret: never put it in a URL, a ticket, or shell history
- Click Open CloudFormation. The quick-create page opens in the gateway's region with
GatewayIdentifier,GatewayName,GatewayRoleArn, andCapsuleEndpointfilled in. The token is never part of the link
The dialog shows the endpoint the link fills in. Check that it matches your Capsule portal, and use it for the CLI:
| Capsule portal URL | Endpoint |
|---|---|
https://portal.us-east1.capsulesecurity.io | https://agentsecurity.us-east1.capsulesecurity.io/v1/aws-bedrock-agentcore/hooks/events/pre |
https://portal.us-west4.capsulesecurity.io | https://agentsecurity.us-west4.capsulesecurity.io/v1/aws-bedrock-agentcore/hooks/events/pre |
https://portal.eu-west4.capsulesecurity.io | https://agentsecurity.eu-west4.capsulesecurity.io/v1/aws-bedrock-agentcore/hooks/events/pre |
The interceptor sends the token and every evaluated request (tool arguments, prompts, agent input) to this URL, so the template accepts only Capsule-operated hosts.
The template is published at:
https://capsule-security-us-east-1-public-demo.s3.us-east-1.amazonaws.com/cf-capsule-bedrock-prevention/versions/latest.yamlThe Open CloudFormation link from Step 1 opens a quick-create page with every parameter except CapsuleToken filled in. Paste the token, check I acknowledge that AWS CloudFormation might create IAM resources, and click Create stack. Without the link:
- Open CloudFormation in the gateway's region
- Click Create stack → With new resources (standard)
- Select Amazon S3 URL, paste the template URL above, and click Next
- Name the stack, for example
CapsuleAgentCorePrevention-abcdef1234(the last 10 characters of the gateway ID) - Fill in the parameters (see the table below)
- Click Next through the remaining pages, check I acknowledge that AWS CloudFormation might create IAM resources, and click Submit
Download latest.yaml from the URL above, then:
aws cloudformation deploy \
--stack-name CapsuleAgentCorePrevention-abcdef1234 \
--template-file latest.yaml \
--capabilities CAPABILITY_IAM \
--region us-east-1 \
--parameter-overrides \
GatewayIdentifier=acme-tools-abcdef1234 \
GatewayName=acme-tools \
GatewayRoleArn=arn:aws:iam::123456789012:role/AcmeAgentCoreGatewayRole \
CapsuleEndpoint=https://agentsecurity.us-east1.capsulesecurity.io/v1/aws-bedrock-agentcore/hooks/events/pre \
CapsuleToken="$CAPSULE_TOKEN"Pass the token from an environment variable or a secrets tool.
| Parameter | Value | Notes |
|---|---|---|
GatewayIdentifier | Gateway ID, e.g. acme-tools-abcdef1234 | Not the ARN. Fixed for the life of the stack; create another stack for another gateway |
GatewayName | Gateway name, e.g. acme-tools | Capsule policies match it as the MCP server name. The stack fails if it does not match the gateway |
GatewayRoleArn | The gateway's service role ARN | AgentCore console → Gateways → your gateway → Service role |
CapsuleEndpoint | Endpoint from Step 1 | Only agentsecurity.<region>.capsulesecurity.io hosts are accepted |
CapsuleToken | Token from Step 1 | Stored in Secrets Manager, never echoed |
Stack creation takes 1-3 minutes, most of it waiting for the gateway to return to READY after the interceptor is attached. Wait for CREATE_COMPLETE.
If the stack fails because the gateway already has a REQUEST interceptor, nothing was changed. Delete the failed stack, remove the other interceptor from the gateway or pick another gateway, and deploy again. If it fails with GatewayName does not match the gateway's name, delete the failed stack and deploy again with the name shown in the message.
- In Capsule, click Verify on the gateway. Capsule reads the gateway from AWS through the integration's role and shows its state:
| State | Meaning |
|---|---|
| Installed | The Capsule interceptor is on the gateway and receives request headers |
| Needs update | The Capsule interceptor is on the gateway without passRequestHeaders, so Capsule cannot identify the calling runtime. Update the stack from the latest template |
| Conflict | Another REQUEST interceptor is on the gateway. The dialog shows its ARN |
| Not installed | No Capsule interceptor on the gateway. Check that the stack reached CREATE_COMPLETE |
The gateway list can be up to five minutes old. Verify reads the gateway's current state from AWS.
- Send a tool call, model request, or agent invocation through the gateway. The log group
/aws/lambda/capsule-agentcore-interceptor-<suffix>shows one invocation per request, and the request appears in Capsule Observability under the runtime that made it.
The target is not called. On MCP targets and MCP passthrough targets, the gateway returns the deny to the agent as a normal MCP tool result with isError: true, and the agent can act on the reason like any other tool error:
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"isError": true,
"content": [
{
"type": "text",
"text": "Capsule Policy Enforcement -\nblock-acme-exfiltration - Sensitive data sent to an external tool"
}
]
}
}On inference, AgentCore Runtime, and A2A targets, the gateway returns 403 with the same reason in the caller's API error format. Model SDKs raise their usual permission error (PermissionDeniedError in the OpenAI and Anthropic SDKs, AccessDeniedException in the AWS SDK) and do not retry it. A streaming request gets the error before any event is sent. For example, an Anthropic SDK client receives:
{
"type": "error",
"error": {
"type": "permission_error",
"message": "Capsule Policy Enforcement -\nblock-acme-exfiltration - Sensitive data sent to an external model"
}
}Capsule shows a blocked request in the same session as the agent's conversation when the calling runtime has AgentCore observability (ADOT) enabled and CloudWatch Transaction Search is on in the account. The runtime then carries its session ID on gateway calls, as long as the agent serves invocations through an ADOT-instrumented server (the AgentCore SDK app, Starlette, or FastAPI) and calls the gateway through an MCP client or httpx (which the OpenAI and Anthropic Python SDKs use) while handling the invocation. Calls made with requests or urllib3 need opentelemetry.propagate.inject(headers), because ADOT leaves those libraries uninstrumented for agents.
Without this, prevention works the same and the blocked request appears in a session of its own.
- Every evaluated request adds one HTTPS round trip from the gateway's region to Capsule plus Capsule's evaluation time, typically a few seconds. A Lambda cold start adds a few hundred milliseconds. For streaming model requests this delays the first token, not the stream
- The interceptor waits at most 25 seconds for Capsule, then lets the request through. Set your MCP, model, and agent client timeouts above 25 seconds so a slow evaluation passes the request through instead of timing out the caller
- The token is cached in the Lambda for 5 minutes. A
401or403from Capsule drops the cached token so the next call re-reads the secret - The interceptor lets the request through instead of failing when Capsule gives no usable answer, so a slow or unreachable Capsule never causes a gateway retry. AWS can still retry an interceptor invocation, and Capsule evaluates every invocation it receives, so a retried request can be evaluated more than once
Capsule publishes new versions at the same latest.yaml URL. Updating is safe while agents are running: the interceptor keeps its function ARN, and new requests run the new code as soon as the update applies. Every update also re-attaches the interceptor if someone removed it from the gateway.
Stacks on template version 1.0 evaluate MCP tool calls only. Update to 1.1 or later to evaluate inference, AgentCore Runtime, and passthrough targets.
Console: CloudFormation → your stack → Update stack → Replace existing template, set Amazon S3 URL to the latest.yaml URL, keep every parameter as it is (CapsuleToken shows as Use existing value), check the IAM acknowledgement, and submit.
CLI:
aws cloudformation update-stack \
--stack-name CapsuleAgentCorePrevention-abcdef1234 \
--template-url https://capsule-security-us-east-1-public-demo.s3.us-east-1.amazonaws.com/cf-capsule-bedrock-prevention/versions/latest.yaml \
--capabilities CAPABILITY_IAM \
--region us-east-1 \
--parameters \
ParameterKey=GatewayIdentifier,UsePreviousValue=true \
ParameterKey=GatewayName,UsePreviousValue=true \
ParameterKey=GatewayRoleArn,UsePreviousValue=true \
ParameterKey=CapsuleEndpoint,UsePreviousValue=true \
ParameterKey=CapsuleToken,UsePreviousValue=trueThe TemplateVersion stack output shows the version you run.
In Capsule, click Verify on the gateway, then Create token under Rotate the token. Update the stack with the new CapsuleToken value and every other parameter unchanged (console: Update stack → Use current template). The interceptor picks up the new value within 5 minutes. Earlier tokens stay valid, so the stack keeps working until you update it. If a token leaks, contact Capsule support.
Delete the stack. The registration Lambda removes the Capsule interceptor from the gateway before the Lambda functions are deleted, so the gateway keeps working without it.
aws cloudformation delete-stack --stack-name CapsuleAgentCorePrevention-abcdef1234 --region us-east-1The gateway, its targets, its service role, and any RESPONSE interceptor are not affected. The token secret stays recoverable in Secrets Manager for 30 days.
If deletion fails with Could not remove the Capsule REQUEST interceptor, remove it in AgentCore console → Gateways → your gateway → Interceptors, then delete the stack again. Do not delete the stack with resources retained while the entry is still on the gateway: the gateway would call a Lambda that no longer exists and every tool call would fail. Do not clear it with a bare aws bedrock-agentcore-control update-gateway either. UpdateGateway replaces the whole gateway definition, so every optional setting you do not re-supply (KMS key, WAF, policy engine, authorizer configuration, description) is cleared.
| Symptom | Where to look | Likely cause |
|---|---|---|
Stack fails at CapsuleGatewayInterceptorRegistration | CloudFormation Events, log group /aws/lambda/capsule-agentcore-register-<suffix> | Wrong GatewayIdentifier or GatewayName, GatewayRoleArn does not match the gateway's role, another REQUEST interceptor on the gateway, or the gateway was not READY |
Stack update fails with GatewayIdentifier cannot be changed | CloudFormation Events | The update pointed the stack at another gateway. Nothing changed; create a separate stack for the other gateway |
| Every request through the gateway fails after deployment | Gateway status; interceptor log group is empty | The gateway's service role does not allow lambda:InvokeFunction (see Gateway service role) |
| Requests go through unevaluated | Log group /aws/lambda/capsule-agentcore-interceptor-<suffix>, capsule unreachable lines | capsule 401: wrong, expired, or rotated token, or an endpoint from another Capsule region. Abort: Capsule did not answer within 25 seconds. fetch failed: the endpoint is not reachable from AWS |
| Requests are never blocked, and nothing is logged | Capsule Inventory → Agents | The calling runtime is not in Capsule yet, or no policy is in Prevention mode |
The interceptor logs one line when it gets no usable answer from Capsule and nothing otherwise. It never logs the caller's Authorization header or request bodies. When contacting support, include the stack name, region, gateway ID, and the x-correlation-id from the interceptor log line. Never send the token.
- Check the Events tab for specific error messages
- Verify you have permissions to create IAM roles
- Ensure the stack name doesn't already exist
- Confirm the stack status is CREATE_COMPLETE
- Verify you copied the full ARN from the Outputs tab
- Check that the role or its permission hasn't been modified or deleted
- Verify Bedrock agents exist in the connected AWS account
- Check the agent regions match your Capsule environment
- Allow several minutes for the initial sync to complete
- Confirm CloudTrail is enabled in your account
- Verify model invocation logging is enabled in Bedrock settings
- Check that agents have been invoked since the integration was connected
The integration supports all AWS regions where Bedrock is available. Each Capsule environment syncs from a specific AWS region based on your deployment.
For help with this integration, contact support.
For AWS Bedrock issues: