O problema: agentes de IA que ignoram quem está perguntando
Imagine que você construiu um agente de dados que permite a usuários de negócio fazer perguntas em linguagem natural sobre um lakehouse. Você já tem políticas de governança definindo quem pode acessar quais conjuntos de dados. O desafio é fazer o agente respeitar essas regras sem precisar reconstruí-las no código da aplicação.
Quando um usuário faz uma pergunta, o agente mapeia a intenção para os dados e monta uma consulta. O problema está aqui: a ferramenta que executa essa consulta opera sob uma função do AWS Gerenciamento de Identidade e Acesso (IAM) própria. Isso significa que o AWS Lake Formation enxerga as credenciais da ferramenta — não a pessoa que fez a pergunta. Sobram duas saídas ruins: restringir o acesso da ferramenta (limitando a análise self-service) ou reconstruir os controles de acesso no código da aplicação (tirando a governança da camada de dados).
A AWS publicou um padrão diferente: agentes de IA com consciência de identidade, que propagam a identidade de cada usuário por todos os saltos — do usuário, passando pelo agente, chegando até a ferramenta — para que o Lake Formation avalie as permissões do usuário real. O código da aplicação não toma nenhuma decisão de autorização, as políticas existentes no Lake Formation funcionam sem modificações, e o AWS CloudTrail registra a pessoa real que acessou os dados.
O que esse padrão entrega na prática
O padrão, implementado com o Amazon Bedrock AgentCore, resolve três problemas de uma vez:
- Controle de acesso por usuário para agentes de IA que consultam o lakehouse, sem reescrever as políticas existentes do Lake Formation.
- Auditabilidade e conformidade garantidas por uma troca de token no servidor, dentro do AWS Lambda, que converte o token de identidade em credenciais com escopo do usuário real — com cada consulta registrada no CloudTrail.
- Validação ponta a ponta com múltiplos usuários, confirmando resultados distintos e evidências de auditoria por usuário.
Os blocos de construção — delegação de token OAuth 2.0, AWS IAM Identity Center, Lake Formation e Lambda — são bem documentados individualmente. A novidade é que um modelo de fundação (FM) agora está no meio da cadeia de propagação. O FM é o cérebro do agente: ele decide quais ferramentas chamar e quais argumentos passar. Qualquer coisa que entra no seu contexto (prompts, esquemas de ferramentas, argumentos) fica acessível dentro daquele limite de confiança. Por isso, o token de identidade do usuário precisa chegar à ferramenta, mas deve fazer isso na camada de transporte HTTP — completamente fora da camada de raciocínio do FM.
Como o fluxo funciona
Dois tokens percorrem o sistema. Um access_token autentica a requisição em cada fronteira de confiança. Um id_token carrega a identidade do usuário e é trocado, no servidor, pelo contexto de identidade que o Lake Formation avalia.
O fluxo completo da requisição funciona assim:
- Usuário → Interface: o usuário se autentica com um provedor de identidade OpenID Connect (OIDC). A implementação de referência usa o Amazon Cognito, mas qualquer provedor OIDC funciona. A interface recebe um
id_tokene umaccess_token. - Interface → AgentCore Runtime: a interface chama o agente via HTTPS. O
access_tokenvai no cabeçalho padrãoAuthorization. Oid_tokenvai em um cabeçalho customizado:X-Amzn-Bedrock-AgentCore-Runtime-Custom-IdToken. O corpo HTTP contém apenas o prompt do usuário. - AgentCore Runtime → código do agente: o runtime valida o
access_tokene repassa a requisição ao container do agente com ambos os cabeçalhos acessíveis viacontext.request_headers. - Agente → AgentCore Gateway: o agente abre uma conexão via Protocolo de Contexto de Modelo (MCP) com o gateway, incluindo ambos os cabeçalhos na conexão. O gateway valida o
access_tokene encaminha o cabeçalho customizado ao Lambda alvo. - AgentCore Gateway → Lambda: os cabeçalhos propagados chegam em
context.client_context.custom['bedrockAgentCorePropagatedHeaders']. - Lambda → camada de dados: o Lambda valida o
id_token, troca-o por um contexto de identidade, assume uma função com esse contexto e executa a consulta no Amazon Athena sob a identidade do usuário. O Lake Formation avalia as permissões do usuário real. O Athena retorna apenas as linhas e colunas que aquele usuário tem direito de ver. O CloudTrail registra a função assumida com uma entradaonBehalfOfidentificando o ser humano.
Os três pontos de configuração no Bedrock AgentCore
1. Lista de permissão de cabeçalhos no runtime
Por padrão, o Bedrock AgentCore Runtime não repassa cabeçalhos de requisição ao container do agente. É necessário declarar uma lista de permissão explícita, seja via agentcore configure ou diretamente na configuração do runtime:
# .bedrock_agentcore.yaml
request_header_configuration:
requestHeaderAllowlist:
- Authorization
- X-Amzn-Bedrock-AgentCore-Runtime-Custom-IdToken
O runtime suporta dois tipos de cabeçalhos encaminhados: o cabeçalho padrão Authorization para autenticação JWT de entrada (access_token), e cabeçalhos customizados com prefixo X-Amzn-Bedrock-AgentCore-Runtime-Custom-. O id_token usa um cabeçalho customizado. Dentro do agente, os cabeçalhos permitidos chegam como um objeto dicionário no contexto da requisição. O código Python que roda no container do agente fica assim:
from bedrock_agentcore.runtime import BedrockAgentCoreApp
ID_TOKEN_HEADER = "X-Amzn-Bedrock-AgentCore-Runtime-Custom-IdToken"
app = BedrockAgentCoreApp()
@app.entrypoint
def invoke(payload, context):
request_headers = getattr(context, "request_headers", None) or {}
id_token = ""
access_token = ""
for key, value in request_headers.items():
if key.lower() == ID_TOKEN_HEADER.lower():
id_token = value
elif key.lower() == "authorization":
access_token = value.replace("Bearer ", "")
# ... build MCP headers and call the Gateway
O código do agente lê o id_token da camada de transporte HTTP e o encaminha (também na camada de transporte) para o próximo salto. Ele não trata o token como argumento de ferramenta e não o injeta em um prompt. Ponto-chave: a lista de permissão do runtime é o primeiro portão. Sem ela, o id_token não chega ao código do agente.
2. Metadados do AgentCore Gateway para propagação de cabeçalhos
O Bedrock AgentCore Gateway é o endpoint MCP com o qual o agente se comunica. Por padrão, ao invocar um Lambda alvo, ele não encaminha cabeçalhos arbitrários. É necessário configurar quais cabeçalhos propagar usando metadataConfiguration.allowedRequestHeaders no alvo:
from aws_cdk import aws_bedrockagentcore as agentcore
self.gateway_target = agentcore.CfnGatewayTarget(
self, "AthenaTarget",
name="athena-executor",
gateway_identifier=self.gateway.attr_gateway_identifier,
target_configuration=agentcore.CfnGatewayTarget.TargetConfigurationProperty(
mcp=agentcore.CfnGatewayTarget.McpTargetConfigurationProperty(
lambda_=agentcore.CfnGatewayTarget.McpLambdaTargetConfigurationProperty(
lambda_arn=lambda_function_arn,
tool_schema=... # execute_athena_query
),
),
),
metadata_configuration=agentcore.CfnGatewayTarget.MetadataConfigurationProperty(
allowed_request_headers=["X-Amzn-Bedrock-AgentCore-Runtime-Custom-IdToken"],
),
...
)
Observe que o esquema da ferramenta não inclui um parâmetro id_token — não há parâmetro de token em nenhuma ferramenta. O FM não vê, seleciona nem passa um id_token, porque o token não faz parte do contrato da ferramenta. Ele viaja em paralelo à chamada de ferramenta, na conexão HTTP, via metadataConfiguration. Essa é uma propriedade crítica de segurança: se o id_token fosse colocado no esquema da ferramenta, o FM seria responsável por passá-lo — o que significa que o token apareceria em prompts, rastreamentos, memória e logs. Mantê-lo fora do contrato da ferramenta o mantém fora do FM completamente.
3. Leitura dos cabeçalhos propagados no Lambda
No lado do Lambda, o cabeçalho propagado chega não no corpo do evento, mas no contexto do cliente, sob uma chave específica:
ID_TOKEN_HEADER = "X-Amzn-Bedrock-AgentCore-Runtime-Custom-IdToken"
def lambda_handler(event, context):
client_ctx = getattr(context.client_context, "custom", {}) or {}
propagated_headers = client_ctx.get("bedrockAgentCorePropagatedHeaders", {})
id_token = propagated_headers.get(ID_TOKEN_HEADER)
if not id_token:
return {"statusCode": 400, "body": {"error": "missing id_token"}}
# Tool arguments from the agent's call (no id_token here)
query = event["query"]
database = event["database"]
workgroup = event["workgroup"]
output_location = event["output_location"]
# ... validate token, exchange, run query
O dicionário do evento contém apenas os parâmetros declarados da ferramenta — nada mais. O id_token é acessado exclusivamente via context.client_context.custom['bedrockAgentCorePropagatedHeaders']. O Lambda é o único componente que lê o token.
A troca de token no servidor
Depois que o Lambda tem o id_token, ele valida o token e o troca por um identityContext. Essa etapa usa a mecânica padrão de Propagação de Identidade Confiável (TIP) do IAM Identity Center. O fato de acontecer dentro do Lambda é o que impede que o contexto de identidade cruze fronteiras de processo:
import boto3, jwt, time
def exchange_and_assume(id_token: str, user_sub: str):
# 1. Validate id_token against the OIDC IdP's JWKS.
claims = validate_id_token(id_token) # signature, exp, aud, iss, token_use
# 2. Exchange for an Identity Center identityContext.
sso_oidc = boto3.client("sso-oidc")
resp = sso_oidc.create_token_with_iam(
clientId=OAUTH_APPLICATION_ARN,
grantType="urn:ietf:params:oauth:grant-type:jwt-bearer",
assertion=id_token,
)
identity_context = resp["awsAdditionalDetails"]["identityContext"]
# 3. AssumeRole with ProvidedContexts
sts = boto3.client("sts")
assumed = sts.assume_role(
RoleArn=TIP_ROLE_ARN,
RoleSessionName=f"agent-tip-{user_sub[:8]}-{int(time.time())}",
ProvidedContexts=[{
"ProviderArn": "arn:aws:iam::aws:contextProvider/IdentityCenter",
"ContextAssertion": identity_context,
}],
)
creds = assumed["Credentials"]
return boto3.Session(
aws_access_key_id=creds["AccessKeyId"],
aws_secret_access_key=creds["SecretAccessKey"],
aws_session_token=creds["SessionToken"],
)
Dois aspectos importantes saem dessa troca: o identityContext é criado e consumido dentro de uma única invocação do Lambda — ele não volta para o agente, o gateway ou a interface. E a boto3.Session resultante contém credenciais de curta duração cuja asserção de identidade subjacente é o usuário real. Quando a sessão chama o Athena, a consulta roda com a identidade do usuário propagada. O Lake Formation enxerga o usuário, não a função do Lambda.
Configuração do Lake Formation
É necessária apenas uma permissão para o usuário ou grupo no IAM Identity Center. Esse é o único trabalho na camada do Lake Formation:
aws lakeformation grant-permissions \
--principal DataLakePrincipalIdentifier=arn:aws:identitystore:::user/ \
--resource '{"Table":{"DatabaseName":"iceberg_db","Name":"trip_details"}}' \
--permissions SELECT
Essa é a permissão que o Lake Formation avalia no momento da consulta. Filtros em nível de coluna e linha são adicionados ao mesmo usuário ou grupo da mesma forma. Nada aqui é específico para agentes de IA. Se você já tem um modelo de permissões do Lake Formation para usuários humanos, você já tem as permissões que esse padrão precisa.
A função TIP que o Lambda assume não tem permissões de dados no Lake Formation. Ela contém apenas permissões IAM para chamar as APIs de serviço: athena:* para execução de consultas, glue:* para leituras do catálogo, lakeformation:GetDataAccess para o handshake do plano de consulta, e acesso ao Amazon Simple Storage Service (Amazon S3) para o bucket de saída do Athena. Quando o Lambda assume essa função com um identityContext anexado via ProvidedContexts, o Lake Formation avalia apenas a identidade do usuário propagada. A função em si é transparente para a decisão de autorização.
Testando o padrão ponta a ponta
Dois usuários, mesma pergunta, resultados diferentes. O Usuário A tem permissão SELECT na tabela trip_details e solicita cinco registros — os dados são retornados. O Usuário B não tem permissão na mesma tabela e faz a mesma pergunta — o acesso é negado. Nenhum código mudou entre as duas interações. Nenhum parâmetro foi alterado. O Lake Formation tomou a decisão com base na identidade propagada.
O registro no CloudTrail para a chamada AssumeRole mostra a delegação:
{
"eventSource": "sts.amazonaws.com",
"eventName": "AssumeRole",
"requestParameters": {
"roleArn": "arn:aws:iam:::role/",
"roleSessionName": "agent-tip--",
"providedContexts": [{
"providerArn": "arn:aws:iam::aws:contextProvider/IdentityCenter",
"contextAssertion": ""
}]
},
"userIdentity": {
"type": "AssumedRole",
"onBehalfOf": {
"userId": "",
"identityStoreArn": "arn:aws:identitystore:::identitystore/"
}
}
}
O bloco onBehalfOf fecha o ciclo de auditoria. Cada consulta que o agente executa em nome de um usuário tem um registro no CloudTrail com o nome desse usuário — sem nenhuma instrumentação adicional no código.
As quatro propriedades de segurança do padrão
- O id_token nunca chega ao modelo de fundação: ele trafega em cabeçalhos HTTP em cada salto, e o Lambda o lê via
context.client_context.custom. Não é um parâmetro de nenhuma ferramenta. O FM não tem caminho para acessá-lo — nem em argumentos de ferramentas, nem em prompts, nem em memória, nem em rastreamentos. - O contexto de identidade permanece dentro de uma única invocação do Lambda: é derivado do
id_token, usado imediatamente em uma chamadaAssumeRolee descartado. Não retorna ao agente, ao gateway ou à interface. - As decisões de autorização vivem no Lake Formation, contra o usuário real: a função TIP que o Lambda assume não tem permissões de dados. O Lake Formation avalia a identidade propagada do usuário. Nenhum caminho de código no agente, gateway ou Lambda executa lógica de autorização.
- A trilha de auditoria não requer trabalho extra: o evento
AssumeRoleno CloudTrail comonBehalfOfidentifica o usuário humano em cada consulta — com a mesma fidelidade de auditoria que você teria para usuários humanos acessando dados diretamente.
Implantando o padrão
Para implantar esse padrão, quatro configurações são necessárias:
- Um provedor de identidade OIDC com um emissor de token confiável (TTI) no IAM Identity Center aceitando seus tokens, e um aplicativo OAuth no Identity Center configurado para
CreateTokenWithIAM. - Bedrock AgentCore Runtime rodando o container do agente com
requestHeaderAllowlistcobrindoAuthorizatione o cabeçalho customizado doid_token. - Bedrock AgentCore Gateway com um alvo Lambda cujo
metadataConfiguration.allowedRequestHeadersinclui o cabeçalho doid_token. O esquema de ferramenta do Lambda não tem parâmetro deid_token. - Lambda lendo o
id_tokendecontext.client_context.custom['bedrockAgentCorePropagatedHeaders'], realizando a troca de token viasso-oidc:CreateTokenWithIAM, e chamandosts:AssumeRolecomProvidedContextspara obter a sessão com TIP.
Conclusão
Quando um agente de IA consulta um lakehouse governado, a camada de dados precisa saber quem está perguntando — não qual função o agente está usando. A abordagem apresentada pela AWS resolve isso tratando o agente como um ator delegado OAuth. O token do usuário trafega junto ao transporte HTTP do agente, mas não entra no contexto do modelo. A troca de token que produz as credenciais de consulta acontece no servidor, dentro do Lambda, com escopo de uma única invocação.
As três funcionalidades do Bedrock AgentCore que tornam isso possível — requestHeaderAllowlist no runtime, metadataConfiguration.allowedRequestHeaders no gateway, e bedrockAgentCorePropagatedHeaders no Lambda — são específicas para construção sobre o Bedrock AgentCore. Tudo o que está abaixo do Lambda é funcionalidade do IAM Identity Center e do Lake Formation.
O resultado é uma separação limpa: a identidade do usuário trafega de ponta a ponta, o modelo nunca a vê, e a camada de dados a aplica exatamente como se o usuário tivesse consultado diretamente.
Recursos relacionados
- Propagação de Identidade Confiável com AWS IAM Identity Center
- Guia do usuário do AWS Lake Formation
- Cabeçalhos customizados do Amazon Bedrock AgentCore Runtime
- Propagação de cabeçalhos no Amazon Bedrock AgentCore Gateway
- RFC 7523 – Perfis JWT Bearer para OAuth 2.0
- Contrato de protocolo A2A do Amazon Bedrock AgentCore Runtime
Fonte
Identity-aware AI data agents with AWS Lake Formation and Trusted Identity Propagation (https://aws.amazon.com/blogs/security/identity-aware-ai-data-agents-with-aws-lake-formation-and-trusted-identity-propagation/)
Leave a Reply