Usar os autorizadores do API Gateway Lambda - Amazon API Gateway

Usar os autorizadores do API Gateway Lambda

Use um autorizador do Lambda (anteriormente conhecido como autorizador personalizado) para controlar o acesso à API. Quando um cliente solicita o método da API, o API Gateway chama o autorizador do Lambda. O autorizador do Lambda usa a identidade do chamador como entrada e retorna uma política do IAM como saída.

Use um autorizador do Lambda para implementar um esquema de autorização personalizado. O esquema pode usar parâmetros de solicitação para determinar a identidade do chamador ou usar uma estratégia de autenticação de token de portador, como OAuth ou SAML. Crie um autorizador do Lambda no console da API REST do API Gateway, usando a AWS CLI ou um SDK da AWS.

Fluxo de trabalho de autorização do autorizador do Lambda

O diagrama a seguir mostra o fluxo de trabalho de autorização referente a um autorizador do Lambda.

Fluxo de trabalho de autorização do Lambda do API Gateway
Fluxo de trabalho de autorização do Lambda do API Gateway
  1. O cliente chama um método em uma API do API Gateway, passando um token de portador ou parâmetros de solicitação.

  2. O API Gateway verifica se a solicitação do método está configurada com um autorizador do Lambda. Se estiver, o API Gateway chama a função do Lambda.

  3. A função do Lambda autentica o chamador. A função pode fazer a autenticação das seguintes maneiras:

    • Chamando um provedor OAuth para receber um token de acesso OAuth.

    • Chamando um provedor SAML para receber uma declaração SAML.

    • Gerando uma política do IAM com base nos valores do parâmetro de solicitação.

    • Recuperando as credenciais de um banco de dados.

  4. A função do Lambda retorna uma política do IAM e um identificador de entidade principal. Se a função do Lambda não retornar essas informações, a chamada falhará.

  5. O API Gateway avalia a política do IAM.

    • Se o acesso for negado, o API Gateway retornará um código de status HTTP, por exemplo, 403 ACCESS_DENIED.

    • Se o acesso for permitido, o API Gateway invocará o método.

      Se você habilitar o armazenamento em cache da autorização, o API Gateway armazenará a política em cache para que a função do autorizador do Lamba não seja invocada novamente.

É possível personalizar as respostas 403 ACCESS_DENIED ou 401 UNAUTHORIZED do gateway. Para saber mais, consulte Respostas de gateway no API Gateway.

Como escolher um tipo de autorizador do Lambda

Existem dois tipos de autorizadores do Lambda:

Solicitar um autorizador do Lambda baseado em parâmetros (autorizador REQUEST)

Um autorizador REQUEST recebe a identidade do chamador em uma combinação de cabeçalhos, parâmetros de strings de consulta, stageVariables e variáveis $context. É possível usar um autorizador REQUEST para criar políticas refinadas com base nas informações de várias fontes de identidade, como as variáveis de contexto $context.path e $context.httpMethod.

Se você ativar o armazenamento em cache de autorização para um autorizador REQUEST, o API Gateway verificará se todas as fontes de identidade especificadas estão presentes na solicitação. Se uma fonte de identidade especificada estiver ausente, for nula ou estiver vazia, o API Gateway retornará uma resposta HTTP 401 Unauthorized sem chamar a função do autorizador do Lambda. Quando há várias fontes de identidade definidas, todas são usadas para derivar a chave de cache do autorizador, preservando a ordem. É possível definir uma chave de cache refinada usando várias fontes de identidade.

Se você alterar qualquer parte da chave do cache e reimplantar a API, o autorizador descartará o documento da política em cache e gerará outro.

Se você desativar o armazenamento em cache de autorização para um autorizador REQUEST, o API Gateway passará a solicitação diretamente à função do Lambda.

Autorizador do Lambda com base em token (autorizador TOKEN)

Um autorizador TOKEN recebe a identidade do chamador em um token de portador, como um JSON Web Token (JWT) ou um token OAuth.

Se você ativar o armazenamento em cache de autorização para um autorizador TOKEN, o nome do cabeçalho especificado na origem do token será a chave do cache.

