I implemented IAM authentication from AgentCore Runtime to AgentCore Gateway using MCP Proxy for AWS

I implemented IAM authentication from AgentCore Runtime to AgentCore Gateway using MCP Proxy for AWS

2026.01.18

This page has been translated by machine translation. View original

Introduction

Hello, I'm Jinno from the Consulting Department, a fan of the supermarket "La Mu" (@yjinno).

How do you handle Inbound Auth authentication when calling Gateway from Amazon Bedrock AgentCore Runtime?

During AgentCore's Preview, I thought M2M authentication was the way to go,
but now that Gateway also supports IAM authentication, I wondered if IAM might be simpler in some cases... That's what prompted me to write this article.

Prerequisites

Environment

I used the following versions for this implementation:

Item Version
Terraform >= 1.5.0
AWS Provider >= 6.25.0
Python 3.12
bedrock-agentcore >= 1.2.0
strands-agents >= 1.22.0
mcp-proxy-for-aws >= 1.1.5

Architecture Overview

Here's the architecture we're building.
Gateway calls will use IAM authentication, and for simplicity, Runtime calls will also use IAM authentication.

CleanShot 2026-01-18 at 15.04.56@2x

For the complete Terraform code, please refer to this repository:

https://github.com/yuu551/runtime-to-gateway-for-iam

Terminology Clarification

Since AgentCore involves authentication at two levels (Runtime / Gateway), let's clarify the terminology first:

  • Runtime Inbound Auth
    • Authentication when a client (person/application) calls AgentCore Runtime (IAM or JWT)
  • Gateway Inbound Auth
    • Authentication when Runtime calls AgentCore Gateway (IAM (SigV4) or JWT)
  • Gateway Outbound Auth
    • Authentication when Gateway calls a target (e.g., Lambda / external API) (SigV4, etc.)

The main focus of this article is Runtime → Gateway calls (= Gateway Inbound Auth).
For simplicity of verification, Runtime Inbound Auth is set to IAM.

Authentication Methods for Runtime→Gateway

M2M Authentication

Initially, I was considering M2M (Machine-to-Machine) authentication for Runtime→Gateway.

However, using M2M authentication requires:

  • Setting up a Cognito User Pool
  • Creating a Machine-to-Machine application client
  • Managing client secrets
  • Implementing token acquisition and refreshing

Creating Cognito and acquiring tokens is a bit cumbersome, isn't it?
Of course, token acquisition can be simplified using the SDK.

import asyncio
from bedrock_agentcore.identity.auth import requires_access_token, requires_api_key

@requires_access_token(
    provider_name= "sample-provider",
    scopes= [],
    auth_flow= 'M2M',
)
async def need_token_2LO_async(*, access_token: str):

IAM Authentication

On the other hand, IAM authentication offers these benefits:

  • No need for Cognito
  • No secret management required (uses IAM roles)
  • Just add bedrock-agentcore:InvokeGateway permission to Runtime's IAM role
  • SigV4 signing automated with mcp-proxy-for-aws

Since AgentCore Runtime already has an IAM role, it's convenient that you only need to add permissions for Gateway access without building additional authentication infrastructure.

Gateway configuration is also simple; just set authorizer_type to AWS_IAM:

gateway.tf
resource "aws_bedrockagentcore_gateway" "main" {
  name     = "${var.project_name}-gateway"
  role_arn = aws_iam_role.gateway.arn

  protocol_type = "MCP"

  # Inbound auth: Specify IAM authentication
  authorizer_type = "AWS_IAM"

  # ...omitted
}

For Runtime, add bedrock-agentcore:InvokeGateway permission:

runtime.tf
resource "aws_iam_role_policy" "agent_runtime_gateway" {
  name = "${var.project_name}-agent-runtime-gateway-policy"
  role = aws_iam_role.agent_runtime.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = "InvokeGateway"
        Effect = "Allow"
        Action = [
          "bedrock-agentcore:InvokeGateway"
        ]
        Resource = aws_bedrockagentcore_gateway.main.gateway_arn
      }
    ]
  })
}

