O blog da AWS
Autenticação e Controle de Sessão no API Gateway com Lambda e JWT
Por Matheus Lima, Consultor de Infraestrutura AWS
Introdução
A implementação de controle de sessão é parte fundamental do processo de autenticação de usuários para qualquer tipo de aplicação. A estratégia utilizada popularmente no passado dependia de sistemas de arquivos locais ou banco de dados para armazenar o estado do acesso do usuário. Esta abordagem apresenta limitações quando falamos de ambientes distribuídos que escalam horizontalmente e de forma elástica, como na nuvem. Isto ocorre pois, caso o servidor que armazena o estado seja interrompido ou o banco de dados esteja no limite de capacidade, o estado que informa quais usuários que estão logados na aplicação são perdidos ou não estão disponíveis no momento. Com o objetivo de transpor estas limitações um novo paradigma serverless é proposto baseado em AWS Lambda, API Gateway e JWT.
Serviços
Amazon API Gateway
O Amazon API Gateway é um serviço totalmente gerenciado que permite que desenvolvedores criem, publiquem, mantenham, monitorem e protejam APIs em qualquer escala. Com apenas alguns cliques no Console de Gerenciamento da AWS, você pode criar uma API que atua como uma “porta de entrada” para que aplicativos acessem dados, lógica de negócios ou funcionalidades a partir de serviços de back-end, como cargas de trabalho executadas no Amazon Elastic Compute Cloud (Amazon EC2), código executado no AWS Lambda ou qualquer aplicação web. O Amazon API Gateway processa todas as tarefas relacionadas à aceitação e ao processamento de até centenas de milhares de chamadas simultâneas de APIs, incluindo gerenciamento de tráfego, autorização e controle de acesso, monitoramento e gerenciamento de versões de APIs. O Amazon API Gateway não tem taxas mínimas ou custos antecipados. Você paga apenas pelas chamadas de API recebidas e pela quantidade transferida de dados de saída.
AWS Lambda
O AWS Lambda é um serviço de computação sem servidor que executa seu código em resposta a eventos e gerencia automaticamente os recursos computacionais adjacentes para você. Você pode usar o AWS Lambda para estender outros serviços da AWS com lógica personalizada ou criar seus próprios serviços de back-end que operam na escala, desempenho e segurança da AWS. O AWS Lambda pode executar automaticamente códigos em resposta a múltiplos eventos, como modificações a objetos em buckets do Amazon S3 ou atualizações de tabela no Amazon DynamoDB.
O Lambda executa seu código em infraestrutura de computação de alta disponibilidade e realiza toda a administração dos recursos de computação, incluindo manutenção de servidor e de sistema operacional, provisionamento de capacidade e escalabilidade automática, implementação de código e de patch de segurança e monitoramento e registro de código. Tudo o que você precisa fazer é fornecer o código.
JWT
JSON Web Token(JWT) é um padrão aberto para criação de tokens de acesso, permitindo a implementação de mecanismo de controle de sessão de forma segura(O algoritmo utilizado é HS256). Por exemplo, um servidor poderia gerar um token que afirma que o usuário logado é um administrador e o fornecer à aplicação cliente. O cliente por sua vez poderia utilizar este token posteriormente para provar que está logado como administrador. Tipicamente o token é armazenado localmente(seja no disco local, memória – no caso de dispositivos mobile ou mesmo Cookies para dispositivos Desktop). Como será observado posteriormente, a implementação é totalmente stateless para o backend, sendo portanto uma abordagem altamente recomendada para aplicações distribuídas, como na nuvem e que escalam horizontalmente. Não há necessidade de consultar qualquer banco de dados para validação do token uma vez que ele armazena todas as informações necessárias para autenticação, sendo desta forma autocontido.
Exemplo Token JSON Decodificado:
Exemplo Token JSON Codificado:
Custom Authorizer – API Gateway
O Custom Authorizer fornecido pelo Amazon API Gateway é uma função Lambda que disponibiliza controle de acesso para suas APIs mediante estratégias de autenticação de token de portador, como OAuth e SAML. Em outra palavras, quando um cliente chama uma API o API Gateway verifica se o Custom Authorizer esta configurado para a API. Se sim, então o API Gateway chama a função Lambda, fornecendo o token de autorização extraído do header da requisição especificada. Você portanto deve utilizar esta função Lambda para implementar a estratégia de autorização pertinente, como por exemplo JSON Web Token(JWT). Abaixo segue diagrama do fluxo descrito[1]:
Pré-requisito:
Faça o download do código-fonte de exemplo que possui as bibliotecas JWT necessárias.
Passo a passo:
Crie uma nova função Lambda com o pacote ZIP enviado.
Preencha os seguintes campos conforme a instrução:
Handler: <nome do arquivo sem extensão .py>.<nome do método a ser chamado quando a função for executada>, neste exemplo a. lambda_handler.
Runtime: Pyhthon 2.7
Role: lambda_basic_execution
Após preencher o formulário, confirme a criação da função.
Agora vamos adicionar o mecanismo de autenticação(ie Custom Authorizer) a uma API já existente no API Gateway. Neste exemplo para uma requisição HTTP GET em /usuário:
Abra a opção “Authorizers”, na lateral esquerda:
Crie um novo Custom Authorizers e preencha o formulário como segue:
Lambda Region: Escolha a região que a função Lambda foi criada anteriormente.
Lambda function: Nome da função Lambda criada anteriormente
Authorizer name: Nome para o Custom Authorizer
Identity token source*: utilize por exemplo method.request.header.Authorization.
Volte para a opção Resources, no menu lateral e abra novamente o método GET, em seguida abra a caixa Method Request.
No campo Authorization escolha o Custom Authorizer criado anteriormente(nomeado JWT) e confirme.
Expanda a opção HTTP Request Headers, clique em Add header e digite Authorization e Salve.
Volte e abra Integration Request, expanda Body Mapping Templates, clique em Add mapping template, digite application/json e confirme:
No campo Generate template, escolha Method Request passthrough. Com isso o template será automaticamente preenchido:
Entretanto ainda precisamos adicionar o campo username. Para realizar isso adicione ao item context o seguinte conteúdo:
“Username”: “$context.authorizer.principalId” e Salve:
Teste
Antes de testar precisamos promover a API para um Stage novo ou existente. Para isso, volte em Resources, clique em Actions, Deploy API e crie um novo Deployment Stage ou escolha algum existente:
Escolha um nome para o novo Stage e clique em Deploy:
Agora um novo Stage foi criado com o nome Dev. Você pode acessa –lo dentro da opção Stage, no menu lateral:
Agora precisamos do path criado automaticamente pelo API Gateway para realizar chamadas à nossa API. Para isso expanda o Stage (Dev neste caso) até o método GET que criamos anteriormente:
Copie o conteúdo de Invoke URL.
Antes de finalmente testarmos é necessário criarmos um token JWT válido, para isso segue um código em Python 2.7 que pode ser usado para gerar o mesmo. Ele pode ser executado em qualquer ambiente que possua o Python 2.7 runtime instalado, como na sua própria máquina:
import jwt,datetime,re
payload = {
"UserName":"Matheus",
'exp': datetime.datetime.utcnow()
}
#Encode the payload
secret = 'my-secret'
encoded = jwt.encode(payload, secret, algorithm='HS256')
request ={
"authorizationToken" : encoded
}
No código de exemplo do Custom Authorizer(Upload realizado no início do artigo), estou considerando um tempo de expiração de 15 minutos mas isso pode ser alterado em:
decoded=jwt.decode(token, secret, algorithms=[‘HS256′],leeway=datetime.timedelta(minutes=15))
Execução:
<p>$ python sample.py</p><p>{'authorizationToken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VyTmFtZSI6Ik1hdGhldXMiLCJleHAiOjE0ODg1Njc0NzV9.EFs_OeJxQ0fBUIAPEJ2135YPbfmmnZkQsZQMknQ_Fdk'}</p>
Copie o token gerado na tela.
Para testes estamos utilizando o Postman, plugin do Chrome para realização de requisições HTTP que tem o objetivo de facilitar o desenvolvimento de APIs.
Para testar com o Postman crie uma nova aba, escolha o verbo HTTP apropriado(GET neste caso) e preencha a URL com o conteúdo copiado anteriormente de Invoke URL(API Gateway – Stage). Antes de cliquar em Send, abra a seção Headers, adicione a chave Authorization e em valor insira o token gerado na etapa anterior:
Ao cliquar em Send, a requisição concluída.
Para demonstrarmos que a validação do token está de fato sendo verificada, inserimos um valor qualquer no Authorization:
E conforme observado na imagem acima, o acesso foi negado.
Referência:
[1] https://jwt.io/
[2] http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html
[3] https://www.getpostman.com/