Como propagar o contexto de autorização do usuário em agentes de IA com o Amazon Bedrock AgentCore

O problema: agentes de IA sem consciência de quem está perguntando

Times de engenharia que implantam agentes de IA frequentemente conectam esses agentes a tabelas do Amazon DynamoDB, repositórios de documentos, plataformas de Software como Serviço (SaaS) e bases de conhecimento internas. O risco central nesse cenário é que o agente, por padrão, não sabe quem está fazendo a pergunta — e pode acabar retornando dados que o usuário não deveria ver.

Para endereçar esse problema, a AWS publicou um guia técnico detalhado sobre como usar o Amazon Bedrock AgentCore para propagar o contexto de autorização do usuário por toda a cadeia de acesso a dados. A abordagem segue a boa prática AGENTSEC03 do AWS Well-Architected Agentic AI Lens.

O princípio central é direto: o agente atua como orquestrador, não como guardião. Ele coordena chamadas e raciocínio, mas quem decide o que cada usuário pode acessar são os serviços de infraestrutura subjacentes — não o código do agente.

Caso de uso: CRM com departamentos isolados

O guia usa como exemplo uma aplicação de chat para Gestão de Relacionamento com o Cliente (CRM), onde funcionários de Vendas e Financeiro interagem com o mesmo agente de IA para acessar informações de clientes. Embora a interface seja a mesma, cada departamento precisa de acesso isolado:

  • Vendas acessa contratos de clientes, estratégias de precificação e dados do pipeline de vendas.
  • Financeiro acessa faturas, registros de pagamento e relatórios financeiros.

O agente acessa três tipos de fontes de dados em nome dos usuários: registros de clientes no Amazon DynamoDB (particionados por departamento), documentos específicos por departamento no Amazon Bedrock Knowledge Bases (armazenados no Amazon Simple Storage Service — Amazon S3), e dados externos de CRM no Salesforce.

A regra é clara: quando um funcionário de Vendas pergunta “Mostre os contratos de clientes”, o agente deve retornar apenas contratos de Vendas — nunca faturas do Financeiro. E esse controle precisa acontecer fora do agente, para que mesmo em caso de comprometimento por injeção de prompt ou bugs, o acesso não autorizado seja bloqueado.

Visão geral da arquitetura

O fluxo de dados da arquitetura proposta funciona da seguinte forma:

  1. O usuário abre a aplicação web e se autentica com o Amazon Cognito user pool, que atua como Provedor de Identidade (IdP).
  2. Um gatilho Lambda de pré-geração de token (V2) enriquece os Tokens Web JSON (JWTs) com uma claim personalizada e metadados de session tag do AWS STS antes de retorná-los ao usuário.
  3. A aplicação web encaminha a requisição do usuário junto com o token de acesso para o agente implantado no Bedrock AgentCore Runtime.
  4. O AgentCore Runtime valida o JWT de entrada e, por meio do Bedrock AgentCore Identity, emite um token de acesso de workload que vincula as identidades do usuário e do agente.
  5. Para consultas que exigem documentos internos, o agente usa sua função do AWS Identity and Access Management (IAM) para consultar o Amazon Bedrock Knowledge Bases com filtragem de metadados, e o DynamoDB com credenciais temporárias com escopo de usuário via session tags.
  6. Para dados externos, o AgentCore Identity recupera credenciais do AWS Secrets Manager e realiza uma troca de token on-behalf-of (RFC 8693) com o Salesforce, retornando um token de acesso com escopo de usuário.
Imagem original — fonte: Aws

Autenticação inicial e enriquecimento do token

Quando o funcionário abre a aplicação, ele se autentica com suas credenciais corporativas usando o Amazon Cognito user pools como IdP. O gatilho Lambda de pré-geração de token (V2) captura o contexto de departamento do usuário e o adiciona tanto ao token de identidade (ID token) quanto ao token de acesso.