Além disso, é possível usar a validação de token para inserir uma instrução RegEx. O API Gateway executa a validação inicial do token de entrada em relação a essa expressão e invoca a função do autorizador do Lambda mediante a validação com êxito. Isso ajuda a reduzir as chamadas para a API.

A propriedade IdentityValidationExpression é compatível somente com autorizadores TOKEN. Para ter mais informações, consulte Objeto x-amazon-apigateway-authorizer.

nota

Recomendamos que você use um autorizador REQUEST para controlar o acesso à API. É possível controlar o acesso à API com base em várias fontes de identidade ao usar um autorizador REQUEST, em comparação com uma única fonte de identidade ao usar um autorizador TOKEN. Além disso, você pode separar as chaves de cache usando várias fontes de identidade para um autorizador REQUEST.

Exemplo de função do Lambda do autorizador REQUEST

O código de exemplo a seguir criará uma função do autorizador do Lambda que permite uma solicitação se o cabeçalho HeaderAuth1, o parâmetro de consulta QueryString1 e a variável de estágio de StageVar1 fornecidos pelo cliente corresponderem aos valores especificados de headerValue1, queryValue1 e stageValue1, respectivamente.

Node.js
// A simple request-based authorizer example to demonstrate how to use request // parameters to allow or deny a request. In this example, a request is // authorized if the client-supplied HeaderAuth1 header, QueryString1 // query parameter, and stage variable of StageVar1 all match // specified values of 'headerValue1', 'queryValue1', and 'stageValue1', // respectively. export const handler = function(event, context, callback) { console.log('Received event:', JSON.stringify(event, null, 2)); // Retrieve request parameters from the Lambda function input: var headers = event.headers; var queryStringParameters = event.queryStringParameters; var pathParameters = event.pathParameters; var stageVariables = event.stageVariables; // Parse the input for the parameter values var tmp = event.methodArn.split(':'); var apiGatewayArnTmp = tmp[5].split('/'); var awsAccountId = tmp[4]; var region = tmp[3]; var restApiId = apiGatewayArnTmp[0]; var stage = apiGatewayArnTmp[1]; var method = apiGatewayArnTmp[2]; var resource = '/'; // root resource if (apiGatewayArnTmp[3]) { resource += apiGatewayArnTmp[3]; } // Perform authorization to return the Allow policy for correct parameters and // the 'Unauthorized' error, otherwise. var authResponse = {}; var condition = {}; condition.IpAddress = {}; if (headers.HeaderAuth1 === "headerValue1" && queryStringParameters.QueryString1 === "queryValue1" && stageVariables.StageVar1 === "stageValue1") { callback(null, generateAllow('me', event.methodArn)); } else { callback("Unauthorized"); } } // Help function to generate an IAM policy var generatePolicy = function(principalId, effect, resource) { // Required output: var authResponse = {}; authResponse.principalId = principalId; if (effect && resource) { var policyDocument = {}; policyDocument.Version = '2012-10-17'; // default version policyDocument.Statement = []; var statementOne = {}; statementOne.Action = 'execute-api:Invoke'; // default action statementOne.Effect = effect; statementOne.Resource = resource; policyDocument.Statement[0] = statementOne; authResponse.policyDocument = policyDocument; } // Optional output with custom properties of the String, Number or Boolean type. authResponse.context = { "stringKey": "stringval", "numberKey": 123, "booleanKey": true }; return authResponse; } var generateAllow = function(principalId, resource) { return generatePolicy(principalId, 'Allow', resource); } var generateDeny = function(principalId, resource) { return generatePolicy(principalId, 'Deny', resource); }
Python
# A simple request-based authorizer example to demonstrate how to use request # parameters to allow or deny a request. In this example, a request is # authorized if the client-supplied HeaderAuth1 header, QueryString1 # query parameter, and stage variable of StageVar1 all match # specified values of 'headerValue1', 'queryValue1', and 'stageValue1', # respectively. import json def lambda_handler(event, context): print(event) # Retrieve request parameters from the Lambda function input: headers = event['headers'] queryStringParameters = event['queryStringParameters'] pathParameters = event['pathParameters'] stageVariables = event['stageVariables'] # Parse the input for the parameter values tmp = event['methodArn'].split(':') apiGatewayArnTmp = tmp[5].split('/') awsAccountId = tmp[4] region = tmp[3] restApiId = apiGatewayArnTmp[0] stage = apiGatewayArnTmp[1] method = apiGatewayArnTmp[2] resource = '/' if (apiGatewayArnTmp[3]): resource += apiGatewayArnTmp[3] # Perform authorization to return the Allow policy for correct parameters # and the 'Unauthorized' error, otherwise. authResponse = {} condition = {} condition['IpAddress'] = {} if (headers['HeaderAuth1'] == "headerValue1" and queryStringParameters['QueryString1'] == "queryValue1" and stageVariables['StageVar1'] == "stageValue1"): response = generateAllow('me', event['methodArn']) print('authorized') return json.loads(response) else: print('unauthorized') raise Exception('Unauthorized') # Return a 401 Unauthorized response return 'unauthorized' # Help function to generate IAM policy def generatePolicy(principalId, effect, resource): authResponse = {} authResponse['principalId'] = principalId if (effect and resource): policyDocument = {} policyDocument['Version'] = '2012-10-17' policyDocument['Statement'] = [] statementOne = {} statementOne['Action'] = 'execute-api:Invoke' statementOne['Effect'] = effect statementOne['Resource'] = resource policyDocument['Statement'] = [statementOne] authResponse['policyDocument'] = policyDocument authResponse['context'] = { "stringKey": "stringval", "numberKey": 123, "booleanKey": True } authResponse_JSON = json.dumps(authResponse) return authResponse_JSON def generateAllow(principalId, resource): return generatePolicy(principalId, 'Allow', resource) def generateDeny(principalId, resource): return generatePolicy(principalId, 'Deny', resource)

Neste exemplo, a função do autorizador do Lambda verifica os parâmetros de entrada e age da seguinte forma:

  • Se todos os valores de parâmetro necessários corresponderem aos valores esperados, a função do autorizador retornará uma resposta HTTP 200 OK e uma política do IAM que é semelhante ao seguinte, e a solicitação de método será bem-sucedida:

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Allow", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
  • Caso contrário, a função do autorizador retornará uma resposta HTTP 401 Unauthorized e ocorrerá uma falha na solicitação do método.

Além de retornar uma política do IAM, a função de autorizador do Lambda também deve retornar o identificador principal do autor da chamada. Opcionalmente, ela pode retornar um objeto context com informações adicionais que podem ser passadas ao back-end de integração. Para ter mais informações, consulte Saída de um autorizador do Lambda para o API Gateway.

No código de produção, talvez seja necessário autenticar o usuário antes de conceder a autorização. É possível adicionar a lógica de autenticação à função do Lambda chamando um provedor de autenticação conforme indicado na documentação desse provedor.

Exemplo de função do Lambda do autorizador TOKEN

O código de exemplo a seguir cria uma função do Lambda do autorizador TOKEN que permite que um chamador invoque um método caso o valor do token fornecido pelo cliente seja allow. O chamador não tem permissão para invocar a solicitação caso o valor do token seja deny. Se o valor do token for unauthorized ou uma string vazia, a função do autorizador retornará uma resposta 401 UNAUTHORIZED.

Node.js
// A simple token-based authorizer example to demonstrate how to use an authorization token // to allow or deny a request. In this example, the caller named 'user' is allowed to invoke // a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke // the request if the token value is 'deny'. If the token value is 'unauthorized' or an empty // string, the authorizer function returns an HTTP 401 status code. For any other token value, // the authorizer returns an HTTP 500 status code. // Note that token values are case-sensitive. export const handler = function(event, context, callback) { var token = event.authorizationToken; switch (token) { case 'allow': callback(null, generatePolicy('user', 'Allow', event.methodArn)); break; case 'deny': callback(null, generatePolicy('user', 'Deny', event.methodArn)); break; case 'unauthorized': callback("Unauthorized"); // Return a 401 Unauthorized response break; default: callback("Error: Invalid token"); // Return a 500 Invalid token response } }; // Help function to generate an IAM policy var generatePolicy = function(principalId, effect, resource) { var authResponse = {}; authResponse.principalId = principalId; if (effect && resource) { var policyDocument = {}; policyDocument.Version = '2012-10-17'; policyDocument.Statement = []; var statementOne = {}; statementOne.Action = 'execute-api:Invoke'; statementOne.Effect = effect; statementOne.Resource = resource; policyDocument.Statement[0] = statementOne; authResponse.policyDocument = policyDocument; } // Optional output with custom properties of the String, Number or Boolean type. authResponse.context = { "stringKey": "stringval", "numberKey": 123, "booleanKey": true }; return authResponse; }
Python
# A simple token-based authorizer example to demonstrate how to use an authorization token # to allow or deny a request. In this example, the caller named 'user' is allowed to invoke # a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke # the request if the token value is 'deny'. If the token value is 'unauthorized' or an empty # string, the authorizer function returns an HTTP 401 status code. For any other token value, # the authorizer returns an HTTP 500 status code. # Note that token values are case-sensitive. import json def lambda_handler(event, context): token = event['authorizationToken'] if token == 'allow': print('authorized') response = generatePolicy('user', 'Allow', event['methodArn']) elif token == 'deny': print('unauthorized') response = generatePolicy('user', 'Deny', event['methodArn']) elif token == 'unauthorized': print('unauthorized') raise Exception('Unauthorized') # Return a 401 Unauthorized response return 'unauthorized' try: return json.loads(response) except BaseException: print('unauthorized') return 'unauthorized' # Return a 500 error def generatePolicy(principalId, effect, resource): authResponse = {} authResponse['principalId'] = principalId if (effect and resource): policyDocument = {} policyDocument['Version'] = '2012-10-17' policyDocument['Statement'] = [] statementOne = {} statementOne['Action'] = 'execute-api:Invoke' statementOne['Effect'] = effect statementOne['Resource'] = resource policyDocument['Statement'] = [statementOne] authResponse['policyDocument'] = policyDocument authResponse['context'] = { "stringKey": "stringval", "numberKey": 123, "booleanKey": True } authResponse_JSON = json.dumps(authResponse) return authResponse_JSON

Neste exemplo, quando a API recebe uma solicitação de método, o API Gateway repassa o token de origem para essa função do autorizador do Lambda no atributo event.authorizationToken. A função do autorizador do Lambda lê o token e age da seguinte forma:

  • Se o valor do token for allow, a função do autorizador retornará uma resposta HTTP 200 OK e uma política do IAM que é semelhante ao seguinte, e a solicitação de método será bem-sucedida:

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Allow", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
  • Se o valor do token for deny, a função do autorizador retornará uma resposta HTTP 200 OK e uma política do IAM Deny que é semelhante ao seguinte, e ocorrerá uma falha na solicitação de método:

    { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Deny", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
    nota

    Fora do ambiente de teste, o API Gateway retorna uma resposta HTTP 403 Forbidden e ocorre uma falha na solicitação do método.

  • Se o valor do token for unauthorized, a função do autorizador retornará uma resposta HTTP 401 Unauthorized, e ocorrerá uma falha na chamada de método.

  • Se o valor do token for diferente, o cliente receberá uma resposta 500 Invalid token, e ocorrerá uma falha na chamada de método.

Além de retornar uma política do IAM, a função de autorizador do Lambda também deve retornar o identificador principal do autor da chamada. Opcionalmente, ela pode retornar um objeto context com informações adicionais que podem ser passadas ao back-end de integração. Para ter mais informações, consulte Saída de um autorizador do Lambda para o API Gateway.

No código de produção, talvez seja necessário autenticar o usuário antes de conceder a autorização. É possível adicionar a lógica de autenticação à função do Lambda chamando um provedor de autenticação conforme indicado na documentação desse provedor.

Exemplos adicionais de funções do autorizador do Lambda

A lista a seguir mostra exemplos adicionais de funções do autorizador do Lambda. É possível criar uma função do Lambda na mesma conta em que você criou a API ou em uma conta diferente.

No exemplo anterior de funções do Lambda, é possível usar a função integrada AWSLambdaBasicExecutionRole, já que essas funções não chamam outros serviços da AWS. Se a função do Lambda chamar outros serviços da AWS, será necessário atribuir um perfil de execução do IAM à função do Lambda. Para criar a função, siga as instruções na Função de execução AWS Lambda.

Exemplo adicional de funções do autorizador do Lambda