Securing AI Tool Calls with Amazon Bedrock AgentCore Gateway Interceptors and Terraform
An AI agent can produce a reasonable answer and still attempt an action it should never be allowed to perform. Consider a support agent connected to tools that retrieve customer records and update account details. A user asks it to access another customer’s information. Whether that request comes from an ordinary mistake, a malicious prompt, or an agent choosing the wrong tool, the engineering question is the same: what enforces the boundary before the action happens?
An AI agent can produce a reasonable answer and still attempt an action it should never be allowed to perform.
Consider a support agent connected to tools that retrieve customer records and update account details. A user asks it to access another customer’s information. Whether that request comes from an ordinary mistake, a malicious prompt, or an agent choosing the wrong tool, the engineering question is the same: what enforces the boundary before the action happens?
A system prompt is not an authorization mechanism. The application needs controls around tool execution, with decisions based on trusted identity and explicit permissions.
This is the problem space behind my contribution to the AWS IA Terraform module for Amazon Bedrock AgentCore, PR #20 : support for Gateway interceptor configurations and automatic Lambda invocation permissions.
The contribution brings the wiring for these controls into Terraform. The actual security decisions still belong in the policies and code that teams implement.
Two points where an interceptor can help
Amazon Bedrock AgentCore Gateway supports Lambda interceptors at two stages of its request lifecycle. A request interceptor runs before the gateway calls its configured target. A response interceptor runs before the gateway returns a response to the caller. [1]
These hooks let teams add application-specific checks and transformations at the gateway boundary.
| Interception point | Example responsibility | Important boundary |
|---|---|---|
| REQUEST | Check whether a caller may invoke a particular tool with the supplied arguments | Make the decision before the target performs an action |
| RESPONSE | Remove fields that should not be returned to the caller | Redaction cannot undo an action already performed by the target |
For a customer-support application, a request interceptor could verify that the caller is allowed to access the requested account. A response interceptor could remove internal-only fields from the result.
Those are possible implementations, not protections that appear automatically when an interceptor is attached. A function that passes every request through unchanged does not enforce authorization.
What I contributed through Terraform
My PR added support for configuring Gateway interceptors in the module’s
awscc_bedrockagentcore_gateway resource, together with automatic permissions for invoking the configured Lambda functions. [3]The practical value is that teams can manage the interceptor attachment alongside their gateway infrastructure instead of maintaining that relationship as a separate manual step.
This matters because a security function and its deployment configuration are part of the same control. A well-written authorization function provides no protection for a gateway that never invokes it.
Managing that wiring through Terraform gives teams a place to review changes: which function is attached, where it runs in the request lifecycle, and what permissions support the integration. It also makes it easier to reproduce the intended setup across environments.
Automatic invocation permissions reduce setup work. They do not prove that every permission in an application follows least privilege. Teams should still review the generated IAM policy and the permissions used by the interceptor and target services.
A concrete example: access to customer records
Imagine an agent that can call a customer-record lookup tool. The tool accepts an account identifier, and its response includes both customer-visible data and internal operational fields.
I would design its controls around three decisions:
- Establish who is calling. Use the configured authentication mechanism and trusted identity context. Never accept an account owner or tenant identity merely because the model supplied it as a tool argument.
- Authorize the requested action. Check the caller’s entitlement to that account and operation before forwarding the tool call. Preserve authorization inside the backend as well, particularly where the backend has other callers.
- Limit the returned information. Return only the fields needed for the task. A response interceptor can provide an additional filtering step, but the backend should avoid returning unnecessary sensitive data in the first place.
For MCP targets, AWS documents a request-interceptor response contract that can return a response immediately instead of forwarding the request to the target. That makes rejecting a disallowed request possible at this boundary. [1]
The identity-to-resource relationship is the crucial part. Checking that a tool name is allowed is insufficient if that same tool can retrieve another tenant’s records.
The implementation details that deserve scrutiny
Forward headers deliberately. The
passRequestHeaders setting controls whether request headers reach the Lambda interceptor. AWS documents that it defaults to false and warns that forwarded headers can contain credentials or authentication tokens. If the implementation requires headers, avoid logging the entire event. [2]Keep the gateway on the enforced path. If an agent can call a backend directly using broader credentials, it may bypass controls implemented only at the gateway. Review the agent’s permissions and the backend’s access rules together.
Treat errors as part of the security design. Test timeouts, malformed responses, unavailable dependencies, and missing identity context. An authorization dependency failing should not become permission to proceed. Verify the behavior of the complete deployed path rather than assuming the function’s happy path is enough.
Test the negative cases. A successful authorized request proves connectivity. A denied cross-tenant request provides evidence about the boundary you intended to enforce.
My minimum acceptance tests would include:
| Test | Expected outcome |
|---|---|
| Authorized caller requests an allowed account | Required data is returned |
| Caller requests another tenant’s account | Request is denied before target execution |
| Required identity context is absent or invalid | Request is denied |
| Target returns an internal-only field | Field is excluded from the caller-visible result |
| Interceptor or authorization dependency fails | Operation does not proceed without authorization |
These are proposed acceptance criteria, not benchmark results or claims about a deployment I have measured.
What this taught me about AI security as code
The value of infrastructure as code extends beyond creating resources. It gives teams a reviewable record of how security controls are connected to the systems they protect.
For AI agents, that includes the boundary between a requested action and an actual tool invocation. The model can propose an action; trusted application controls must decide whether it is permitted.
My AgentCore contribution addresses a specific part of that work: making Gateway interceptor configuration and its invocation permissions easier to manage through Terraform. Teams still need sound authorization logic, constrained backend access, and tests that demonstrate enforcement.
If you are building an agent with access to business tools, start with one question: where is an unauthorized action stopped before it executes? Then make that control explicit in both your application and your infrastructure code.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article