O token de acesso é usado pelo autorizador JWT personalizado do AgentCore Runtime para autorização de entrada. O ID token recebe a claim https://aws.amazon.com/tags, que é o formato específico exigido pelo AWS Security Token Service (AWS STS) para extrair session tags durante o AssumeRoleWithWebIdentity. Para mais detalhes, a AWS disponibiliza o guia Como personalizar tokens de acesso no Amazon Cognito user pools.

O código a seguir mostra a lógica principal dentro de uma função Lambda handler configurada como gatilho no Amazon Cognito user pool. Esse código roda automaticamente quando o usuário se autentica, extraindo o atributo de departamento e adicionando-o como uma claim personalizada em ambos os tokens:

import json
def lambda_handler(event, context):
    department = event['request']['userAttributes'].get('custom:department', '')
    event['response']['claimsAndScopeOverrideDetails'] = {
        'idTokenGeneration': {
            'claimsToAddOrOverride': {
                'department': department,
                'https://aws.amazon.com/tags': {
                    "principal_tags": {"department": [department]},
                    "transitive_tag_keys": ["department"]
                }
            }
        },
        'accessTokenGeneration': {
            'claimsToAddOrOverride': {
                'department': department
            }
        }
    }
    return event

Autorização de entrada pelo AgentCore Runtime

Quando a requisição chega ao AgentCore Runtime, o autorizador JWT de entrada realiza duas verificações: valida o token JWT com o Amazon Cognito (verificando assinatura criptográfica, expiração e emissor confiável) e extrai a claim de departamento do token validado, comparando-a com o valor esperado na configuração do autorizador. Qualquer token sem uma claim correspondente é rejeitado antes mesmo de o código do agente ser invocado.

Imagem original — fonte: Aws

O exemplo abaixo mostra a configuração do autorizador JWT de entrada. O campo inboundTokenClaimName é department, o inboundTokenClaimValueType declara o tipo como STRING_ARRAY, e o authorizingClaimMatchValue especifica os valores permitidos (["Sales", "Finance"]) com o operador CONTAINS_ANY:

authorizer_config = {
    "customJWTAuthorizer": {
        "discoveryUrl": discovery_url,
        "allowedClients": [client_id],
        "customClaims": [
            {
                "inboundTokenClaimName": "department",
                "inboundTokenClaimValueType": "STRING_ARRAY",
                "authorizingClaimMatchValue": {
                    "claimMatchValue": ["Sales", "Finance"]
                    "claimMatchOperator": "CONTAINS_ANY"
                }
            }
        ]
    }
}

Vale destacar que o AgentCore Runtime cria automaticamente uma identidade de workload para cada agente implantado. Essa identidade representa a identidade digital do agente no ambiente AWS, permitindo que ele mantenha identidade consistente ao usar funções IAM para acesso a recursos AWS, tokens OAuth 2.0 para integração com serviços externos, ou chaves de API para acesso a ferramentas de terceiros.

Padrão 1: Escopo de acesso ao DynamoDB por usuário

Para o acesso ao DynamoDB, a abordagem usa o AssumeRoleWithWebIdentity com session tags para criar credenciais com escopo de usuário por requisição. O agente passa o ID token assinado do usuário para o AWS STS, que extrai a tag de departamento da claim https://aws.amazon.com/tags e retorna credenciais temporárias restritas à partição de dados daquele departamento.

Isso move o controle de acesso do código do agente para a avaliação de políticas IAM. O STS também valida a claim de audiência (aud) do token contra a configuração do provedor OIDC do IAM, impedindo que tokens emitidos para outros clientes de aplicação sejam usados para assumir a função.

Como pré-requisito de configuração única, é necessário registrar o Amazon Cognito como um provedor OIDC no IAM e configurar a política de confiança da UserScopedDynamoDBRole para incluir as permissões sts:AssumeRoleWithWebIdentity e sts:TagSession:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Federated": "arn:aws:iam::111122223333:oidc-provider/cognito-idp.us-east-1.amazonaws.com/us-east-1_EXAMPLE"
    },
    "Action": [
      "sts:AssumeRoleWithWebIdentity",
      "sts:TagSession"
    ],
    "Condition": {
      "StringEquals": {
        "cognito-idp.us-east-1.amazonaws.com/us-east-1_EXAMPLE:aud": "<app-client-id>"
      }
    }
  }]
}

