New White Paper: From Zero Trust to Agent Trust
Read now
Home
Blog
When AI Agents Call AWS, Who Does AWS Think They Are?

When AI Agents Call AWS, Who Does AWS Think They Are?

Jeffrey Ellin

6 min read
Published July 8, 2026

When AI Agents Call AWS, Who Does AWS Think They Are? Blog Header Image

In Part 1, Your AI Agent Needs to Know Who You Are, we showed how Teleport JWTs give MCP tools a verified identity for every request. This post extends that pattern to AWS, specifically to Amazon Bedrock AgentCore, where the same identity gap exists but requires a different solution stack.

You ask an AI agent to list your S3 buckets. The agent calls an MCP tool. The tool reaches out to AWS. However, CloudTrail records the action under something like agentcore-bot, but not your identity. A generic service account tells you almost nothing.

This is the default when you build on Amazon Bedrock AgentCore without identity propagation, which makes the audit trail almost useless for accountability. And when someone leaves, their agent-powered access stays behind.

Two panel graphic divided left and right. Left side reads: “What You Wanted: Alice wants to list her S3 buckets, Alex wants read only access to order data, and Amy wants to check deployment status. Right side reads: “What AWS Sees: lambda-service-role called ListBuckets, agent-bot requested GetOrder, and mcp-tool-user queried ECS tasks.”

The fix is to carry caller identity through the entire chain from login, through the agent, through AgentCore, into the Lambda, and into the AWS API call. Here’s how it works.

Why AgentCore is the right chokepoint

AgentCore is a managed MCP gateway, which means every tool call passes through it before reaching a Lambda. This makes it the natural place to enforce identity. By default, the gateway validates that requests are structurally correct, but it doesn’t propagate caller identity into the tools. This means that Lambda knows it was invoked by AgentCore, but it doesn’t know which human was behind the request.

This gap has three consequences:

  • Shared permissions: All users run as the same IAM role. You either over-provision it or break power users.
  • Anonymous audit trail: CloudTrail shows the Lambda execution role but not the person who triggered the action.
  • Stale access: IAM roles on Lambda functions aren’t tied to individuals. When Alice leaves, the tools she could invoke keep running for anyone using the same agent.

Teleport as the identity source for AgentCore

Teleport addresses these gaps in AgentCore. When a user authenticates and connects to the MCP gateway, Teleport issues a short-lived signed JWT with their verified identity. For example:

tsh login your-cluster.teleport.sh
tsh mcp connect <mcp-server>
sub:   [email protected]
roles: ["mcp-user", "order-admin"]
aud:   mcp+https://<mcp-server>/mcp
exp:   <1 hour from now>

Teleport then attaches this JWT to every outbound agent request as Authorization: Bearer <token>. This is signed by Teleport’s private key and verifiable against Teleport's JWKS URL, so no downstream component needs to trust the caller’s word about who they are.

One config change in teleport.yaml wires this up:

app_service:
  enabled: true
  apps:
    - name: identity-aware-mcp
      uri: "mcp+http://localhost:9999/mcp"
      rewrite:
        headers:
          - "Authorization: Bearer {{internal.id_token}}"

In this example, {{internal.id_token}} resolves to the signed JWT for the authenticated user at request time. Without this, tsh mcp connect reaches the server but no identity context flows through.

The AWS stack

AgentCore: Validation at the edge

Configure AgentCore with a JWT authorizer pointing to Teleport's OIDC discovery URL. On every incoming tool call, the gateway fetches Teleport’s current public signing keys and validates the JWT before routing anything to a Lambda. For example:

authorizerType='CUSTOM_JWT',
authorizerConfiguration={
  'customJWTAuthorizer': {
    'discoveryUrl': 'https://<cluster>/.well-known/openid-configuration',
    'allowedAudience': [mcp_audience],
    'customClaims': [{
      'inboundTokenClaimName': 'roles',
      'claimMatchValue': {'matchValueString': 'mcp-user'},
      'claimMatchOperator': 'CONTAINS'
    }]
  }
}

Expired token, wrong audience, forged signature, or missing required role causes the call to be rejected, and no Lambda runs. However, the gateway validates the JWT and then drops it, so the Lambda still receives no identity context. This is what the interceptor solves.

REQUEST interceptor: Bridging the gap

AgentCore supports interceptor Lambdas that run before tool invocations. Configure one as a REQUEST interceptor with passRequestHeaders: true and AgentCore forwards the original Authorization header to it. Because the gateway already validated the JWT, the interceptor decodes the payload and injects the identity claims into the tool call arguments, like so:

def lambda_handler(event, context):
    auth_header = event.get('requestHeaders', {}).get('Authorization', '')
    token = auth_header.replace('Bearer ', '')
    payload = jwt.decode(token, options={"verify_signature": False})  # gateway verified

    event['requestParameters']['arguments']['_teleport_user']  = payload.get('sub', 'unknown')
    event['requestParameters']['arguments']['_teleport_roles'] = json.dumps(payload.get('roles', []))
    return event

Amazon Verified Permissions: Per-tool authorization

Amazon Verified Permissions evaluates Cedar policies. The interceptor calls avp.is_authorized() with the caller's Teleport identity and the requested tool name. Cedar policies map Teleport roles to tools:

// Any mcp-user can read orders
permit (
  principal in TeleportRole::"mcp-user",
  action == Action::"invoke_tool",
  resource == Tool::"get_order_tool"
);

// Only order-admin can modify orders
permit (
  principal in TeleportRole::"order-admin",
  action == Action::"invoke_tool",
  resource == Tool::"update_order_tool"
);

On deny, the interceptor returns an error and the tool Lambda never runs. Policy changes take effect on the next request, with no Lambda redeployment or gateway restart. These are the same Teleport roles already controlling SSH, database, and Kubernetes access, with no second RBAC system to maintain.

Tool Lambdas: Identity as parameters

Teleport ensures tools receive identity as clean, already-verified function parameters and without requiring auth code. For example:

def get_order_tool(orderId, *, _teleport_user='unknown', _teleport_roles='[]', **kwargs):
    roles = json.loads(_teleport_roles)
    if 'order-admin' in roles:
        return query_all_orders()
    return query_orders(owner=_teleport_user)  # scoped to caller

What this looks like in practice

Six step flowchart organized from top to bottom. Step 1, user runs tsh mcp connect, Teleport issues JWT. Step 2, agent calls AgentCore Gateway with JWT in Authorization header. Step 3, gateway validates JWT against Teleport’s OIDC discovery URL. Step 4, AgentCore Interceptor processes the request and injects identity context. Step 5, request is routed to the MCP server with identity context. Step 6, MCP server executes the request and returns the response to the agent.

Consider two examples of what this workflow looks like in practice. Both Alice and Bob are attempting to update an invoice using an agent. However, Alice’s assigned role is not scoped to this action, while Bob’s role is.

Alice (role: mcp-user) asks her agent to update order 42. AgentCore validates her JWT, and the interceptor asks AVP: “Is [email protected] allowed to invoke update_order_tool?” However, there’s no Cedar policy granting mcp-user that access, so AVP returns deny. Alice’s agent gets a 403, and the Lambda never runs.

Bob (role: order-admin) makes the same agent call. AVP finds the matching policy, returns allow, the interceptor injects Bob’s identity, and the tool runs scoped to Bob. CloudTrail records Bob’s identity.

There are three audit sources in this workflow:

  1. Teleport session logs (who connected and when)
  2. AVP authorization logs (every decision with the matching policy ID)
  3. CloudTrail (the AWS API call attributed to the user)

Identity is recorded across these sources, making correlation and incident investigations straightforward.

What it takes to set this up

If you’re already on Teleport, this workflow is very easy to configure. JWT issuance is built into tsh mcp connect. The AgentCore OIDC authorizer is a configuration change. The interceptor Lambda is around 30 lines. Cedar policies are readable by anyone who has written an access control rule.

The notebooks in our aws-agentcore GitHub repo are the fastest way to see it working. Each notebook leaves the infrastructure from the previous one in place, so the final state is the complete working system. The whole sequence takes under an hour if you have a Teleport cluster and an AWS account ready.


Jeffrey Ellin

Jeffrey Ellin

Jeffrey Ellin is a cloud-native technologist with 10+ years of hands-on experience in Kubernetes architecture, enterprise-scale containerized deployments, and AI-powered applications. Jeffrey actively builds and experiments with agentic AI systems, including Model Context Protocol (MCP) integrations, OAuth workflows, and machine identity with SPIFFE to bridge the gap between emerging technology and real-world, production-ready solutions.

Teleport Newsletter

Stay up-to-date with the newest Teleport releases by subscribing to our monthly updates.

Teleport Newsletter

Stay up-to-date with the newest Teleport releases by subscribing to our monthly updates.


Related Articles