
Identity-aware AI data agents with AWS Lake Formation and Trusted Identity Propagation
AWS Security Blog walkthrough showing how to build identity-aware AI data agents on Amazon Bedrock AgentCore that propagate a real user's OIDC id_token through the agent's tool-calling chain (Runtime → MCP Gateway → Lambda) via HTTP headers, keeping the token out of the foundation model's context entirely. A Lambda function performs a server-side token exchange using IAM Identity Center Trusted Identity Propagation, assumes a scoped TIP role, and runs the user's Athena query so AWS Lake Formation evaluates the real user's grants, producing per-user row/column access and CloudTrail audit records naming the actual human (onBehalfOf) without rewriting existing governance policies.
What it claims
An agent's tools usually run under a shared IAM role, so Lake Formation sees that role and not the person asking. This post routes the user's id_token around the foundation model instead, using three Bedrock AgentCore settings. A Lambda function exchanges the token server-side and assumes a TIP role that holds no Lake Formation data grants. The role is "a session vehicle, not an authorization subject", so only the user's existing grants decide access. The agent, gateway and Lambda contain no authorization logic.
How it works
The decision that matters is where the token travels: on the HTTP transport, never in the tool contract.
flowchart LR UI -->|prompt in body| RT[AgentCore Runtime] UI -->|id_token custom header| RT RT --> FM[Foundation model] FM -->|tool args only| GW[AgentCore Gateway] RT -->|headers via agent code| GW GW -->|event = tool params| L[Lambda] GW -->|propagated headers| L L -->|CreateTokenWithIAM + AssumeRole| ATH[Athena / Lake Formation]
Three gates control propagation. Each is off by default:
- Runtime
requestHeaderAllowlist. AllowAuthorization(theaccess_token, validated by the JWT authorizer) and a custom header. Custom headers must use the prefixX-Amzn-Bedrock-AgentCore-Runtime-Custom-; the post usesX-Amzn-Bedrock-AgentCore-Runtime-Custom-IdToken. Agent code reads them fromcontext.request_headersand attaches both to the MCP connection to the gateway. - Gateway target
metadataConfiguration.allowedRequestHeaders. List theid_tokenheader here. The tool schema has no token parameter. If the token were a tool argument, the model would have to pass it, and it would end up in prompts, traces, memory and logs. - Lambda. The token arrives in
context.client_context.custom['bedrockAgentCorePropagatedHeaders'], not inevent, which holds only the declared tool parameters.
Inside Lambda, the function:
- Validates the
id_token. - Calls
sso-oidc:CreateTokenWithIAMto get anidentityContext. - Calls
sts:AssumeRolewithProvidedContextsto get a short-livedboto3.Session. - Runs the Athena query with that session.
The identityContext is never returned to the agent, gateway or UI.
How to use it
Prerequisites, none of which the post sets up:
- An IAM Identity Center trusted token issuer (TTI) that accepts your IdP's tokens. Cognito is the demo IdP; the post says Auth0, Entra ID, Okta, Ping or any other OIDC provider works the same way.
- An Identity Center OAuth application configured for
CreateTokenWithIAMwith the JWT Bearer grant. - Lake Formation governing the Glue Data Catalog, with grants on Identity Center users or groups. Existing grants and row/column filters work unchanged.
- An Athena workgroup and an S3 bucket for query results.
Permissions the post lists for the TIP role:
athena:*glue:*lakeformation:GetDataAccess- S3 access to the Athena output bucket
To verify:
- Run the same question as two users. User A has SELECT on
trip_detailsand gets rows; User B has no grant and is refused. No code changes between the runs. - Check the CloudTrail
AssumeRoleevent for anonBehalfOfblock naming the human.
Limits
- The code samples and configuration snippets did not appear in the fetched text. Expect to take them from the original post or its reference implementation.
- The three header-propagation settings are specific to AgentCore. Other agent stacks such as Strands or LangGraph need AgentCore underneath or an equivalent transport path.
- The listed TIP role permissions are wildcards (
athena:*,glue:*). Data access is still bounded by Lake Formation, but you may want to narrow these. - The post does not discuss:
- token expiry during long agent sessions,
- whether the agent container and gateway logs capture the headers,
- any latency or cost added by the per-call token exchange.
Organisations named here
- Amazon Web Services
- Okta
- Auth0
- Microsoft
- Ping Identity
- AWS
- AWS Glue
- LangGraph
Technologies named here
- Amazon Bedrock AgentCore Runtime
- Amazon Bedrock AgentCore Gateway
- Strands
- LangGraph
- Model Context Protocol
- AWS Lake Formation
- AWS IAM Identity Center
- AWS Lambda
- Amazon Athena
- AWS CloudTrail
- Amazon Cognito
- AWS Glue Data Catalog
- Amazon S3
- AWS
- Amazon Bedrock AgentCore
- AWS Glue
- OAuth
Techniques named here
- Trusted Identity Propagation
- Server-side token exchange
- Runtime request header allow list
- Gateway metadata header propagation
- Out-of-band identity transport
- TIP role with no data grants
Related in agents