While the MCP client for Gateway connections typically assumes token authentication, AgentCore Gateway requires IAM (SigV4) authentication. You might worry about implementing signature processing, but the convenient MCP Proxy for AWS library bridges this gap! We'll look at the implementation details later.

https://github.com/aws/mcp-proxy-for-aws

When to Choose IAM vs M2M Authentication

After explaining the benefits of IAM authentication, you might wonder when to use M2M authentication instead.

If you have multiple agents and need fine-grained authorization control for tools on a per-agent basis, M2M authentication might be a better option. Let's look at the differences in detail.

IAM Authentication Constraints

IAM authentication only allows access control at the Gateway level.

{
  "Action": "bedrock-agentcore:InvokeGateway",
  "Resource": "arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/my-gateway"
}

It doesn't allow tool-level control, such as specifying which tools within a Gateway a Runtime can use.
Therefore, if each agent needs to execute different sets of tools, you'd need to separate Gateways as shown below:

CleanShot 2026-01-18 at 15.11.54@2x

If you only have a few tools, you might not need Gateway at all, or if all agents use the same universal tools, one Gateway might be sufficient.

What M2M Authentication + Interceptors/Policies Can Do

On the other hand, combining M2M JWT authentication with Gateway Interceptors/Cedar Policies enables more fine-grained authorization control.
Let's consider a scenario with multiple AI agents, each with restricted access to specific tools:

CleanShot 2026-01-18 at 20.07.48@2x

This level of control can be achieved by validating JWT scopes and attributes using Interceptors or Cedar Policies.

Authentication Method Selection Guide

Pattern Use Case Tool-level Authorization
IAM Authentication Simple setup, all tools available to all agents Not possible
M2M JWT + Interceptor/Policy Multi-agent, tool-level authorization needed Possible

I believe IAM authentication is sufficient for simple configurations with just one agent.
If you have multiple agents and need to assign different tool access permissions to each agent for the same Gateway, consider M2M authentication.

I plan to test and introduce agent-specific permission separation in a future article.

M2M Authentication Considerations

When using custom attributes with M2M authentication, there are some important considerations:

https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-token-generation.html

If you need authorization control based on user permissions, you'll need to implement user delegation-based permission control. This article is specifically focused on scenarios where agents are the authorization principals.

Implementation with Strands Agents

Agent Implementation

Let's look at the code implementation.
It's a simple agent that connects to Gateway and calls tools:

agent/agent.py
import os
from bedrock_agentcore.runtime import BedrockAgentCoreApp
from strands import Agent
from strands.models import BedrockModel
from strands.tools.mcp import MCPClient
from mcp_proxy_for_aws.client import aws_iam_streamablehttp_client

GATEWAY_URL = os.getenv("GATEWAY_URL", "")
AWS_REGION = os.getenv("AWS_REGION", "us-east-1")
MODEL_ID = os.getenv("BEDROCK_MODEL_ID", "us.anthropic.claude-haiku-4-5-20251001-v1:0")

app = BedrockAgentCoreApp()
model = BedrockModel(model_id=MODEL_ID, region_name=AWS_REGION)

@app.entrypoint
def invoke(payload: dict) -> dict:
    message = payload.get("prompt") or payload.get("message", "")
    if not message:
        return {"error": "No message", "status": "error"}

    if GATEWAY_URL:
        # Create MCP client with SigV4 signature using mcp-proxy-for-aws
        mcp_factory = lambda: aws_iam_streamablehttp_client(
            endpoint=GATEWAY_URL,
            aws_region=AWS_REGION,
            aws_service="bedrock-agentcore"
        )
        mcp_client = MCPClient(mcp_factory)
        agent = Agent(model=model, tools=[mcp_client])
        result = agent(message)
    else:
        agent = Agent(model=model)
        result = agent(message)

    return {"response": str(result.message), "status": "success"}

if __name__ == "__main__":
    app.run()

The key part is using aws_iam_streamablehttp_client to connect to Gateway with IAM authentication:

