O blog da AWS
Como criar uma autorização refinada usando o Amazon Cognito, o API Gateway e o IAM
Como desenvolvedor, você está criando uma aplicação voltada para o cliente, na qual os usuários farão login pela web ou dispositivo móvel e, por isso, suas APIs serão expostas por meio do API Gateway com serviços upstream. As APIs podem ser implantadas no Amazon Elastic Container Service (Amazon ECS), Amazon Elastic Kubernetes Service (Amazon EKS), AWS Lambda ou Elastic Load Balancing, e cada uma dessas opções encaminhará a solicitação às suas instâncias do Amazon Elastic Compute Cloud (Amazon EC2). Além disso, você pode usar serviços on-premises conectados ao seu ambiente da Amazon Web Services (AWS) por meio de uma AWS VPN ou do AWS Direct Connect. É importante ter controles refinados para cada endpoint de API e utilizar HTTP. Por exemplo, o usuário deve ter permissão para fazer uma solicitação GET a um endpoint, mas não deve ter permissão para fazer uma solicitação POST ao mesmo endpoint. Como prática recomendada, você deve atribuir usuários a grupos e usar a associação a grupos para permitir ou negar acesso aos seus serviços de API.
Visão geral da solução
Neste blog você aprenderá a usar um grupo de usuários do Amazon Cognito como diretório de usuários e permitir que os usuários autentiquem e adquiram o JSON Web Token (JWT) para passar para o API Gateway. O JWT é usado para identificar a qual grupo o usuário pertence, pois o mapeamento de um grupo para uma política do IAM exibirá os direitos de acesso concedidos ao grupo.
Nota: a solução funciona de forma semelhante se o Amazon Cognito federar usuários com um provedor de identidades (IdP) externo, como Ping, Active Directory ou Okta, em vez de ser ele mesmo um IdP. Para saber mais, consulte Adding User Pool Sign-in Through a Third Party (Adicionar login do grupo de usuários por meio de terceiros). Além disso, se quiser usar grupos de um IdP externo para conceder acesso, você pode encontrar a descrição de como fazer isso em Role-based access control using Amazon Cognito and an external identity provider (Controle de acesso baseado em função usando o Amazon Cognito e um provedor de identidades externo).
A figura a seguir mostra a arquitetura básica e o fluxo de informações para solicitações do usuário.
Vamos analisar o fluxo de solicitações para entender o que ocorre em cada etapa, conforme mostrado na figura 1:
- Um usuário faz login e adquire um token JWT do Amazon Cognito, um token de acesso e um token de atualização. Para saber mais sobre cada token, consulte Using tokens with user pools (Como usar tokens com grupos de usuários).
- Uma solicitação RestAPI é feita e um Bearer Token, o qual nessa solução é um token de acesso, é passado nos cabeçalhos.
- O API Gateway encaminha a solicitação para um autorizador do Lambda (Lambda authorizer), também conhecido como autorizador customizado (custom authorizer).
- O autorizador do Lambda verifica o Amazon Cognito JWT usando a chave pública do Amazon Cognito. Na invocação inicial do Lambda, a chave pública é baixada do Amazon Cognito e armazenada em cache. As chamadas subsequentes usarão a chave pública do cache.
- O autorizador do Lambda pesquisa o grupo do Amazon Cognito ao qual o usuário pertence no JWT e faz uma pesquisa no Amazon DynamoDB para obter a política mapeada para o grupo.
- O Lambda retorna a política e, opcionalmente, o contexto para o API Gateway. O contexto é um mapa contendo pares de chave-valor que você pode passar para o serviço upstream. Podem ser informações adicionais sobre o usuário, o serviço ou qualquer dado que forneça informações adicionais ao serviço upstream.
- O mecanismo de avaliação política do API Gateway avalia a política.
Nota: o Lambda não é responsável por entender e avaliar a política. Essa responsabilidade recai sobre os recursos nativos do API Gateway. - A solicitação é encaminhada para o serviço.
Nota: para otimizar ainda mais o autorizador do Lambda, a política de autorização pode ser armazenada em cache ou desabilitada, dependendo de suas necessidades. Ao habilitar o cache, você pode melhorar a performance, pois a política de autorização será retornada do cache sempre que houver uma correspondência de chave de cache. Para saber mais, consulte Configure a Lambda authorizer using the API Gateway console (Configure um autorizador do Lambda usando o console do API Gateway).
Vamos ver mais de perto o exemplo de política a seguir, que é armazenado como parte de um item no DynamoDB.
Com base nessa política de exemplo, o usuário tem permissão para fazer chamadas para a API petstore. Para a versão v1, o usuário pode fazer solicitações a qualquer verbo e qualquer caminho, qual é expresso por um asterisco (*). Para a v2, o usuário só tem permissão para fazer uma solicitação GET para o caminhostatus. Para saber mais sobre como as políticas funcionam, consulte Output from an Amazon API Gateway Lambda authorizer (Output de um autorizador Lambda do Amazon API Gateway).
Conceitos básicos
Para essa solução, você precisa dos seguintes pré-requisitos:
- A AWS Command Line Interface (AWS CLI) instalada e configurada para uso.
- Python 3.6 ou posterior, para o código Python pelo Lambda
Nota: recomendamos o uso de um ambiente virtual ou virtualenvwrapper para isolar a solução do restante de seu ambiente Python.
- Um perfil ou usuário do IAM com permissões suficientes para criar um grupo de usuários do Amazon Cognito, perfil do IAM, Lambda, política do IAM, API Gateway e tabela do DynamoDB.
- O repositório do GitHub para a solução. Você pode baixá-lo ou usar o seguinte comando do Git para baixá-lo no seu terminal.
Nota: esse código de exemplo deve ser usado para testar a solução e não deve ser usado na conta de produção.
Use o comando a seguir para fazer o packaging do código Python para implantação no Lambda.
Para implementar essa arquitetura de referência, você utilizará os seguintes serviços:
- Amazon Cognito para oferecer suporte a um grupo de usuários para a base de usuários.
- API Gateway para proteger e publicar as APIs.
- Lambda para servir as APIs.
Nota: essa solução foi testada nas regiões us-east-1, us-east-2, us-west-2, ap-southeast-1 e ap-southeast-2. Antes de selecionar uma região, verifique quais serviços necessários (Amazon Cognito, API Gateway e Lambda) estão disponíveis nessas regiões.
Vamos analisar cada serviço e como eles serão usados antes de criar os recursos para essa solução.
Grupo de usuários do Amazon Cognito
Um grupo de usuários (User Pool) é um diretório de usuários no Amazon Cognito. Com um grupo de usuários, os usuários podem fazer login em sua aplicação da web ou dispositivo móvel por meio do Amazon Cognito. Você usa o diretório de usuários do Amazon Cognito diretamente, pois essa solução de exemplo cria um usuário do Amazon Cognito. No entanto, seus usuários também podem fazer login por meio de IdPs sociais, OpenID Connect (OIDC) e SAML.
Lambda como serviço de apoio de API
Inicialmente, você cria uma função Lambda que atende às suas APIs. O API Gateway encaminha todas as solicitações para a função Lambda para atender às solicitações.
Uma instância do API Gateway e integração com o Lambda
Depois, você cria uma instância do API Gateway e a integra à função Lambda que você criou. Essa instância do API Gateway serve como ponto de entrada para o serviço upstream. O comando bash a seguir cria um grupo de usuários do Amazon Cognito, uma função Lambda e uma instância do API Gateway. Em seguida, o comando configura a integração de proxy com o Lambda e implanta um estágio do API Gateway.
Implantar a solução exemplo
No diretório onde você baixou o código de exemplo do GitHub, execute o comando a seguir para gerar uma senha de usuário aleatória do Amazon Cognito e criar os recursos descritos na seção anterior.
Quando o comando é concluído, ele retorna uma mensagem confirmando a criação da pilha(stack).
Validar a criação de usuários do Amazon Cognito
Para validar que um usuário do Amazon Cognito foi criado, execute o seguinte comando para abrir a interface do usuário do Amazon Cognito em seu navegador. Depois, faça login com suas credenciais.
Nota: quando você executa esse comando, ele retorna o nome de usuário e a senha que você deve usar para fazer login.
Como alternativa, você pode abrir a pilha do CloudFormation e obter a URL da interface do usuário hospedada do Amazon Cognito das saídas da pilha (Outputs). A URL é o valor atribuído à variável CognitoHostedUiUrl.
Validar o Amazon Cognito JWT ao fazer login
Como não instalamos uma aplicação da web que responderia à solicitação de redirecionamento, o Amazon Cognito redirecionará para o localhost, o que pode parecer um erro. Após um login bem sucedido, uma URL semelhante à seguinte aparecerá na barra de navegação do seu navegador:
Teste da configuração da API
Antes de proteger a API com o Amazon Cognito para que somente usuários autorizados possam acessá-la, vamos verificar se a configuração está correta e se a API é atendida pelo API Gateway. O comando a seguir faz uma solicitação curl ao API Gateway para recuperar dados do serviço da API.
O resultado esperado é que a resposta seja uma lista de animais de estimação. Nesse caso, a configuração está correta: o API Gateway está servindo a API.
Proteger a API
Para proteger sua API, os itens a seguir são necessários:
- DynamoDB, para armazenar a política que será avaliada pelo API Gateway para tomar uma decisão de autorização.
- Uma função Lambda, para verificar o token de acesso do usuário e pesquisar a política no DynamoDB.
Vamos revisar todos os serviços antes de criar os recursos.
Autorizador do Lambda
Um autorizador do Lambda é um recurso do API Gateway que usa uma função Lambda para controlar o acesso a uma API. Um autorizador do Lambda é usado para implementar um esquema de autorização customizado que usa uma estratégia de autenticação de Bearer Token. Quando um cliente faz uma solicitação para uma das operações de API, o API Gateway chama o autorizador do Lambda. O autorizador do Lambda pega a identidade do chamador como entrada e retorna uma política do IAM como saída. A saída é a política retornada no DynamoDB e avaliada pelo API Gateway. Se não houver uma política mapeada para a identidade do chamador, o Lambda gerará uma política de rejeição e a solicitação será negada.
Tabela do DynamoDB
O DynamoDB é um banco de dados de documentos e chave-valor que oferece performance de um a nove milissegundos em qualquer escala. Isso é ideal para esse caso de uso de forma a garantir que o autorizador do Lambda possa processar rapidamente o Bearer Token, pesquisar a política e devolvê-la ao API Gateway. Para saber mais, consulte Control access for invoking an API (Controle o acesso para invocar uma API).
A etapa final é criar a tabela do DynamoDB para que o autorizador do Lambda procure a política, que é mapeada para um grupo do Amazon Cognito.
A figura 3 ilustra um item no DynamoDB. Os principais atributos são:
- Grupo(group), que é usado para pesquisar a política.
- Política(policy), que é retornada ao API Gateway para avaliar a política.
Com base nessa política, o usuário que faz parte do grupo do Amazon Cognito pet-veterinarian tem permissão para fazer solicitações de API para os endpoints https://<domain>/<api-gateway-stage>/petstore/v1/*
e https://<domain>/<api-gateway-stage>/petstore/v2/status
apenas para solicitações GET.
Atualizar e criar recursos
Execute o comando a seguir para atualizar os recursos existentes e criar um autorizador do Lambda e uma tabela do DynamoDB.
Teste da configuração do autorizador customizado
Comece seu teste com a solicitação a seguir, que não inclui um token de acesso.
A solicitação é negada com a mensagem Não autorizado. Nesse ponto, o Amazon API Gateway espera um cabeçalho chamado Authorization (diferencia maiúsculas de minúsculas) na solicitação. Se não houver cabeçalho de autorização, a solicitação será negada antes de chegar ao autorizador do Lambda. Essa é uma forma de filtrar solicitações que não incluem as informações necessárias.
Use o comando a seguir para o próximo teste. Neste teste, você passa o cabeçalho necessário, mas o token é inválido porque não foi emitido pelo Amazon Cognito; é um token simples no formato JWT armazenado em ./helper.sh. Para saber mais sobre como decodificar e validar um JWT, consulte decode and verify an Amazon Cognito JSON token (decodifique e verifique um token JSON do Amazon Cognito).
Desta vez, a mensagem é diferente. O autorizador do Lambda recebeu a solicitação e identificou o token como inválido e respondeu com a mensagem O usuário não está autorizado a acessar este recurso.
Para ter sucesso em uma solicitação à API protegida, seu código precisará seguir as seguintes etapas:
- Usar um nome de usuário e senha para autenticar no grupo de usuários do Amazon Cognito.
- Adquirir os tokens (token de identidade, token de acesso e token de atualização).
- Fazer uma solicitação HTTPS (TLS) para o API Gateway e passar o token de acesso nos cabeçalhos.
Antes que a solicitação seja encaminhada para o serviço de API, o API Gateway recebe a solicitação e a passa para o autorizador do Lambda. O autorizador executa as seguintes etapas. Se alguma das etapas falhar, a solicitação será negada.
- Recupera as chaves públicas do Amazon Cognito.
- Armazena em cache as chaves públicas para que o autorizador do Lambda não precise fazer chamadas adicionais para o Amazon Cognito, desde que o ambiente de execução do Lambda não seja encerrado.
- Usa chaves públicas para verificar o token de acesso.
- Consulta a política no DynamoDB.
- Retorna a política ao API Gateway.
O token de acesso tem declarações como grupos atribuídos do Amazon Cognito, nome de usuário, uso de token e outros, conforme mostrado no exemplo a seguir (alguns campos foram removidos).
Por fim, vamos fazer login programaticamente na interface do usuário do Amazon Cognito, adquirir um token de acesso válido e fazer uma solicitação ao API Gateway. Execute o comando a seguir para chamar a API protegida.
Desta vez, você recebe uma resposta com dados do serviço da API. Vamos examinar as etapas que o código de exemplo executou:
- O autorizador do Lambda valida o token de acesso.
- O autorizador do Lambda procura a política no DynamoDB com base no nome do grupo que foi recuperado do token de acesso.
- O autorizador do Lambda passa a política do IAM de volta ao API Gateway.
- O API Gateway avalia a política do IAM e o efeito final é allow.
- O API Gateway encaminha a solicitação para o Lambda.
- O Lambda retorna a resposta.
Vamos continuar testando nossa política da figura 3. No documento de política, arn:aws:execute-api:*:*:*/*/GET/petstore/v2/status
é o único endpoint da versão V2, o que significa que as solicitações para o endpoint /GET/petstore/v2/pets
devem ser negadas. Execute o seguinte comando para testar.
Nota: agora que você entendeu o controle de acesso refinado usando o grupo de usuários do Cognito, o API Gateway e a função Lambda e concluiu o teste, execute o seguinte comando para limpar todos os recursos associados a essa solução:
Políticas avançadas do IAM para controlar ainda mais sua API
Com o IAM, você pode criar políticas avançadas para refinar ainda mais o acesso às suas APIs. Você pode saber mais sobre as chaves de condição que podem ser usadas no API Gateway, o uso delas em uma política do IAM com condições e como a lógica de avaliação de políticas determina se deve permitir ou negar uma solicitação.
Resumo
Nesta publicação, você aprendeu como o IAM e o Amazon Cognito podem ser usados para fornecer controle de acesso refinado para sua API por trás do API Gateway. Você pode usar essa abordagem para aplicar de forma transparente um controle refinado à sua API sem precisar modificar o código nela e para criar políticas avançadas usando as chaves de condição do IAM.
Se você tiver algum feedback sobre esta publicação, envie os comentários na seção Comentários abaixo. Se você tiver dúvidas sobre esta publicação, inicie um novo tópico no fórum do Amazon Cognito ou em Entre em contato com o AWS Support.
Este artigo foi traduzido do Blog da AWS em inglês.
Sobre o autor
Artem Lovan é arquiteto sênior de soluções em Nova York. Ele ajuda os clientes a arquitetar e otimizar aplicações na AWS. Seu envolvimento em TI inclui infraestrutura, rede, segurança, DevOps e desenvolvimento de software.