Por padrão, o AgentCore Runtime descarta cabeçalhos personalizados por segurança. Para permitir que o cabeçalho X-Id-Token chegue ao container do agente, é preciso configurá-lo no requestHeaderAllowlist do runtime:

request_header_config = {
    'requestHeaderAllowlist': ['X-Id-Token']
}

O código do agente para assumir a função com escopo de usuário é o seguinte:

def _scoped_dynamodb_resource(id_token: str):
    """Assume user-scoped role and return DynamoDB resource."""
    sts = boto3.client('sts')
    response = sts.assume_role_with_web_identity(
        RoleArn=USER_SCOPED_DYNAMODB_ROLE_ARN,
        RoleSessionName="agent-user-session",
        WebIdentityToken=id_token,
        DurationSeconds=900
    )
    creds = response['Credentials']
    session = boto3.Session(
        aws_access_key_id=creds['AccessKeyId'],
        aws_secret_access_key=creds['SecretAccessKey'],
        aws_session_token=creds['SessionToken']
    )
    return session.resource('dynamodb')

O AWS STS extrai a claim https://aws.amazon.com/tags e cria uma sessão com aws:PrincipalTag/department definido. A política de permissão na função usa a condição dynamodb:LeadingKeys vinculada a essa tag, garantindo que apenas a partição do departamento do usuário seja acessível — e esse controle acontece na camada de política IAM, não no código do agente:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": ["dynamodb:GetItem", "dynamodb:Query"],
    "Resource": "arn:aws:dynamodb:us-east-1:111122223333:table/CustomerRecords",
    "Condition": {
      "ForAllValues:StringEquals": {
        "dynamodb:LeadingKeys": ["${aws:PrincipalTag/department}"]
      }
    }
  }]
}

Padrão 2: Autorização com escopo de usuário no Amazon Bedrock Knowledge Bases

Para documentos armazenados no Amazon Bedrock Knowledge Bases, o agente aplica filtragem de metadados no momento da consulta. Cada documento é marcado com um atributo de metadados Department durante a ingestão. Os arquivos de metadados ficam no Amazon S3 com o mesmo nome do arquivo-fonte e sufixo .metadata.json:

{"metadataAttributes": {"Department": "Sales"}}

Quando o agente consulta o Amazon Bedrock Knowledge Bases, ele chama a ação bedrock:Retrieve e adiciona o filtro de configuração de recuperação com escopo para o departamento do usuário. O valor do departamento é extraído do token de acesso JWT recebido durante a autorização de entrada:

response = client.retrieve(
    knowledgeBaseId=KNOWLEDGE_BASE_ID,
    retrievalQuery={"text": user_query},
    retrievalConfiguration={
        "vectorSearchConfiguration": {
            "filter": {"equals": {"key": "Department", "value": department}}
        }
    }
)

Importante: a filtragem de metadados é um controle na camada de aplicação. A API bedrock:Retrieve não expõe o conteúdo do filtro de metadados como uma chave de condição IAM. Para isolamento mais rigoroso, a AWS recomenda considerar bases de conhecimento separadas por departamento com políticas IAM em nível de recurso.

Padrão 3: Acesso a serviços externos via troca de token on-behalf-of

Para serviços externos como o Salesforce, que não suportam controle de acesso baseado em IAM, é necessário um mecanismo diferente para propagar a identidade do usuário. A troca de token On-Behalf-Of (OBO) do AgentCore Identity (RFC 8693) resolve isso trocando a identidade autenticada do usuário por um token com escopo de usuário que o serviço externo reconhece e aplica nativamente.