mcp_factory = lambda: aws_iam_streamablehttp_client(
    endpoint=GATEWAY_URL,
    aws_region=AWS_REGION,
    aws_service="bedrock-agentcore"
)
Parameter Value Description
endpoint Gateway URL AgentCore Gateway endpoint URL
aws_region us-east-1, etc. AWS Region
aws_service bedrock-agentcore Service name for SigV4 signature

Specifying bedrock-agentcore as the aws_service ensures that requests to Gateway have the correct SigV4 signatures. It's simple and convenient!

The rest is almost the same as a regular MCP Client implementation.
Set the mcp_client in the Agent's tools:

mcp_factory = lambda: aws_iam_streamablehttp_client(
            endpoint=GATEWAY_URL,
            aws_region=AWS_REGION,
            aws_service="bedrock-agentcore"
        )
mcp_client = MCPClient(mcp_factory)
agent = Agent(model=model, tools=[mcp_client])
result = agent(message)

This is an experimental feature, but being able to set the client directly is convenient! Previously, we had to write it with a with statement, so this is simpler. Even though it's experimental, I'd like to use it actively.

mcp_factory = lambda: aws_iam_streamablehttp_client(
            endpoint=GATEWAY_URL,
            aws_region=AWS_REGION,
            aws_service="bedrock-agentcore"
        )
with MCPClient(mcp_factory) as mcp:
    agent = Agent(model=model, tools=mcp.list_tools_sync())
    result = agent(message)

https://strandsagents.com/latest/documentation/docs/user-guide/concepts/tools/mcp-tools/#integration-approaches

Let's Try It Out

Let's deploy this configuration with Terraform and verify that requests are properly sent to Gateway!

Clone the Repository

First, clone the repository:

git clone https://github.com/yuu551/runtime-to-gateway-for-iam.git
cd runtime-to-gateway-for-iam

Initialize and Deploy with Terraform

Initialize Terraform:

terraform init

Next, check what will be deployed:

terraform plan

After confirming that Gateway, Runtime, Lambda functions, and other resources will be created,
run the deployment:

terraform apply

When prompted for confirmation, enter yes:

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

Upon completion, you'll see output like this:

Apply complete! Resources: 23 added, 0 changed, 0 destroyed.

Outputs:

gateway_endpoint = "https://xxxxxxxxxx.bedrock-agentcore.us-east-1.amazonaws.com"
runtime_endpoint = "https://yyyyyyyyyy.bedrock-agentcore.us-east-1.amazonaws.com"

Deployment complete!

Testing from the Console

Now that we've deployed, let's try sending requests from the console.
We expect the Lambda functions attached to the Gateway to process our requests. We have:

  • Addition tool
  • Multiplication tool
  • Greeting tool
  • Tool search tool made available by Gateway
{"prompt": "Tell me what I can do with these tools"}

CleanShot 2026-01-18 at 08.40.47@2x

We got the tool list as expected!
Now let's check if the addition tool works:

{"prompt": "What is 100 + 12?"}

CleanShot 2026-01-18 at 08.41.14@2x

The tool executed correctly! The logs also confirm it:

{
  "message": {
    "tool_calls": [
      {
        "type": "function",
        "id": "tooluse_c9qOEPXPS2a6OR8UxN4tfg",
        "function": {
          "name": "iam-auth-demo-lambda-target___add_numbers",
          "arguments": {
            "a": 100,
            "b": 12
          }
        }
      }
    ],
    "role": "assistant"
  },
  "index": 0,
  "finish_reason": "tool_use"
}

This confirms that Runtime→Gateway works with IAM authentication!

Conclusion

Using MCP Proxy for AWS makes it convenient to call Gateway from Runtime without worrying about SigV4 signatures.
For simple configurations, IAM authentication is a viable option as it doesn't require Cognito or secret management.

However, for multi-agent environments where tool-level authorization is needed for each agent, consider using M2M authentication with Interceptors/Policies.

I hope this article has been helpful!
Thank you for reading!

Share this article

FacebookHatena blogX

Related articles