Category: Uncategorized

  • Amazon Cognito ganha novas capacidades com infraestrutura de nova geração

    O que mudou no Amazon Cognito

    O Amazon Cognito acaba de receber um conjunto significativo de melhorias — e o que torna essa história interessante é que elas só foram possíveis graças a uma reformulação profunda da infraestrutura interna do serviço. A AWS migrou centenas de milhões de perfis de usuário para uma nova camada de armazenamento, e a grande maioria dos clientes simplesmente não percebeu que isso aconteceu.

    Neste artigo, a CloudTroop explica o que foi anunciado, como a nova arquitetura funciona por baixo dos panos e quais lições a própria AWS compartilhou sobre esse processo de modernização em larga escala.

    Novas capacidades disponíveis no Cognito

    A migração para a nova infraestrutura não foi apenas uma questão de manutenção técnica — ela criou a base para entregar funcionalidades que resolvem problemas reais dos clientes. Três capacidades se destacam:

    Alto desempenho para cargas de trabalho exigentes

    A nova arquitetura suporta volumes de requisições muito maiores, mantendo a baixa latência que as aplicações modernas exigem. O serviço agora é capaz de suportar dezenas de milhões de usuários por user pool e milhares de transações por segundo (TPS). Isso atende diretamente às demandas de aplicações em escala que antes encontravam limitações no Cognito.

    Chaves gerenciadas pelo cliente

    Com as chaves gerenciadas pelo cliente, agora é possível usar chaves de criptografia próprias, armazenadas no Serviço de Gerenciamento de Chaves da AWS (AWS KMS), para criptografar dados em repouso. Isso oferece controle aprimorado de segurança e dá ao cliente a propriedade total sobre o ciclo de vida das suas chaves de criptografia — um requisito frequente em ambientes regulados e com políticas de conformidade mais rígidas.

    Replicação multi-região

    A replicação multi-região permite que os clientes sincronizem todos os dados do seu user pool — incluindo senhas, atributos e configurações — com outro user pool em uma região de sua escolha. Com isso, é possível implementar estratégias de continuidade de negócios e manter a disponibilidade da autenticação mesmo em caso de falha regional, garantindo que as aplicações continuem acessíveis aos usuários durante interrupções inesperadas.

    A arquitetura por trás da inovação

    A nova infraestrutura do Cognito usa uma camada de armazenamento desenvolvida especificamente para operações de identidade, com foco em extensibilidade e escala. A AWS ancorou as decisões arquiteturais em três princípios orientadores:

    • Design centrado em identidade: a camada de armazenamento entende identidades de usuário. Não há lógica de negócio específica de cliente nem generalizações além do gerenciamento de identidade, mantendo o sistema focado, portátil e otimizado.
    • Evitar decisões irreversíveis: entregar valor de forma incremental, mantendo as escolhas arquiteturais reversíveis para que o serviço possa evoluir conforme novas necessidades surjam.
    • Compatibilidade retroativa: mudanças na infraestrutura subjacente jamais devem quebrar as aplicações dos clientes.

    Esses princípios moldaram cada decisão arquitetural do projeto. A nova arquitetura separa o sistema em domínios implantáveis de forma independente. Anteriormente, enquanto o serviço usava o Amazon Cloud Directory, a arquitetura dependia de um único armazenamento de dados para persistir todas as informações dos clientes. Essa abordagem oferecia mecanismos diretos de travessia de dados, mas exigia coordenação entre múltiplos serviços para ajustar o esquema do banco de dados sempre que novos recursos eram necessários.

    A nova arquitetura utiliza conjuntos de dados distintos, permitindo que cada um evolua de forma independente e acelerando as iterações de novas funcionalidades.

    Migração com zero tempo de inatividade

    Migrar usuários em escala exige cuidados extremos. A estratégia adotada pela AWS priorizou tanto a estabilidade imediata quanto a flexibilidade de longo prazo, por meio de quatro camadas de proteção:

    Validação em modo sombra

    As requisições de API dos clientes foram executadas simultaneamente nas infraestruturas antiga e nova, com comparação de estruturas de resposta, códigos de status e características comportamentais. A validação foi projetada para que informações sensíveis nunca ficassem expostas em texto simples durante as comparações. Variações conhecidas — como pequenas diferenças em timestamps — foram contabilizadas para que apenas discrepâncias significativas gerassem alertas acionáveis.

    Preenchimento retroativo de dados

    Antes de migrar um user pool para a nova infraestrutura, a AWS realizou um preenchimento em massa de todos os registros de usuários existentes do sistema legado para o novo armazenamento. Esse processo ocorreu em paralelo com o tráfego em produção, com uma arquitetura de escrita dupla capturando qualquer alteração feita durante a janela de migração — garantindo que nenhum dado fosse perdido ou ficasse desatualizado.

    Arquitetura de escrita dupla

    Todas as operações de identidade foram escritas simultaneamente nos sistemas legado e novo, com validação abrangente para garantir consistência. Mesmo quando uma escrita dupla para a nova infraestrutura falhava, a operação ainda era concluída com sucesso no sistema legado, preservando todas as requisições iniciadas pelos clientes. Isso significa que qualquer falha na escrita dupla era contida como um problema interno de consistência, sem impacto para o cliente.

    Validação anti-entropia

    Foi implementado um sistema de validação e correção de dados que comparava continuamente os registros entre as infraestruturas antiga e nova, detectando e resolvendo qualquer divergência. As varreduras comparavam atributos de usuário, hashes de credenciais, associações a grupos e configurações, entre outros registros. Quando discrepâncias reais eram encontradas, o sistema as reconciliava automaticamente usando o sistema legado como fonte de verdade. Essa camada conseguiu capturar casos extremos que o modo sombra e as escritas duplas, por si só, não cobriam.

    Implantação incremental com capacidade de reversão

    Foram estabelecidas fases de implantação controladas com capacidade de reversão imediata. Após migrar um user pool para a nova infraestrutura, a AWS continuou replicando todas as escritas de volta para o sistema legado, garantindo a possibilidade de reverter qualquer user pool à infraestrutura anterior a qualquer momento, sem perda de dados. Se uma reversão fosse necessária durante a migração, um orquestrador reproduzia as entradas em ordem cronológica, sincronizando os perfis de usuário de volta ao sistema legado.

    Lições aprendidas para modernização de infraestrutura

    A AWS optou por compartilhar os aprendizados desse processo de modernização, reconhecendo que os princípios se aplicam a qualquer projeto de infraestrutura em larga escala. Três lições se destacam:

    Padrões de acesso dos clientes guiam as decisões de arquitetura

    A análise dos padrões reais de acesso dos clientes revelou que cargas de trabalho de identidade seguem padrões previsíveis. Isso permitiu adotar uma abordagem de escrita dupla síncrona que equilibrou completude com simplicidade operacional. O princípio se aplica a qualquer migração específica de domínio: entenda os padrões de acesso reais da sua carga de trabalho antes de escolher soluções de uso geral.

    Preservar o comportamento exige técnicas além dos testes tradicionais

    Garantir funcionalidade equivalente entre sistemas antigos e novos foi relativamente simples. Preservar o comportamento idêntico da API foi muito mais desafiador. Testes funcionais validam comportamentos intencionais, mas a AWS identificou cenários em que clientes haviam construído aplicações em torno de comportamentos específicos da API — de modo que uma mudança poderia ter quebrado silenciosamente essas aplicações.

    Por exemplo, escritas concorrentes para o mesmo usuário poderiam resultar em estados finais diferentes entre os sistemas, mesmo com todas as escritas sendo bem-sucedidas. Da mesma forma, clientes que escrevem um atributo e imediatamente o leem são afetados pela janela de consistência — diferenças sutis de tempo em quando as atualizações se tornam visíveis podem causar leituras de dados desatualizados. Esses não são falhas funcionais, mas o comportamento sob padrões de tráfego real pode variar. A verificação em modo sombra revelou casos extremos que testes automatizados sozinhos não teriam detectado.

    Validação gradual constrói confiança que testes sozinhos não conseguem

    A recomendação da AWS é usar múltiplas técnicas de validação independentes em camadas — como modo sombra, escritas duplas e varreduras anti-entropia — cada uma cobrindo um padrão de acesso diferente. Nenhuma abordagem isolada captura tudo, e é justamente nas lacunas entre elas que os problemas em produção se escondem. A implantação incremental com capacidade de reversão imediata permite validar cada etapa enquanto mantém a habilidade de reverter rapidamente.

    O que isso significa na prática

    A nova infraestrutura do Cognito já está em produção. As capacidades como chaves gerenciadas pelo cliente e replicação multi-região estão disponíveis agora. À medida que a migração avança, todos os clientes do Cognito terão acesso a essas funcionalidades no mesmo serviço que já utilizam hoje, sem necessidade de nenhuma ação da parte deles.

    Para equipes que gerenciam autenticação em aplicações de grande escala, reguladas ou com requisitos de alta disponibilidade, essas mudanças representam um salto relevante nas possibilidades do serviço. Vale revisar as configurações de criptografia e avaliar se a replicação multi-região faz sentido para a estratégia de continuidade de negócios da sua organização.

    Para saber mais, acesse a página oficial do Amazon Cognito.

    Fonte

    Amazon Cognito unlocks advanced capabilities with next-generation infrastructure (https://aws.amazon.com/blogs/security/amazon-cognito-unlocks-advanced-capabilities-with-next-generation-infrastructure/)

  • Visibilidade total em ataques DDoS com flow logs no AWS Shield Advanced

    O problema que os flow logs resolvem

    Reconstruir o tráfego de um ataque de negação de serviço distribuído — Distributed Denial of Service (DDoS) — costumava ser um trabalho de arqueologia: você combinava dados de múltiplas fontes depois que o estrago já havia acontecido. A AWS mudou essa dinâmica com os attack flow logs do Shield Advanced, que capturam metadados de tráfego durante os ataques, permitindo identificar origens, confirmar se as mitigações funcionaram e alimentar os pipelines de análise que você já usa.

    Os logs são publicados no Amazon Simple Storage Service (Amazon S3), no Amazon CloudWatch Logs ou no Amazon Data Firehose, usando a mesma infraestrutura de entrega do CloudWatch Logs que outros flow logs da AWS já utilizam. Isso significa que eles se encaixam diretamente nas ferramentas de monitoramento e análise que você já tem em operação.

    Como ataques DDoS afetam suas aplicações

    Um ataque DDoS inunda uma aplicação com tráfego até torná-la indisponível para os usuários. Ataques na camada de infraestrutura saturam a banda disponível e esgotam as tabelas de conexão — o resultado prático são perdas de pacotes e timeouts.

    O AWS Shield Advanced é um serviço gerenciado de proteção contra DDoS que detecta e mitiga ataques para os seguintes recursos: distribuições do Amazon CloudFront, balanceadores de carga do Elastic Load Balancing, zonas hospedadas do Amazon Route 53, aceleradores padrão do AWS Global Accelerator e endereços Elastic IP (EIP). Consulte a documentação do AWS Shield Advanced para ver a lista completa de recursos suportados.

    Inicialmente, a AWS disponibilizou os flow logs de ataques na camada de infraestrutura para proteções de EIP, com suporte a outros tipos de recursos previsto para o futuro.

    Principais benefícios dos flow logs

    Os flow logs ajudam as equipes de segurança de várias formas práticas:

    • Reconstruir padrões de tráfego: é possível consultar os logs após um ataque para analisar volume, distribuição de origens e mix de protocolos, sem depender apenas das métricas agregadas do CloudWatch.
    • Identificar origens dos ataques: os campos srccountry e location mostram de onde o tráfego se originou e por qual localização de borda da AWS ele entrou.
    • Verificar o comportamento de mitigação: o campo action registra o que o Shield fez com cada fluxo de tráfego.

    Os logs podem ser enviados para o Amazon S3, CloudWatch Logs ou Data Firehose. A partir daí, você pode consultá-los com o Amazon Athena (serviço serverless de consulta de dados no S3), encaminhá-los para plataformas de Gerenciamento de Informações e Eventos de Segurança — Security Information and Event Management (SIEM) de terceiros — ou criar consultas no CloudWatch Logs Insights, tudo isso sem precisar implantar nenhuma infraestrutura nova.

    O que os attack flow logs capturam

    Cada registro de log captura endereços IP de origem e destino, portas, protocolo, contagem de pacotes e bytes, a ação tomada pelo Shield Advanced, flags TCP, a localização de entrada na AWS e um código de país de duas letras para a origem do tráfego (quando disponível).

    Os logs são gravados em intervalos de 5 minutos e ficam disponíveis tanto durante um ataque ativo quanto após sua conclusão. O tamanho máximo de cada arquivo é 75 MB. Se esse limite for atingido dentro da janela de 5 minutos, o arquivo é fechado, publicado e um novo arquivo começa a ser gravado.

    Os flow logs suportam os formatos de saída JSON, texto simples, W3C e Parquet. Os campos disponíveis em cada registro são:

    • protection_arn — Nome de Recurso da Amazon (ARN) da proteção do Shield
    • event_timestamp — Timestamp de geração do log
    • version — Versão do flow log
    • srcaddr — Endereço IP de origem
    • dstaddr — Endereço IP de destino
    • srcport — Porta de origem
    • dstport — Porta de destino
    • protocol — Número do protocolo IP
    • packets — Contagem de pacotes na janela de agregação
    • bytes — Contagem de bytes na janela de agregação
    • starttime — Início da janela de agregação
    • endtime — Fim da janela de agregação
    • action — Ação tomada pelo Shield
    • location — Localização de entrada na AWS
    • sampling_rate — Taxa de amostragem usada no processamento de pacotes
    • tcp_flags — Flags TCP do pacote
    • srccountry — Código de país de duas letras para a origem do tráfego

    Como configurar os flow logs para proteções do Shield Advanced

    A seguir, o passo a passo para criar os recursos de entrega do CloudWatch Logs que conectam uma proteção do Shield Advanced ao destino de log de sua preferência.

    Pré-requisitos

    Antes de configurar os flow logs, certifique-se de ter:

    Os flow logs incorrem nas cobranças padrão de vended logs do CloudWatch Logs, e os recursos de destino (armazenamento em bucket S3, grupo de logs do CloudWatch Logs ou processamento de dados no Firehose) têm cobranças separadas. Revise a entrada de Vended Logs na página de preços do CloudWatch e os preços do serviço de destino escolhido antes de habilitar os flow logs em recursos de alto tráfego.

    Como funciona a entrega de logs

    A entrega de logs requer três objetos:

    • DeliverySource — Representa a proteção do Shield Advanced que produz os logs
    • DeliveryDestination — Representa para onde os logs devem ser enviados (Amazon S3, CloudWatch Logs ou Amazon Data Firehose)
    • Delivery — Conecta a origem ao destino

    Esse modelo de três objetos permite reutilizar destinos em múltiplas origens e gerenciar pipelines de entrega de forma independente. Por exemplo, é possível enviar logs de múltiplas proteções do Shield para o mesmo bucket S3 criando múltiplos objetos DeliverySource que referenciam o mesmo DeliveryDestination.

    Como os attack flow logs do Shield Advanced usam a infraestrutura de entrega do CloudWatch Logs, eles podem ser agregados entre contas e regiões assim como outros vended logs. É possível entregar diretamente para um bucket S3 centralizado com política cross-account, replicar grupos de logs do CloudWatch usando regras de centralização cross-account e cross-Region, ou transmitir para um stream compartilhado do Firehose usando assinaturas cross-account.

    Passo 1: Criar o recurso de destino

    Escolha um destino:

    Passo 2: Configurar a política do recurso de destino (se necessário)

    O recurso de destino precisa de uma política que conceda permissões de escrita ao serviço de entrega do CloudWatch Logs. A política varia conforme o tipo de destino. Para mais informações, consulte Logs enviados ao Amazon S3, Logs enviados ao CloudWatch Logs ou Logs enviados ao Firehose.

    Para destinos no Amazon S3, há duas opções: criação automática de política (se o bucket não tiver política de recurso existente e você tiver as permissões s3:GetBucketPolicy e s3:PutBucketPolicy, a AWS cria a política necessária automaticamente ao criar a entrega no passo 6) ou atualização manual da política (se precisar customizá-la ou se sua organização exigir políticas pré-aprovadas, siga as instruções em Logs enviados ao Amazon S3).

    Passo 3: Obter o ARN da proteção

    O Shield Advanced é um serviço global e usa a região us-east-1 para gerenciamento. Execute o comando abaixo para listar suas proteções do Shield Advanced:

    aws shield list-protections \
    --region us-east-1

    Na saída, copie o valor de ProtectionArn da proteção que você deseja registrar.

    Passo 4: Criar a origem de entrega (DeliverySource)

    Execute o comando abaixo para criar a origem de entrega, substituindo <protection-arn> pelo valor de ProtectionArn obtido no passo 3:

    aws logs put-delivery-source \
    --name my-shield-delivery-source \
    --resource-arn <protection-arn> \
    --log-type FLOW_LOGS \
    --region us-east-1

    O parâmetro --resource-arn é o ARN da proteção do Shield Advanced — não o do recurso protegido em si. O Shield Advanced cria um objeto de proteção separado que envolve seu recurso, e os flow logs são gerados por essa camada de proteção, não pelo recurso subjacente.

    Passo 5: Criar o destino de entrega (DeliveryDestination)

    Execute o comando abaixo para criar o destino de entrega, substituindo <resource-arn> pelo ARN do recurso de destino criado no passo 1:

    aws logs put-delivery-destination \
    --name my-shield-delivery-destination \
    --output-format plain \
    --delivery-destination-configuration '{"destinationResourceArn":"<resource-arn>"}' \
    --region us-east-1

    O parâmetro --delivery-destination-configuration recebe um objeto JSON com a chave destinationResourceArn, cujo valor é o ARN do seu bucket S3, grupo de logs ou stream do Firehose. Na saída, copie o valor do campo ARN de nível superior — este é o ARN do destino de entrega (diferente do ARN do bucket). Você usará esse valor no passo 6.

    Passo 6: Criar a entrega (Delivery)

    Execute o comando abaixo para conectar a origem ao destino, substituindo <delivery-destination-arn> pelo ARN do destino de entrega obtido no passo 5:

    aws logs create-delivery \
    --delivery-source-name my-shield-delivery-source \
    --delivery-destination-arn <delivery-destination-arn> \
    --region us-east-1

    Passo 7: Verificar a entrega

    Execute o comando abaixo para confirmar que a entrega está ativa:

    aws logs describe-deliveries \
    --region us-east-1

    Após a entrega estar ativa, o Shield Advanced publica registros de flow logs no seu destino durante eventos de DDoS.

    Limpeza dos recursos

    Para evitar cobranças contínuas, exclua os recursos criados seguindo a ordem abaixo.

    Exclua a entrega:

    aws logs delete-delivery \
    --id <delivery-id> \
    --region us-east-1

    Exclua a origem de entrega:

    aws logs delete-delivery-source \
    --name my-shield-delivery-source \
    --region us-east-1

    Exclua o destino de entrega:

    aws logs delete-delivery-destination \
    --name my-shield-delivery-destination \
    --region us-east-1

    Opcionalmente, faça backup dos dados de flow log se precisar retê-los para conformidade ou análise. Em seguida, exclua o recurso de destino.

    Atenção: excluir o recurso de destino apagará permanentemente todos os dados de flow log.

    Para um bucket S3:

    aws s3 rb s3://<bucket-name> \
    --force \
    --region <region>

    Para um grupo de logs do CloudWatch Logs:

    aws logs delete-log-group \
    --log-group-name <log-group-name> \
    --region <region>

    Para um stream do Firehose:

    aws firehose delete-delivery-stream \
    --delivery-stream-name <stream-name> \
    --region <region>

    Próximos passos

    Com os flow logs habilitados nas proteções do Shield Advanced, a AWS recomenda explorar as seguintes possibilidades para aprofundar a análise:

    Para a referência completa sobre configuração de flow logs, consulte a documentação do AWS Shield Advanced.

    Fonte

    Gain visibility into DDoS attacks with flow logs in AWS Shield Advanced (https://aws.amazon.com/blogs/security/gain-visibility-into-ddos-attacks-with-flow-logs-in-aws-shield-advanced/)

  • Amazon Cognito passa a suportar replicação multi-região

    O que mudou no Amazon Cognito

    A AWS anunciou uma novidade importante para quem usa o Amazon Cognito como base de autenticação: o serviço agora suporta replicação multi-região. Isso significa que é possível sincronizar dados de identidade de usuários e máquinas — incluindo credenciais, configurações do user pool e integrações de federação — para um user pool secundário em uma região de standby designada, em tempo quase real.

    Como funciona na prática

    A lógica é simples: você mantém um user pool principal em uma região e configura uma réplica em outra região de standby. Se houver uma interrupção na região primária, o tráfego pode ser redirecionado para o user pool secundário sem que os usuários precisem se autenticar novamente.

    Usuários que já estavam com sessão ativa continuam acessando suas aplicações normalmente. Usuários já cadastrados conseguem fazer login com as mesmas credenciais existentes. Não há impacto visível para o usuário final durante o processo de failover.

    Métodos de autenticação suportados na região secundária

    Todos os principais métodos de autenticação continuam funcionando na região de standby, incluindo:

    • Usuário e senha tradicionais
    • Federação com provedores de identidade social
    • Federação via SAML e OIDC (Linguagem de Marcação para Asserções de Segurança e Conexão OpenID)
    • Fluxos de autorização máquina a máquina

    Disponibilidade e regiões suportadas

    A replicação multi-região está disponível como um complemento pago para user pools nos planos de funcionalidades Essentials ou Plus. O recurso já está ativo nas seguintes regiões da AWS:

    • EUA Leste (Ohio e Norte da Virgínia)
    • EUA Oeste (Norte da Califórnia e Oregon)
    • Ásia-Pacífico (Mumbai, Seul, Singapura, Sydney e Tóquio)
    • Canadá (Central)
    • Europa (Frankfurt, Irlanda, Londres, Paris e Estocolmo)
    • América do Sul (São Paulo)

    A região de São Paulo já está incluída desde o lançamento, o que é uma boa notícia para equipes brasileiras que precisam de alta disponibilidade com conformidade de dados no país.

    Como começar a usar

    Para ativar a replicação multi-região, basta adicionar um user pool réplica usando o Console de Gerenciamento da AWS, a Interface de Linha de Comando (CLI) da AWS ou os Kits de Desenvolvimento de Software (SDKs) da AWS. Consulte a página de preços para detalhes de custos e o guia do desenvolvedor para instruções de configuração.

    Fonte

    Amazon Cognito now supports multi-Region replication (https://aws.amazon.com/about-aws/whats-new/2026/06/amazon-cognito-multi-region/)

  • Personalize o login federado com o novo trigger Lambda do Amazon Cognito

    O desafio da federação de identidades

    O Amazon Cognito já permite que aplicações web e mobile autentiquem usuários de diversas formas: contas gerenciadas com senha, fluxos sem senha ou por meio de provedores de identidade (IdP) externos via SAML, OIDC (OpenID Connect) e provedores sociais como Google, Facebook, Apple e Login with Amazon.

    Para o usuário final, a federação significa menos senhas para lembrar e uma experiência de login mais fluida. Para fornecedores de Software como Serviço (SaaS) no modelo B2B (Business-to-Business), significa que os clientes corporativos mantêm o controle sobre suas próprias identidades. Mas a federação também traz desafios reais para desenvolvedores e equipes de segurança.

    O que acontece quando o provedor SAML de um cliente corporativo envia centenas de grupos que ultrapassam os limites de tamanho de atributos? Ou quando um usuário de e-commerce esquece que já tem uma conta e tenta entrar com um provedor social diferente, criando registros duplicados? Para resolver exatamente esses cenários, a AWS anunciou o inbound federation Lambda trigger para o Amazon Cognito.

    Como funciona o inbound federation Lambda trigger

    Esse trigger do AWS Lambda é invocado logo após o Amazon Cognito receber e validar a resposta do provedor de identidade externo. Nesse ponto, antes de qualquer criação ou atualização de perfil no user pool, a função Lambda recebe o payload com os dados do usuário e pode adicionar, modificar ou suprimir atributos conforme a necessidade da aplicação.

    O payload enviado à função Lambda inclui os parâmetros comuns dos triggers do Cognito (como userPoolId e clientId), o nome e o tipo do provedor externo utilizado (providerName e providerType), além dos atributos do usuário vindos do IdP. O formato desses atributos varia conforme o tipo de provedor: para SAML, chegam como um mapeamento JSON de chave-valor da asserção; para OIDC ou provedores sociais, chegam os tokens de acesso e os dados do endpoint /userinfo. Mais detalhes sobre os parâmetros do trigger estão disponíveis na documentação oficial.

    O fluxo completo funciona assim: o usuário acessa a aplicação, seleciona o IdP desejado na tela de login gerenciado (ou o cliente passa o parâmetro identity_provider diretamente), o Cognito encaminha a requisição ao IdP externo, o usuário se autentica, o IdP responde ao Cognito, que valida a assinatura criptográfica — e só então invoca o Lambda. Os atributos retornados pela função são mapeados para o perfil do usuário. Na sequência, o fluxo OAuth 2.0 continua normalmente com a emissão dos tokens. Vale lembrar que é uma boa prática de segurança usar clientes confidenciais (confidential clients) e a extensão Prova de Chave para Troca de Código (PKCE) sempre que possível.

    Casos de uso práticos

    Caso de uso 1: Filtragem de atributos de grupo excessivos (B2B)

    Em aplicações B2B e SaaS, é comum usar os grupos do IdP para determinar o nível de acesso do usuário dentro do serviço. O problema é que clientes corporativos podem inadvertidamente enviar todos os grupos do Active Directory a que um usuário pertence — o que pode chegar a centenas. Se esse atributo for mapeado para um atributo do Cognito, o limite de 2.048 caracteres por atributo pode ser facilmente ultrapassado, causando falha na autenticação.

    Outro problema comum é a inconsistência de formato: o mesmo grupo pode chegar como nome canônico (example.com/groups/myApp-readOnly), nome distinto (distinguished name, como cn=myApp-readOnly,OU=groups,DC=example,DC=com) ou texto simples (myApp-readOnly). Antes desse trigger, a solução exigia coordenação com o departamento de TI do cliente para modificar a configuração SAML na origem — um processo que podia levar semanas.

    Com o inbound federation Lambda trigger, é possível resolver isso programaticamente. O exemplo de código abaixo filtra o atributo de grupos para incluir apenas os relevantes para a aplicação e normaliza os diferentes formatos de nome:

    // Configure the group prefix to filter on (e.g. "App1-", "myApp-", etc.)
    // Change this to match the prefix your IdP uses for relevant group names.
    const GROUP_PREFIX = process.env.GROUP_PREFIX || 'myApp-';
    
    // The SAML attribute/claim name that contains group membership.
    // Common values: "groups", "memberOf", "http://schemas.xmlsoap.org/claims/Group", etc.
    const GROUP_ATTRIBUTE = process.env.GROUP_ATTRIBUTE || 'groups';
    
    /**
     * Extracts the short group name from common IdP formats:
     * - Plain text: "myApp-readOnly"
     * - Leading slash: "/myApp-readOnly"
     * - Canonical/URL: "example.com/groups/myApp-readOnly"
     * - Distinguished name (DN): "cn=myApp-readOnly,OU=groups,DC=example,DC=com"
     * Returns the last meaningful segment so all formats normalize to "myApp-readOnly".
     */
    function extractGroupName(raw) {
      let name = raw.trim();
      // Some IdPs prefix group names with "/" to indicate a top level group — strip it before format detection
      if (name.startsWith('/')) {
        name = name.substring(1);
      }
      // DN format — extract the CN (common name) value
      if (/^cn=/i.test(name) || /,\s*(ou|dc)=/i.test(name)) {
        const cnMatch = name.match(/^cn=([^,]+)/i);
        return cnMatch ? cnMatch[1].trim() : name;
      }
      // URL / path format — take the last segment after the final "/"
      if (name.includes('/')) {
        const segments = name.split('/').filter(Boolean);
        return segments[segments.length - 1];
      }
      return name;
    }
    
    export const handler = async (event) => {
      try {
        console.log('Full event:', JSON.stringify(event, null, 2));
        console.log('Provider type:', event.request?.providerType);
    
        // Initialize the response structure
        event.response = event.response || {};
    
        if (event.request?.providerType?.toLowerCase() === "saml") {
          const samlResponse = event.request.attributes?.samlResponse;
    
          if (samlResponse) {
            console.log('Original SAML Attributes:', JSON.stringify(samlResponse, null, 2));
    
            // Build the attribute map — you MUST include every attribute you want Cognito to retain. Anything omitted from userAttributesToMap is dropped.
            const mappedAttributes = {};
    
            Object.keys(samlResponse).forEach(key => {
              if (key === GROUP_ATTRIBUTE) {
                // Parse the groups JSON string from the SAML assertion
                let groupsArray = [];
                try {
                  groupsArray = JSON.parse(samlResponse[GROUP_ATTRIBUTE]);
                } catch (error) {
                  console.error(`Error parsing ${GROUP_ATTRIBUTE}:`, error);
                }
    
                // Normalize each group name, then filter to the configured prefix
                const normalizedGroups = groupsArray.map(extractGroupName);
                const filteredGroups = normalizedGroups.filter(group =>
                  group.startsWith(GROUP_PREFIX)
                );
    
                console.log(`Original ${GROUP_ATTRIBUTE}:`, groupsArray);
                console.log(`Normalized ${GROUP_ATTRIBUTE}:`, normalizedGroups);
                console.log(`Filtered ${GROUP_ATTRIBUTE}:`, filteredGroups);
    
                // Only include the groups attribute if there are matching groups
                if (filteredGroups.length > 0) {
                  mappedAttributes[GROUP_ATTRIBUTE] = filteredGroups.map(group => `'${group}'`).join(', ');
                }
              } else {
                // Pass all other SAML attributes through unchanged
                mappedAttributes[key] = samlResponse[key];
              }
            });
    
            event.response.userAttributesToMap = mappedAttributes;
            console.log('Response to Cognito:', JSON.stringify(event.response, null, 2));
          }
        }
    
        // For any unhandled provider type (or missing samlResponse), this intentionally does NOT set userAttributesToMap and tells Cognito to keep all original IdP attributes unchanged (no-op).
        // To handle OIDC or social providers, add additional logic here using event.request.attributes.idToken, .userInfo, and/or .tokenResponse.
        return event;
    
      } catch (error) {
        console.error('Error in Lambda:', error);
        throw error;
      }
    };

    Com essa abordagem, a lista de grupos é reduzida apenas ao que é relevante para a aplicação. A autenticação passa a funcionar sem depender de mudanças na configuração do IdP do cliente.

    Caso de uso 2: Vinculação automática de contas (B2C)

    Em aplicações voltadas ao consumidor, como lojas virtuais, é muito comum o seguinte cenário: um cliente cria uma conta com e-mail e senha para fazer uma compra. Meses depois, ele volta ao site, não lembra da conta e decide entrar pelo botão “Login with Amazon”. Sem vinculação de contas, o Cognito cria um novo perfil federado — e agora o mesmo cliente tem dois registros separados, com históricos de compras distintos e preferências fragmentadas.

    Embora a vinculação de contas também possa ser implementada em um trigger de pré-cadastro, o inbound federation trigger tem uma vantagem importante: ele é executado em todos os logins federados, não apenas no primeiro. Isso garante acesso contínuo aos atributos mais recentes do IdP e permite aplicar a lógica de vinculação de forma consistente.

    O exemplo abaixo demonstra como implementar essa vinculação automática. A lógica é direta: ao receber um login federado, a função extrai o e-mail do usuário, busca no user pool se já existe uma conta local com esse mesmo e-mail e, se encontrar, vincula a identidade federada a ela. Se não existir conta local, cria uma nova conta sem senha (confirmada, com autenticação por OTP via e-mail) e já a vincula ao provedor externo. Em ambos os casos, a conta local se torna a identidade primária — garantindo que o campo sub dos tokens JSON Web (JWT) seja sempre o mesmo, independentemente de como o usuário fizer login.

    import {
      CognitoIdentityProviderClient,
      ListUsersCommand,
      AdminCreateUserCommand,
      AdminLinkProviderForUserCommand
    } from "@aws-sdk/client-cognito-identity-provider";
    
    const client = new CognitoIdentityProviderClient();
    
    export const handler = async (event) => {
      try {
        console.log('Full event:', JSON.stringify(event, null, 2));
    
        const { userPoolId, request, userName } = event;
        const { providerName, providerType, attributes } = request;
    
        // Extract email and profile attributes based on provider type
        const { email, givenName, surname } = extractAttributes(providerType, attributes);
    
        if (!email) {
          console.error('No email found in federated response');
          return event;
        }
    
        console.log(`Processing federated login for email: ${email}, provider: ${providerName} (${providerType})`);
    
        // Check if a local user exists with this email
        const existingUser = await findLocalUserByEmail(userPoolId, email);
    
        if (existingUser) {
          console.log(`Found existing local user: ${existingUser.Username}`);
          if (isAlreadyLinked(existingUser, providerName, userName)) {
            console.log(`Federated identity ${providerName}:${userName} is already linked to ${existingUser.Username}, skipping link`);
          } else {
            await linkFederatedUser(userPoolId, existingUser.Username, providerName, userName);
          }
        } else {
          console.log('No existing local user found, creating new one');
          const newUsername = await createLocalUser(userPoolId, email, givenName, surname);
          await linkFederatedUser(userPoolId, newUsername, providerName, userName);
        }
    
        return event;
    
      } catch (error) {
        console.error('Error in account linking Lambda:', error);
        throw error;
      }
    };
    
    /**
     * Check if the federated identity is already linked to the local user by inspecting the identities attribute from the ListUsers response.
     */
    function isAlreadyLinked(user, providerName, federatedUsername) {
      const identities = user.Attributes?.find(a => a.Name === 'identities');
      if (!identities?.Value) return false;
      try {
        const parsed = JSON.parse(identities.Value);
        return parsed.some(id => id.providerName === providerName && id.userId === federatedUsername);
      } catch {
        return false;
      }
    }
    
    /**
     * Extract email and profile attributes based on provider type.
     * - SAML: attributes come from samlResponse
     * - OIDC/Social: attributes come from userInfo, falling back to idToken (if one exists)
     */
    function extractAttributes(providerType, attributes) {
      if (providerType?.toLowerCase() === 'saml') {
        const saml = attributes?.samlResponse;
        return {
          email: saml?.email || null,
          givenName: saml?.givenName || '',
          surname: saml?.surname || ''
        };
      }
      // OIDC and social providers: prefer userInfo, fall back to idToken
      const userInfo = attributes?.userInfo;
      const idToken = attributes?.idToken;
      const source = userInfo?.email ? userInfo : idToken;
      return {
        email: source?.email || null,
        givenName: source?.given_name || '',
        surname: source?.family_name || ''
      };
    }
    
    /**
     * Find a local Cognito user (not EXTERNAL_PROVIDER) by email address.
     */
    async function findLocalUserByEmail(userPoolId, email) {
      try {
        const command = new ListUsersCommand({
          UserPoolId: userPoolId,
          Filter: `email = "${email}"`
        });
        const response = await client.send(command);
        console.log('ListUsers response:', JSON.stringify(response, null, 2));
    
        if (!response.Users || response.Users.length === 0) {
          return null;
        }
        // Find the first user that is a true local account (not a federated-only profile)
        const localUser = response.Users.find(u => u.UserStatus !== 'EXTERNAL_PROVIDER');
        return localUser || null;
      } catch (error) {
        console.error('Error finding user by email:', error);
        throw error;
      }
    }
    
    /**
     * Create a new local Cognito user without a password.
     * With passwordless (email OTP) enabled on the user pool, the user is created with UserStatus=CONFIRMED and no FORCE_CHANGE_PASSWORD state.
     */
    async function createLocalUser(userPoolId, email, givenName, surname) {
      try {
        const userAttributes = [
          { Name: 'email', Value: email }
        ];
        if (givenName) userAttributes.push({ Name: 'given_name', Value: givenName });
        if (surname) userAttributes.push({ Name: 'family_name', Value: surname });
    
        const command = new AdminCreateUserCommand({
          UserPoolId: userPoolId,
          Username: email,
          UserAttributes: userAttributes,
          MessageAction: 'SUPPRESS'
        });
    
        const response = await client.send(command);
        console.log(`Created local user: ${email}`, JSON.stringify(response, null, 2));
        return email;
      } catch (error) {
        console.error('Error creating local user:', error);
        throw error;
      }
    }
    
    /**
     * Link a federated user identity to a local Cognito user.
     * The local user becomes the primary profile — all future JWTs will represent this local user regardless of sign-in method.
     */
    async function linkFederatedUser(userPoolId, localUsername, providerName, federatedUsername) {
      try {
        const command = new AdminLinkProviderForUserCommand({
          UserPoolId: userPoolId,
          DestinationUser: {
            ProviderName: 'Cognito',
            ProviderAttributeValue: localUsername
          },
          SourceUser: {
            ProviderName: providerName,
            ProviderAttributeName: 'Cognito_Subject',
            ProviderAttributeValue: federatedUsername
          }
        });
    
        const response = await client.send(command);
        console.log(`Linked federated user ${federatedUsername} to local user ${localUsername}`);
        console.log('Link response:', JSON.stringify(response, null, 2));
        return response;
      } catch (error) {
        if (error.name === 'AliasExistsException' || error.message?.includes('already linked')) {
          console.log(`User already linked: ${error.message}`);
          return;
        }
        console.error('Error linking federated user:', error);
        throw error;
      }
    }

    Um detalhe importante: o recurso Hide My Email da Apple gera um endereço de e-mail único por aplicativo, o que impede a vinculação automática por e-mail. Nesses casos, a aplicação precisará implementar um fluxo de vinculação iniciado pelo próprio usuário, pedindo que ele confirme a propriedade de ambos os endereços antes de chamar a API AdminLinkProviderForUser.

    Boas práticas de implementação

    Ao colocar esses padrões em prática, algumas orientações merecem atenção:

    • Tempo de execução: a função Lambda deve concluir em até 5 segundos. Otimize para velocidade e, se fizer chamadas externas — como consultas ao Amazon DynamoDB ou APIs externas — implemente cache sempre que possível.
    • Tratamento de erros: se a função lançar uma exceção, a autenticação pode falhar para o usuário. Considere registrar o erro em log e retornar o evento original ao Cognito em vez de interromper o fluxo. Consulte as boas práticas para funções Lambda para mais orientações.
    • Observabilidade: monitore a performance da função com as métricas do Amazon CloudWatch. Configure alertas para erros, timeouts e throttling. Durante o desenvolvimento inicial, capture payloads de exemplo a partir de um grupo de logs do CloudWatch — eles são valiosos para testes locais e depuração, especialmente porque diferentes IdPs (SAML e OIDC, em particular) podem responder com formatos e valores de atributos bastante variados.
    • Alertas de segurança: configure alarmes no CloudWatch para notificar as equipes de segurança e operações caso haja pico de falhas de autenticação, o que pode indicar tentativa de ataque, má configuração ou oportunidade de otimização do trigger.

    Disponibilidade e próximos passos

    O novo trigger está disponível em todas as regiões AWS onde o Amazon Cognito opera e funciona com provedores SAML, OIDC e provedores sociais suportados. Para saber mais sobre esse e outros triggers disponíveis, a AWS disponibiliza o Guia do Desenvolvedor do Amazon Cognito. Dúvidas e discussões sobre casos de uso específicos podem ser levadas ao AWS re:Post.

    Fonte

    Customize federated sign-in with new Amazon Cognito Lambda trigger (https://aws.amazon.com/blogs/security/customize-federated-sign-in-with-new-amazon-cognito-lambda-trigger/)

  • AWS IoT Device Management adiciona dados de sessão MQTT à API de status de conectividade

    O que mudou no AWS IoT Device Management

    A AWS anunciou uma atualização relevante para quem gerencia frotas de dispositivos conectados: o AWS IoT Device Management agora inclui dados de sessão MQTT na sua API de status de conectividade. Com isso, equipes de engenharia ganham mais visibilidade para diagnosticar problemas de conexão e auditar padrões de comunicação entre dispositivos de Internet das Coisas (IoT).

    Essa atualização coloca a API de status de conectividade do IoT Device Management em paridade completa com a GetConnection API do AWS IoT Core, lançada recentemente. Agora é possível consultar informações detalhadas de conexão e de sessão MQTT de um dispositivo específico, identificado pelo seu thing name.

    O que está disponível agora

    Além das informações que já existiam — status de conexão, timestamp e motivo da desconexão — a API passa a expor novos dados:

    • Timeout e expiração da sessão MQTT
    • Detalhes opcionais em nível de socket, como endereços IP de origem e destino, portas utilizadas e ID do endpoint VPC do cliente

    O acesso às informações de socket é controlado por políticas granulares de Gerenciamento de Identidade e Acesso (IAM), o que permite restringir essa visibilidade apenas às equipes que realmente precisam dela.

    A grande vantagem: retenção de dados indefinida

    Um diferencial importante dessa API em relação à GetConnection do IoT Core é o tempo de retenção dos dados. Enquanto a GetConnection mantém informações de conexão e sessão por apenas 30 minutos após a desconexão de um dispositivo, a API de status de conectividade do IoT Device Management armazena essas informações indefinidamente.

    Na prática, isso significa que é possível investigar motivos de desconexão, revisar metadados de sessão e diagnosticar problemas muito tempo depois de um dispositivo ter ficado offline — o que faz uma diferença significativa em cenários de operação distribuída ou com dispositivos em campo.

    Disponibilidade e requisitos

    A melhoria está disponível em todas as regiões da AWS onde o AWS IoT Device Management é suportado. Vale lembrar que o serviço exige que os dispositivos estejam registrados no Thing Registry do AWS IoT Core.

    Para saber mais, a AWS disponibiliza a documentação e o guia de referência do AWS IoT Device Management.

    Fonte

    AWS IoT Device Management adds MQTT session data to connectivity status API (https://aws.amazon.com/about-aws/whats-new/2026/05/aws-iot-device-management-mqtt/)

  • Segurança multi-tenant em agentes de IA com políticas baseadas em recursos do Amazon Bedrock AgentCore

    O desafio de servir múltiplos clientes com requisitos diferentes

    Provedores de Software como Serviço (SaaS) que constroem aplicações de IA sobre o Amazon Bedrock AgentCore frequentemente se deparam com um problema clássico: precisam atender múltiplos clientes (tenants) com exigências de segurança completamente distintas, tudo a partir de uma infraestrutura compartilhada.

    Alguns clientes precisam de acesso entre contas da Amazon Web Services (AWS). Outros, por questões regulatórias, exigem que o tráfego fique restrito a uma Nuvem Privada Virtual (VPC). Sem um controle centralizado no nível do recurso, gerenciar essa diversidade se torna complexo e propenso a erros.

    A AWS documentou como o AgentCore suporta políticas baseadas em recursos — um mecanismo que oferece controle centralizado sobre quem pode acessar o AgentCore Runtime e seus endpoints, e sob quais condições. A seguir, exploramos o cenário prático e o passo a passo técnico apresentados no blog oficial.

    O cenário multi-tenant

    Imagine um provedor SaaS que opera uma plataforma de atendimento ao cliente com IA. Ele usa o AgentCore para implantar agentes inteligentes que respondem dúvidas de produtos, processam devoluções e escalam casos complexos para atendentes humanos. Dois clientes empresariais compartilham esse mesmo agente, mas com requisitos de segurança bem diferentes:

    • Tenant A — Example Corp: grande varejista operando na conta AWS 111122223333. Sua equipe de desenvolvimento e equipe de administração precisam invocar o agente diretamente da própria conta AWS, sem necessidade de compartilhamento de credenciais. Não há restrições de rede — qualquer caminho de acesso é válido, desde que as credenciais AWS sejam válidas.
    • Tenant B — AnyCompany: empresa de saúde operando na conta AWS 444455556666. Por exigências de conformidade com a regulação HIPAA, todo o tráfego ao agente de IA deve originar-se exclusivamente de dentro de uma VPC privada (vpc-health1234). Qualquer chamada de API feita fora desse perímetro de rede deve ser bloqueada, mesmo que venha de uma role com credenciais válidas.

    O provedor SaaS opera na conta 555555555555, na região us-west-2, com um AgentCore Runtime chamado support-agent-runtime e um AgentCore Runtime endpoint padrão (DEFAULT). Ambos os tenants compartilham essa mesma infraestrutura.

    Arquitetura da solução

    A solução utiliza políticas baseadas em recursos aplicadas tanto ao AgentCore Runtime quanto ao AgentCore Runtime endpoint. O diagrama abaixo ilustra os dois padrões de acesso em ação:

    Imagem original — fonte: Aws

    A conta do provedor SaaS hospeda o AgentCore Runtime e o endpoint. A Example Corp acessa o agente entre contas usando roles do AWS Identity and Access Management (IAM) autenticadas com Signature Version 4 (SigV4), o protocolo padrão de assinatura de requisições AWS. A AnyCompany também acessa entre contas, mas com uma restrição adicional: todas as requisições devem passar por um endpoint de VPC para o AgentCore.

    Um detalhe crítico: as políticas baseadas em recursos precisam ser aplicadas tanto no AgentCore Runtime quanto no AgentCore Runtime endpoint. Para operações InvokeAgentRuntime, a AWS avalia as políticas nos dois recursos — se qualquer um deles negar o acesso ou não tiver um Allow explícito, a requisição é bloqueada.

    Implementação passo a passo

    Pré-requisitos

    Antes de começar, é necessário ter:

    • Uma conta AWS com acesso ao AgentCore e permissões para chamar PutResourcePolicy, GetResourcePolicy e DeleteResourcePolicy
    • AWS Command Line Interface (AWS CLI) v2 instalada e configurada com a API bedrock-agentcore-control disponível
    • Um AgentCore Runtime com autenticação SigV4 e um endpoint DEFAULT apontando para a versão mais recente
    • Para o cenário com restrição de VPC: um endpoint de VPC de interface para o AgentCore configurado na VPC do tenant. Veja mais em Interface VPC endpoints para Amazon Bedrock AgentCore

    Passo 1: Acesso entre contas para a Example Corp (Tenant A)

    Sem políticas baseadas em recursos, habilitar acesso entre contas normalmente exigiria que as roles da Example Corp assumissem uma role na conta do provedor via encadeamento de roles IAM — adicionando complexidade operacional e criando roles adicionais que precisariam ser mantidas para cada tenant. Com políticas baseadas em recursos, as roles da Example Corp recebem acesso direto ao AgentCore Runtime e ao endpoint, sem encadeamento de roles.

    Política baseada em recurso para o AgentCore Runtime — salve como runtime-policy.json:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowExampleCorpCrossAccountAccess",
          "Effect": "Allow",
          "Principal": {
            "AWS": [
              "arn:aws:iam::111122223333:role/DeveloperRole",
              "arn:aws:iam::111122223333:role/AdminRole"
            ]
          },
          "Action": "bedrock-agentcore:InvokeAgentRuntime",
          "Resource": "arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime"
        }
      ]
    }

    Política baseada em recurso para o AgentCore Runtime endpoint — salve como endpoint-policy.json:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowExampleCorpCrossAccountAccess",
          "Effect": "Allow",
          "Principal": {
            "AWS": [
              "arn:aws:iam::111122223333:role/DeveloperRole",
              "arn:aws:iam::111122223333:role/AdminRole"
            ]
          },
          "Action": "bedrock-agentcore:InvokeAgentRuntime",
          "Resource": "arn:aws:bedrock-agentcore:us-west-2:999999999999:runtime/support-agent-runtime/runtime-endpoint/DEFAULT"
        }
      ]
    }

    Aplicar as políticas:

    aws bedrock-agentcore-control put-resource-policy \
    --resource-arn arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime \
    --policy file://runtime-policy.json \
    --region us-west-2
    
    aws bedrock-agentcore-control put-resource-policy \
    --resource-arn arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime/runtime-endpoint/DEFAULT \
    --policy file://endpoint-policy.json \
    --region us-west-2

    Verificar as políticas:

    aws bedrock-agentcore-control get-resource-policy \
    --resource-arn arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime \
    --region us-west-2
    
    aws bedrock-agentcore-control get-resource-policy \
    --resource-arn arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime/runtime-endpoint/DEFAULT \
    --region us-west-2

    Política baseada em identidade na conta da Example Corp — políticas baseadas em recursos sozinhas não são suficientes para acesso entre contas. A Example Corp também precisa anexar uma política baseada em identidade às roles DeveloperRole e AdminRole na conta 111122223333:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowInvokeAgentRuntime",
          "Effect": "Allow",
          "Action": "bedrock-agentcore:InvokeAgentRuntime",
          "Resource": [
            "arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime",
            "arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime/runtime-endpoint/DEFAULT"
          ]
        }
      ]
    }

    Passo 2: Acesso entre contas com restrição de VPC para a AnyCompany (Tenant B)

    A AnyCompany opera sob conformidade HIPAA e exige que todo o tráfego ao agente permaneça dentro de um caminho de rede privado. Assim como a Example Corp, ela precisa de acesso entre contas — mas com uma restrição adicional: as requisições devem originar-se da VPC vpc-health1234 via endpoint de VPC de interface. Qualquer requisição fora dessa VPC é negada, mesmo que venha da ApplicationRole com credenciais válidas.

    Para isso, as políticas baseadas em recursos são atualizadas com um par de declarações: um Allow para a ApplicationRole e um Deny explícito para qualquer requisição que não venha da VPC aprovada. A condição StringNotEquals sobre aws:SourceVpc garante que, se o valor não corresponder a vpc-health1234 — ou se a chave estiver ausente porque nenhum endpoint de VPC foi usado — o bloqueio entra em vigor. Como um Deny explícito sempre sobrepõe qualquer Allow, esse padrão garante que nenhuma outra política possa inadvertidamente conceder acesso de fora da VPC.

    Adicione os seguintes statements ao runtime-policy-v2.json, junto com os statements da Example Corp do Passo 1:

    {
      "Sid": "AllowAnyCompanyCrossAccountAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::444455556666:role/ApplicationRole"
      },
      "Action": "bedrock-agentcore:InvokeAgentRuntime",
      "Resource": "arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime"
    },
    {
      "Sid": "DenyAnyCompanyOutsideVpc",
      "Effect": "Deny",
      "Principal": {
        "AWS": "arn:aws:iam::444455556666:role/ApplicationRole"
      },
      "Action": "bedrock-agentcore:InvokeAgentRuntime",
      "Resource": "arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime",
      "Condition": {
        "StringNotEquals": {
          "aws:SourceVpc": "vpc-health1234"
        }
      }
    }

    Adicione os statements equivalentes ao endpoint-policy-v2.json:

    {
      "Sid": "AllowAnyCompanyCrossAccountAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::444455556666:role/ApplicationRole"
      },
      "Action": "bedrock-agentcore:InvokeAgentRuntime",
      "Resource": "arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime/runtime-endpoint/DEFAULT"
    },
    {
      "Sid": "DenyHealthFirstOutsideVpc",
      "Effect": "Deny",
      "Principal": {
        "AWS": "arn:aws:iam::444455556666:role/ApplicationRole"
      },
      "Action": "bedrock-agentcore:InvokeAgentRuntime",
      "Resource": "arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime/runtime-endpoint/DEFAULT",
      "Condition": {
        "StringNotEquals": {
          "aws:SourceVpc": "vpc-health1234"
        }
      }
    }

    Como o comando put-resource-policy substitui toda a política do recurso, os arquivos atualizados devem incluir tanto os statements da AnyCompany quanto os da Example Corp do Passo 1.

    Aplicar as políticas atualizadas:

    aws bedrock-agentcore-control put-resource-policy \
      --resource-arn arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime \
      --policy file://runtime-policy-v2.json \
      --region us-west-2
    
    aws bedrock-agentcore-control put-resource-policy \
      --resource-arn arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime/runtime-endpoint/DEFAULT \
      --policy file://endpoint-policy-v2.json \
      --region us-west-2

    Verificar as políticas atualizadas:

    # Verificar política do Agent Runtime
    aws bedrock-agentcore-control get-resource-policy \
      --resource-arn arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime \
      --region us-west-2
    
    # Verificar política do Agent Runtime Endpoint
    aws bedrock-agentcore-control get-resource-policy \
      --resource-arn arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime/runtime-endpoint/DEFAULT \
      --region us-west-2

    Política baseada em identidade na conta da AnyCompany — a restrição de VPC é aplicada inteiramente na conta do provedor, por meio da condição na política baseada em recurso. Portanto, a política baseada em identidade da AnyCompany não precisa de condições de VPC, mantendo a configuração do lado do tenant simples:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowInvokeAgentRuntime",
          "Effect": "Allow",
          "Action": "bedrock-agentcore:InvokeAgentRuntime",
          "Resource": [
            "arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime",
            "arn:aws:bedrock-agentcore:us-west-2:555555555555:runtime/support-agent-runtime/runtime-endpoint/DEFAULT"
          ]
        }
      ]
    }

    Considerações sobre autenticação OAuth

    As políticas apresentadas até aqui usam autenticação SigV4 com principals de roles IAM específicas. Se o AgentCore Runtime ou o AgentCore Gateway estiver configurado com autenticação OAuth, a estrutura do principal muda. Recursos autenticados via OAuth requerem um principal curinga ("Principal": "*"), pois a identidade do chamador vem de um Token Web JSON (JWT) validado antes da avaliação da política. Requisições anônimas ou não autenticadas são rejeitadas antes mesmo de a política ser avaliada, então o curinga não significa acesso aberto.

    Para restringir requisições OAuth a uma VPC específica, basta combinar o principal curinga com uma condição de VPC na política baseada em recurso. Vale notar que chaves de condição baseadas em principal IAM — como aws:PrincipalAccount e aws:PrincipalOrgID — não são populadas no contexto de autenticação OAuth. Apenas chaves de condição de nível de rede (como aws:SourceVpc, aws:SourceVpce, aws:SourceIp) estão disponíveis. Veja mais detalhes em políticas baseadas em recursos para Amazon Bedrock AgentCore.

    Entendendo a avaliação das políticas

    Para consolidar o entendimento, vale observar como a AWS avalia as políticas em diferentes cenários:

    • Example Corp, qualquer rede: política de identidade permite + política do runtime permite + política do endpoint permite → Acesso concedido
    • AnyCompany, de dentro da VPC: política de identidade permite + condição aws:SourceVpc corresponde em ambos os recursos → Acesso concedido
    • AnyCompany, fora da VPC: condição aws:SourceVpc não corresponde → Deny explícito em ambos os recursos → Acesso negado
    • Qualquer outra role entre contas, qualquer rede: sem Allow correspondente na política do recurso → Acesso negado
    • Qualquer role sem política de identidade: mesmo com Allow no recurso, a ausência de política de identidade bloqueia o acesso entre contas → Acesso negado

    Conclusão

    O que a AWS demonstra nesse guia é uma abordagem elegante para um problema real de plataformas SaaS multi-tenant: como oferecer controles de segurança distintos para cada cliente sem duplicar infraestrutura. A Example Corp obtém integração entre contas sem complexidade de gerenciamento de credenciais. A AnyCompany obtém o isolamento de rede exigido pela sua equipe de conformidade, com a garantia de que interações envolvendo informações potencialmente sensíveis ficam dentro do perímetro de rede controlado.

    Ambos os tenants compartilham o mesmo AgentCore Runtime e endpoint, mas cada um tem controles de segurança sob medida aplicados no nível do recurso. Políticas baseadas em recursos complementam as políticas baseadas em identidade do IAM, oferecendo controle em camadas sobre quais principals podem invocar quais agentes e a partir de quais caminhos de rede.

    Para aprofundar o tema, a AWS recomenda:

    Fonte

    Secure multi-tenant AI agents with Amazon Bedrock AgentCore resource-based policies (https://aws.amazon.com/blogs/security/secure-multi-tenant-ai-agents-with-amazon-bedrock-agentcore-resource-based-policies/)

  • AWS Config passa a suportar regras vinculadas a serviços internos

    O que mudou no AWS Config

    A AWS anunciou uma expansão importante no AWS Config: o serviço agora oferece suporte a regras vinculadas a serviços internos (internal service linked rules). Com essa novidade, outros serviços da AWS passam a conseguir avaliar configurações de recursos diretamente por meio das regras gerenciadas do AWS Config.

    Como essa funcionalidade se encaixa no ecossistema

    Essa capacidade é uma extensão natural do gravador vinculado a serviços (service linked recorder), que já existia anteriormente. A diferença agora é que serviços como o AWS Security Hub CSPM podem ir além do registro: eles conseguem implantar e gerenciar avaliações de regras voltadas para funcionalidades específicas de cada serviço.

    Na prática, isso significa que serviços da AWS podem usar as regras gerenciadas do Config para oferecer capacidades integradas de segurança e conformidade — sem que o cliente precise configurar ou gerenciar essas regras manualmente.

    Entrega de resultados e modelo de custos

    Os resultados das avaliações são entregues diretamente ao serviço da AWS que implantou a regra. Um ponto importante para quem gerencia custos na nuvem: não há cobrança do AWS Config ao cliente por essas avaliações realizadas via regras vinculadas a serviços internos.

    Independência em relação às configurações existentes

    As regras vinculadas a serviços internos operam de forma independente dos gravadores e regras gerenciados pelo próprio cliente no AWS Config. Isso garante que quem já usa o Config para inventário, governança, conformidade e auditoria pode continuar fazendo isso normalmente — enquanto os serviços da AWS gerenciam, de forma autônoma, as avaliações específicas de cada um deles.

    Ou seja, não há interferência entre o que o cliente configura e o que os serviços internos da AWS gerenciam. As duas camadas coexistem sem conflito.

    Disponibilidade

    As regras vinculadas a serviços internos do AWS Security Hub CSPM já estão disponíveis em todas as regiões comerciais, regiões GovCloud e regiões da China.

    Para se aprofundar no funcionamento técnico do recurso, a AWS disponibiliza a documentação oficial do AWS Config.

    Fonte

    AWS Config now supports internal service linked rules (https://aws.amazon.com/about-aws/whats-new/2026/06/aws-config-supports-internal-service-linked-rules)

  • Amazon EKS e EKS Distro passam a suportar Kubernetes versão 1.36

    Suporte ao Kubernetes 1.36 chega ao Amazon EKS

    A AWS anunciou que o Amazon Serviço Elástico de Kubernetes (EKS) e o Amazon EKS Distro agora oferecem suporte oficial ao Kubernetes versão 1.36. A partir de agora, é possível criar novos clusters EKS com essa versão ou atualizar clusters existentes — tudo isso via console do EKS, pela interface de linha de comando eksctl ou por ferramentas de infraestrutura como código.

    O que há de novo no Kubernetes 1.36

    Esta versão traz quatro melhorias de destaque que valem atenção de quem opera ambientes Kubernetes em produção:

    • User Namespaces em disponibilidade geral: o recurso que mapeia o usuário root de um contêiner para um usuário sem privilégios no host passou da fase beta para GA (disponibilidade geral). Na prática, isso significa que mesmo que um processo consiga escapar do contêiner, ele não terá privilégios no nó subjacente — um ganho relevante de segurança.
    • Mutating Admission Policies: agora é possível realizar mutações de recursos diretamente no servidor de API usando CEL (Common Expression Language), sem precisar configurar infraestrutura de webhook. Isso simplifica pipelines de admissão e reduz dependências operacionais.
    • Escalonamento vertical de recursos de Pod sem reinicialização: os Pods podem agora redimensionar seu orçamento compartilhado de CPU e memória em tempo real, sem precisar ser reiniciados. Esse recurso, chamado de In-Place Pod-Level Resources Vertical Scaling, traz mais flexibilidade para workloads que precisam de ajustes dinâmicos de capacidade.
    • Resource Health Status: a saúde de dispositivos de hardware agora é reportada diretamente no status do Pod. Isso facilita a identificação de crash loops causados por falhas de hardware, tornando o diagnóstico de problemas muito mais direto.

    Para conhecer todos os detalhes das mudanças introduzidas no Kubernetes 1.36, a AWS disponibiliza a documentação oficial e as notas de release do projeto Kubernetes.

    Disponibilidade e como atualizar

    O suporte ao Kubernetes 1.36 no EKS já está ativo em todas as regiões AWS onde o serviço está disponível, incluindo as regiões AWS GovCloud (US). Para consultar as versões disponíveis e obter instruções detalhadas de atualização, a AWS indica a documentação do EKS.

    Antes de realizar o upgrade, vale usar o recurso EKS cluster insights para verificar se há problemas que possam impactar o processo de atualização do cluster.

    As builds do EKS Distro para o Kubernetes 1.36 já estão disponíveis no ECR Public Gallery e no GitHub. Para entender melhor as políticas de ciclo de vida das versões suportadas pelo EKS, a AWS mantém documentação específica sobre o tema.

    Fonte

    Amazon EKS and Amazon EKS Distro now supports Kubernetes version 1.36 (https://aws.amazon.com/about-aws/whats-new/2026/06/amazon-eks-distro-kubernetes-version-1-36)

  • Identifique chaves AWS KMS não utilizadas e evite exclusões acidentais

    Gerenciar chaves KMS em escala é um desafio real

    Conforme o uso da Amazon Web Services (AWS) cresce dentro de uma organização, o gerenciamento de chaves criptográficas se torna cada vez mais complexo. Seja com um punhado de chaves ou com milhares distribuídas por múltiplas contas e regiões, existe sempre a necessidade de auditar o uso dessas chaves — seja para atender requisitos de conformidade, avaliar riscos ou reduzir custos operacionais.

    O problema é que descobrir quais chaves estão ativas e quais ficaram paradas sem uso costumava ser um processo trabalhoso. Para resolver isso, o Serviço de Gerenciamento de Chaves da AWS (AWS KMS) lançou a API GetKeyLastUsage, uma nova funcionalidade que permite identificar rapidamente quando cada chave foi usada pela última vez em uma operação criptográfica. Para saber mais, consulte a documentação Determine past usage of a KMS key.

    Como era feita a auditoria antes

    Antes desse lançamento, a principal forma de auditar o uso de chaves era por meio dos logs do AWS CloudTrail. O CloudTrail registra todas as operações criptográficas por padrão, então os dados estavam disponíveis — o problema era transformar esse volume de dados em informação acionável.

    Para os últimos 90 dias, o histórico de eventos do CloudTrail tornava o processo viável. Para períodos mais longos, era necessário criar uma trilha dedicada, entregar os logs para o Amazon Simple Storage Service (Amazon S3) para retenção de longo prazo e, em seguida, consultar esses logs com ferramentas como o Amazon Athena. Um fluxo complexo para uma pergunta relativamente simples: “quando essa chave foi usada pela última vez?”

    O que a API GetKeyLastUsage oferece

    O AWS KMS agora disponibiliza uma forma direta de consultar quando uma chave foi utilizada pela última vez em operações criptográficas. Essa informação também pode ser visualizada pelo console de gerenciamento da AWS e pela Interface de Linha de Comando da AWS (AWS CLI).

    A API GetKeyLastUsage retorna a data e hora da operação criptográfica mais recente realizada com uma chave KMS — sem precisar vasculhar logs do CloudTrail. Os dados retornados incluem:

    • Data e hora da última operação com a chave
    • Tipo de operação realizada
    • ID do evento no CloudTrail
    • ID da requisição no KMS

    Essa informação está disponível para todas as chaves gerenciadas pelo cliente e chaves gerenciadas pela AWS, independentemente do tipo de chave, origem, armazenamento ou tipo de uso.

    Além disso, é possível restringir a desativação ou o agendamento de exclusão de uma chave que foi usada recentemente, incorporando essas informações de uso como condição na política da chave KMS.

    Entendendo o período de rastreamento

    Antes de depender das informações de último uso de uma chave, é fundamental compreender o conceito de período de rastreamento. Esse é o ponto de partida a partir do qual o AWS KMS passou a registrar a atividade criptográfica de cada chave. Para a maioria das regiões da AWS, o rastreamento teve início em 23 de abril de 2026.

    Isso é crítico: a ausência de informações de uso pode significar que a chave nunca foi usada ou que ela simplesmente não foi usada desde o início do rastreamento. Por exemplo, uma chave criada em 1º de janeiro de 2026 pode ter sido amplamente utilizada entre janeiro e 22 de abril — mas essas operações não estarão refletidas nos dados da API. Portanto, não é possível concluir que uma chave está em desuso apenas porque não há registros de uso após o início do rastreamento.

    Como visualizar as informações de uso

    Não é necessário habilitar nada nem fazer configurações adicionais para acessar as informações de último uso das chaves KMS. Basta acessar o console do KMS, selecionar uma chave em Customer-managed keys e verificar o campo Last used nas configurações gerais. Ao clicar no link exibido nesse campo, é possível ver detalhes adicionais como o timestamp, o tipo de operação e o ID do evento no CloudTrail.

    A coluna Last used também é exibida ao tentar agendar a exclusão de uma chave, permitindo tomar decisões mais informadas antes de confirmar a ação.

    Casos de uso práticos

    Caso de uso 1: Otimização de custos com limpeza de chaves não utilizadas

    Organizações que gerenciam milhares de chaves KMS distribuídas por múltiplas contas frequentemente acumulam chaves que nunca foram usadas ou que caíram em desuso. A limpeza dessas chaves reduz custos operacionais e diminui a superfície de segurança exposta. A API GetKeyLastUsage facilita esse processo ao indicar quais chaves não realizaram operações criptográficas recentemente.

    No entanto, é importante ter cautela: o fato de uma chave não ter sido usada recentemente não significa que ela pode ser excluída com segurança. Uma chave pode ficar meses sem atividade e ainda ser necessária para descriptografar arquivos em cenários de conformidade ou recuperação de desastres.

    Um exemplo claro disso são os volumes do Amazon Elastic Block Store (Amazon EBS). Esses volumes interagem com chaves KMS apenas em eventos específicos do ciclo de vida, como criação, anexação e desanexação. Após um volume ser anexado a uma instância do Amazon Elastic Compute Cloud (Amazon EC2), a chave de criptografia de dados em texto simples fica armazenada em cache no hardware do Nitro Card — e todas as operações subsequentes de leitura e gravação usam essa chave em cache, sem nenhuma chamada adicional à API do KMS.

    Isso significa que um volume de produção rodando continuamente por meses ou anos pode não mostrar nenhuma atividade KMS durante todo esse período — mas ainda depende completamente da chave para qualquer operação futura, como reinicializações de instância, reanexação de volume ou recuperação de desastres. Se a chave for excluída, a chave de criptografia de dados armazenada com o volume nunca poderá ser descriptografada novamente, tornando os dados do volume permanentemente inacessíveis.

    A recomendação é: ao identificar uma chave potencialmente não utilizada, primeiro desative-a usando o comando DisableKey e monitore suas aplicações e serviços em busca de falhas de criptografia ou descriptografia. Antes de excluir qualquer chave KMS, verifique se não há volumes EBS ou snapshots associados a ela, independentemente de quando ocorreu a última chamada à API do KMS.

    A AWS também disponibiliza um mecanismo para criar um alarme no CloudWatch que notifica quando uma chave com exclusão pendente está sendo acessada, dando a oportunidade de cancelar a exclusão antes que os dados se tornem inacessíveis.

    Script para identificar chaves não utilizadas

    A seguir, um exemplo de script que percorre todas as chaves gerenciadas pelo cliente em uma conta e recupera a data de último uso de cada uma via API GetKeyLastUsage. O script aceita dois parâmetros opcionais: um limite em dias e uma região da AWS. Ele filtra e exibe apenas as chaves que não foram usadas dentro do período especificado, apresentando os resultados em uma tabela com o nome da chave, ID da conta, região e data de último uso.

    Exemplo para verificar todas as chaves não usadas nos últimos 180 dias na região us-east-1:

    ./script.sh 180 us-east-1
    #!/bin/bash
    DAYS=${1:-90}
    REGION=${2:-$(aws configure get region)}
    CUTOFF=$(date -v-${DAYS}d +%s 2>/dev/null || date -d "-${DAYS} days" +%s)
    ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
    
    printf "Showing keys not used in the last %s days (Region: %s)\n\n" "$DAYS" "$REGION"
    printf "%-50s %-15s %-20s %-15s\n" "Key Name" "Account ID" "Region" "Last Usage Date"
    printf "%.0s-" {1..100}
    printf "\n"
    
    for key_id in $(aws kms list-keys --region $REGION --query 'Keys[*].KeyId' --output text); do
        key_manager=$(aws kms describe-key --region $REGION --key-id $key_id --query 'KeyMetadata.KeyManager' --output text)
        if [ "$key_manager" = "CUSTOMER" ]; then
            last_usage=$(aws kms get-key-last-usage --region $REGION --key-id $key_id)
            timestamp=$(echo $last_usage | jq -r '.KeyLastUsage.TimeStamp // empty')
            if [ -z "$timestamp" ]; then
                last_epoch=0
            else
                last_epoch=$(date -jf "%Y-%m-%dT%H:%M:%S" "$(echo $timestamp | cut -d. -f1)" +%s 2>/dev/null || date -d "$timestamp" +%s)
            fi
            if [ "$last_epoch" -lt "$CUTOFF" ]; then
                key_alias=$(aws kms list-aliases --region $REGION --key-id $key_id --query 'Aliases[0].AliasName' --output text)
                key_name=${key_alias:-$key_id}
                [ "$key_name" = "None" ] && key_name=$key_id
                if [ -z "$timestamp" ]; then
                    tracking_date=$(echo $last_usage | jq -r '.TrackingStartDate' | cut -d'T' -f1)
                    last_used="${tracking_date}*"
                else
                    last_used=$(echo $timestamp | cut -d'T' -f1)
                fi
                printf "%-50s %-15s %-20s %-15s\n" "$key_name" "$ACCOUNT_ID" "$REGION" "$last_used"
            fi
        fi
    done
    
    printf "\n* = No operations performed since tracking started\n"

    Caso de uso 2: Prevenção de exclusões acidentais com controles de política

    Exclusões acidentais de chaves KMS são um risco real nas organizações. Uma chave pode ser excluída porque alguém acredita que ela não está mais em uso — e só depois se descobre que aplicações ou workloads críticos dependiam dela. O resultado são falhas de acesso a dados, indisponibilidade de aplicações e procedimentos de recuperação de emergência.

    Para evitar esse cenário, é possível usar a chave de condição kms:TrailingDaysWithoutKeyUsage nas políticas de chave KMS, bloqueando automaticamente a exclusão ou desativação de chaves usadas recentemente. Veja como configurar isso no console do AWS KMS:

    1. Acesse o console do AWS KMS e selecione Customer managed keys no painel de navegação.
    2. Selecione a chave que deseja proteger.
    3. Na aba Key policy, clique em Edit.
    4. No editor de política, adicione o seguinte bloco:
    {
      "Sid": "PreventDeletionOfRecentlyUsedKeys",
      "Effect": "Deny",
      "Principal": "*",
      "Action": [
        "kms:ScheduleKeyDeletion",
        "kms:DisableKey"
      ],
      "Resource": "*",
      "Condition": {
        "NumericLessThanEquals": {
          "kms:TrailingDaysWithoutKeyUsage": "365"
        }
      }
    }

    Essa política bloqueia a exclusão ou desativação de qualquer chave que tenha sido usada nos últimos 365 dias. O limite pode ser ajustado conforme as necessidades da organização. Para mais informações sobre essa chave de condição, consulte a documentação de kms:TrailingDaysWithoutKeyUsage.

    Considerações importantes antes de excluir uma chave

    Ao revisar chaves para possível exclusão, é essencial ter em mente os seguintes pontos:

    • A exclusão de uma chave é irreversível e torna os dados criptografados com ela irrecuperáveis.
    • A AWS impõe um período de espera de 7 a 30 dias antes da exclusão ser efetivada. Durante esse tempo, monitore tentativas de uso e cancele a exclusão se necessário.
    • Exclua uma chave somente se tiver certeza de que nenhum dado foi ou será criptografado com ela.
    • Considere desativar a chave primeiro para testar o impacto da sua indisponibilidade antes de partir para a exclusão definitiva.
    • O CloudTrail continua sendo a fonte autoritativa de auditoria, pois fornece o histórico completo de quem fez cada requisição e com quais parâmetros. A GetKeyLastUsage informa rapidamente quando e qual operação ocorreu, mas o CloudTrail mostra o contexto completo. Saiba mais sobre registro de chamadas à API do KMS com o CloudTrail.

    Conclusão

    A API GetKeyLastUsage representa um avanço significativo nas capacidades de gerenciamento do ciclo de vida de chaves KMS. Ela oferece acesso imediato a dados de uso que antes só estavam disponíveis mediante consultas complexas ao CloudTrail. Para equipes que gerenciam grandes volumes de chaves, isso simplifica auditorias, reduz riscos de exclusões acidentais e facilita a otimização de custos.

    O ponto de partida é simples: acesse o console do AWS KMS e verifique o campo Last used nas chaves gerenciadas pelo cliente e nas chaves gerenciadas pela AWS. Para auditorias mais amplas, integre a API aos scripts de automação existentes usando os exemplos de AWS CLI apresentados aqui.

    Fonte

    Identify unused AWS KMS keys and prevent accidental key deletions (https://aws.amazon.com/blogs/security/identify-unused-aws-kms-keys-and-prevent-accidental-key-deletions/)

  • Novas capacidades do Amazon Bedrock AgentCore Gateway para MCP em produção

    Um único ponto de entrada para servidores MCP corporativos

    Quando uma organização começa a escalar o uso de servidores Protocolo de Contexto de Modelo (MCP) em produção, surgem desafios sérios: controle de acesso granular, visibilidade sobre quais equipes usam quais ferramentas, proteção contra vazamento de dados e gerenciamento centralizado de credenciais. Sem uma solução centralizada, cada servidor MCP precisa resolver esses problemas por conta própria.

    O Amazon Bedrock AgentCore Gateway foi criado exatamente para resolver esse cenário. Ele atua como intermediário entre os servidores MCP e os clientes que os consomem, centralizando credenciais, observabilidade e conectividade segura em um único ponto confiável. A AWS anunciou recentemente uma expansão significativa desse serviço com novas capacidades voltadas para implantações MCP em ambientes corporativos.

    As novidades cobrem: suporte estendido ao esquema de ferramentas MCP, prompts MCP e recursos MCP como primitivos de primeira classe, listagem dinâmica para descoberta em tempo de execução, streaming e gerenciamento de sessões para interações em tempo real, elicitação para solicitações de entrada durante a execução, e troca de tokens OAuth 2.0 on-behalf-of para autenticação delegada. Exemplos práticos estão disponíveis no repositório de amostras no GitHub.

    Como o AgentCore Gateway centraliza a governança

    Sem um gateway centralizado, cada servidor MCP construído pela organização precisa lidar individualmente com credenciais, aplicação de políticas, conectividade privada e logs. O servidor MCP de revisão de contratos do time jurídico, o de recuperação de dados do time financeiro e o de resposta a incidentes do time de operações — todos carregam o mesmo peso de infraestrutura. O time de segurança precisa revisar cada servidor separadamente, os desenvolvedores aguardam aprovações e ninguém tem uma visão unificada do uso da infraestrutura MCP.

    O AgentCore Gateway elimina essa duplicação ao estabelecer um ponto de entrada único para todo o tráfego MCP. Cada equipe cuida apenas da lógica de negócio do seu servidor; o gateway trata do restante. Ele agrega capacidades de diferentes tipos de destino, incluindo servidores MCP, APIs REST, funções AWS Lambda e outros.

    Entre os recursos de governança já disponíveis no AgentCore Gateway, destacam-se:

    Primitivos MCP como cidadãos de primeira classe

    O AgentCore Gateway passa a funcionar como um único endpoint MCP que agrega capacidades de todos os servidores MCP da organização. Os clientes enxergam um catálogo unificado de ferramentas, uma biblioteca de prompts e um namespace de recursos — sem precisar gerenciar 20 conexões separadas.

    O gateway suporta os três primitivos MCP: ferramentas, prompts e recursos. As definições de ferramentas incluem um outputSchema opcional para definir a estrutura de saída esperada e anotações que descrevem propriedades comportamentais, como se a ferramenta é somente leitura ou destrutiva. O gateway também suporta os métodos MCP completos: tools/list, tools/call, prompts/list, prompts/get, resources/list, resources/read e resources/templates/list.

    No modo de listagem padrão, o AgentCore Gateway descobre e armazena em cache as ferramentas, prompts e recursos dos servidores MCP conectados. Esse cache é atualizado implicitamente sempre que se chama CreateGatewayTarget ou UpdateGatewayTarget, e pode ser atualizado explicitamente com a API SynchronizeGatewayTargets. Quando os clientes fazem chamadas de listagem, o gateway responde diretamente do cache. A interação real com o servidor MCP só ocorre durante operações de invocação: tools/call, prompts/get e resources/read.

    Ferramentas e prompts retornados pelo gateway recebem o prefixo do nome do destino no formato targetName___. URIs de recursos são retornados sem prefixo — o URI original do servidor MCP é repassado diretamente. Um ponto de atenção importante: como os URIs de recursos não são validados pelo gateway, é preciso ter cuidado com destinos não confiáveis, pois um servidor MCP comprometido poderia retornar URIs apontando para endpoints internos ou caminhos do sistema de arquivos local.

    Listagem dinâmica para controle de acesso por usuário

    Alguns servidores MCP personalizam suas capacidades por usuário. Um servidor com controle de permissões pode expor a ferramenta approve_expense apenas para gerentes, ou um servidor multi-tenant pode disponibilizar ferramentas compatíveis com HIPAA somente para clientes de saúde. A listagem dinâmica permite preservar esse controle de acesso no lado do servidor, mesmo roteando pelo AgentCore Gateway.

    Ao criar um destino, é possível escolher entre dois modos de listagem: padrão e dinâmico.

    • Modo padrão: o gateway invoca o servidor MCP durante CreateGatewayTarget ou UpdateGatewayTarget para descobrir e armazenar em cache ferramentas, prompts e recursos. Chamadas de listagem são respondidas diretamente do cache.
    • Modo dinâmico: o gateway não invoca o servidor durante a criação ou atualização do destino. As chamadas de listagem são encaminhadas em tempo real ao servidor MCP, usando a identidade do usuário que está fazendo a chamada.

    Em ambos os modos, operações de invocação como tools/call, prompts/get e resources/read são roteadas diretamente ao servidor MCP de destino.

    Imagem original — fonte: Aws

    Essa arquitetura dual também oferece flexibilidade para multi-tenancy e controle de acesso granular (FGAC). Para o modo dinâmico, o controle de acesso pode ser gerenciado diretamente no servidor MCP, já que as operações de listagem são executadas sob a identidade do usuário final. Vale observar que, no modo dinâmico, os primitivos não são indexados no gateway, o que significa que a capacidade de busca semântica de ferramentas não pode ser utilizada.

    Streaming, gerenciamento de sessões e elicitação

    Muitos fluxos de trabalho MCP corporativos vão além de simples chamadas de requisição-resposta. Um servidor MCP pode precisar transmitir atualizações de progresso enquanto gera um relatório, pausar no meio da execução para pedir aprovação do usuário antes de uma ação sensível, ou manter contexto ao longo de uma conversa com múltiplos passos. O AgentCore Gateway agora suporta transporte HTTP com streaming, gerenciamento de sessões MCP e elicitação.

    HTTP com Streaming

    Sem streaming, uma chamada de ferramenta que leva 45 segundos não retorna nada até o final. Com streaming, o usuário vê eventos de progresso em tempo real. Quando um cliente envia uma requisição tools/call com Accept: application/json, text/event-stream, o AgentCore Gateway abre um stream SSE (Eventos Enviados pelo Servidor) e encaminha eventos do servidor MCP em tempo real, incluindo notificações de progresso, mensagens de log e o resultado final da ferramenta. Clientes que enviam apenas Accept: application/json continuam recebendo uma única resposta JSON, preservando compatibilidade retroativa.

    Para habilitar o streaming, basta configurar o bloco enableResponseStreaming na chamada de API CreateGateway ou UpdateGateway:

    "protocolConfiguration": {
      "mcp": {
        "streamingConfiguration": {
          "enableResponseStreaming": true
        }
      }
    }

    Um ponto de atenção: o AgentCore Gateway determina o código de status HTTP a partir do primeiro evento do stream. Se ocorrer um erro no meio do stream, ele é entregue como um objeto de erro JSON-RPC dentro de um frame SSE, e não como um código de status HTTP.

    Gerenciamento de Sessões

    O gerenciamento de sessões introduz fluxos de trabalho com múltiplos turnos ao AgentCore Gateway. Quando as sessões são habilitadas, o gateway gera um Mcp-Session-Id na primeira requisição de inicialização e o retorna como cabeçalho de resposta. O cliente inclui esse cabeçalho nas requisições subsequentes, permitindo que o gateway rastreie interações, mantenha mapeamentos para sessões de servidores MCP downstream e correlacione requisições de elicitação entre chamadas de ferramentas.

    Para habilitar sessões, adiciona-se um bloco sessionConfiguration na chamada de API CreateGateway ou UpdateGateway. O tempo limite de sessão pode ser configurado de 15 minutos a 8 horas, com padrão de 1 hora:

    "protocolConfiguration": {
      "mcp": {
        "sessionConfiguration": {
          "sessionTimeoutInSeconds": 3600
        }
      }
    }

    As sessões são escopadas ao usuário autenticado. O gateway deriva a identidade do usuário a partir do contexto de autorização — token JWT bearer para ingresso OAuth ou credenciais IAM para ingresso AWS_IAM — e valida que cada requisição dentro de uma sessão se origina do mesmo usuário, ajudando a prevenir sequestro de sessão. O gateway retorna HTTP 400 se receber uma requisição sem o cabeçalho Mcp-Session-Id, e HTTP 404 para sessões expiradas ou inexistentes.

    Elicitação

    A elicitação permite que servidores MCP por trás do AgentCore Gateway pausem a execução e solicitem entrada do usuário final. Isso é especialmente valioso para operações de alto risco que exigem confirmação explícita do usuário, coleta de dados estruturados ou autenticação fora de banda antes de prosseguir.

    O AgentCore Gateway suporta três modos de elicitação:

    • Modo formulário: o servidor MCP envia um JSON Schema descrevendo os campos necessários, e o cliente renderiza um formulário para o usuário preencher.
    • Modo URL: o servidor envia uma URL que o cliente abre para o usuário — tipicamente uma tela de consentimento OAuth ou um fluxo de aprovação externo.
    • Modo exceção URL: o servidor retorna um URLElicitationRequiredError contendo uma URL, solicitando que o cliente redirecione o usuário e tente novamente após a conclusão do fluxo externo.

    A elicitação requer que tanto o streaming quanto as sessões estejam habilitados no gateway. O AgentCore Gateway respeita a negociação de capacidades — ele só declara suporte à elicitação para um servidor MCP downstream quando o cliente conectado também declarou suporte durante a inicialização. O gateway também suporta múltiplas elicitações ativas por sessão, permitindo que chamadas de ferramentas concorrentes tenham cada uma sua própria elicitação pendente.

    Troca de tokens OAuth 2.0 on-behalf-of

    Quando agentes precisam acessar recursos downstream em nome de usuários autenticados, o AgentCore Gateway suporta troca de tokens OAuth 2.0 on-behalf-of (OBO) por meio do AgentCore Identity. Isso habilita um modelo de autenticação zero-trust onde a identidade original do usuário é preservada e propagada em cada salto da cadeia de requisições, enquanto cada camada recebe um token escopado precisamente para sua audiência pretendida.

    O fluxo funciona assim: o cliente MCP se autentica no AgentCore Gateway com JWT A, escopado para a audiência do gateway (aud: gw). Quando o gateway precisa chamar um servidor MCP downstream, ele chama o AgentCore Identity para trocar JWT A por JWT B, agora escopado para a audiência do servidor MCP (aud: mcp). Se o servidor MCP precisar chamar uma API ainda mais downstream, pode usar GetResourceOAuth2Token para obter JWT C escopado para essa API (aud: api). Em cada salto, a identidade original do usuário (sub: X) é mantida, permitindo que serviços downstream apliquem autorização granular por usuário sem disparar fluxos de consentimento adicionais.

    O AgentCore Identity atua como o broker central de tokens para todo esse fluxo. Ele fornece um cofre seguro de tokens para armazenar credenciais OAuth e segredos de cliente, além de suportar identidade de carga de trabalho para autenticação serviço a serviço usando identidade de carga de trabalho AWS em vez de segredos de longa duração. Suporta troca de tokens padrão (RFC 8693) ou concessão de autorização JWT (RFC 7523), dependendo do provedor de identidade.

    Adoção incremental sem quebrar o que já funciona

    Com essas novidades, é possível construir fluxos de trabalho agênticos com múltiplos turnos com streaming de progresso em tempo real, gates de aprovação humana que pausam e retomam a execução, e propagação de identidade zero-trust — tudo por meio de um único endpoint gerenciado. Sem stores de sessão customizados, sem infraestrutura de streaming manual, sem credenciais de conta de serviço compartilhadas.

    Para começar, a AWS recomenda consultar a documentação do Amazon Bedrock AgentCore Gateway para detalhes de configuração de cada recurso. Para exemplos práticos, o repositório de amostras no GitHub é o ponto de partida. Quem já executa servidores MCP por trás do AgentCore Gateway pode adotar essas capacidades de forma incremental, sem alterações nas configurações existentes do gateway ou dos destinos.

    Fonte

    Extending MCP support for Amazon Bedrock AgentCore Gateway (https://aws.amazon.com/blogs/machine-learning/extending-mcp-support-for-amazon-bedrock-agentcore-gateway-2/)