O guia compara três padrões OAuth suportados pelo AgentCore Identity para acesso a serviços externos:

  • Client Credentials — OAuth de Duas Pernas (2LO) ou máquina a máquina (M2M): o agente autentica como conta de serviço e recebe um token com acesso amplo. Adequado para dados organizacionais não vinculados a um usuário individual. Veja mais em Empower AI agents with user context using Amazon Cognito.
  • Authorization Code — OAuth de Três Pernas (3LO): o usuário consente explicitamente via redirecionamento no navegador. Funciona quando é necessário consentimento por serviço, mas exige interação do usuário, o que é impraticável para operações em segundo plano. Veja mais em Secure AI agents with Amazon Bedrock AgentCore Identity on Amazon ECS.
  • Troca de token OBO: a identidade já autenticada do usuário é trocada por um token com escopo de serviço sem interação adicional do usuário, e o serviço externo aplica o controle de acesso. É o padrão mais adequado para este caso de uso.

O OBO propaga a identidade do usuário de ponta a ponta sem que o agente armazene credenciais, escala automaticamente sem armazenamento de token por usuário, e permite que serviços downstream apliquem sua própria autorização (regras de compartilhamento, Controle de Acesso Baseado em Função — RBAC).

Imagem original — fonte: Aws

O código do agente usa o decorator @requires_access_token para invocar o fluxo OBO:

@requires_access_token(
    provider_name="salesforce-token-exchange",
    scopes=[],
    auth_flow="ON_BEHALF_OF_TOKEN_EXCHANGE",
)
def _get_salesforce_token_sync(*, access_token: str) -> str:
    return access_token

No Salesforce, é necessário registrar o Amazon Cognito como provedor de autenticação OpenID Connect, configurar um handler de troca de token (classe Apex estendendo Auth.Oauth2TokenExchangeHandler) que resolve usuários pelo FederationIdentifier, e configurar regras de compartilhamento para acesso com escopo de departamento. O ID de federação (sub) é imutável e não pode ser forjado pelo agente, pois origina do token de identidade assinado criptograficamente.

Como resultado, nenhum filtro de departamento é necessário na consulta Salesforce Object Query Language (SOQL) — as regras de compartilhamento do Salesforce aplicam o controle de acesso nativamente:

@tool
def query_salesforce_opportunities(query_text: str) -> str:
    access_token = _get_salesforce_token_sync()
    # No department filter needed. Salesforce sharing rules enforce access.
    soql = "SELECT Id, Name, Amount, StageName, CloseDate FROM Opportunity ORDER BY CloseDate DESC LIMIT 10"
    response = requests.get(
        f"{SALESFORCE_URL}/services/data/v59.0/query?q={urllib.parse.quote(soql)}",
        headers={"Authorization": f"Bearer {access_token}"},
        timeout=30,
    )
    return json.dumps(response.json().get("records", []))

Conclusão e próximos passos

A arquitetura apresentada pela AWS demonstra como implementar autorização consistente de ponta a ponta em aplicações de IA agêntica, propagando o contexto do usuário do Amazon Cognito pelo Amazon Bedrock AgentCore até os recursos downstream. Os três padrões cobertos são:

  • Credenciais temporárias com escopo de usuário por requisição usando AssumeRoleWithWebIdentity com session tags, avaliadas por políticas IAM de Controle de Acesso Baseado em Atributos (ABAC) para acesso ao Amazon DynamoDB.
  • Filtragem de metadados com escopo de departamento na camada de aplicação para acesso ao Amazon Bedrock Knowledge Bases.
  • Troca de token on-behalf-of (RFC 8693) usando o AgentCore Identity, com regras de compartilhamento nativas do Salesforce governando o acesso a dados externos de CRM.

O ponto central é que o agente coordena o trabalho, mas não decide quem pode acessar o quê. As decisões de acesso são tomadas por controles de infraestrutura e pelo modelo de autorização dos serviços downstream. Essa abordagem em camadas garante que, mesmo que o agente se comporte de forma inesperada, o acesso não autorizado a dados ainda seja bloqueado.

Para explorar mais, a AWS disponibiliza os seguintes recursos:

Fonte

Propagate user authorization context in AI agents with Amazon Bedrock AgentCore (https://aws.amazon.com/blogs/security/propagate-user-authorization-context-in-ai-agents-with-amazon-bedrock-agentcore/)

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *