Uso de autorizadores de AWS Lambda para API HTTP - Amazon API Gateway

Uso de autorizadores de AWS Lambda para API HTTP

El autorizador de Lambda se utiliza para emplear una función de Lambda para controlar el acceso a una API HTTP. Después, cuando un cliente llama a dicha API, API Gateway invoca la función de Lambda. API Gateway utiliza la respuesta de su función de Lambda para determinar si el cliente puede acceder a la API.

Versión de formato de carga

La versión del formato de carga del autorizador especifica el formato de los datos que API Gateway envía a un autorizador de Lambda y cómo API Gateway interpreta la respuesta de Lambda. Si no especifica una versión de formato de carga, la AWS Management Console utiliza la versión más reciente de forma predeterminada. Si crea un autorizador de Lambda mediante la AWS CLI, AWS CloudFormation o un SDK, debe especificar una authorizerPayloadFormatVersion. Los valores admitidos son 1.0 y 2.0.

Si necesita compatibilidad con las API de REST, utilice la versión 1.0.

Los siguientes ejemplos muestran la estructura de cada versión de formato de carga.

2.0
{ "version": "2.0", "type": "REQUEST", "routeArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request", "identitySource": ["user1", "123"], "routeKey": "$default", "rawPath": "/my/path", "rawQueryString": "parameter1=value1&parameter1=value2&parameter2=value", "cookies": ["cookie1", "cookie2"], "headers": { "header1": "value1", "header2": "value2" }, "queryStringParameters": { "parameter1": "value1,value2", "parameter2": "value" }, "requestContext": { "accountId": "123456789012", "apiId": "api-id", "authentication": { "clientCert": { "clientCertPem": "CERT_CONTENT", "subjectDN": "www.example.com", "issuerDN": "Example issuer", "serialNumber": "1", "validity": { "notBefore": "May 28 12:30:02 2019 GMT", "notAfter": "Aug 5 09:36:04 2021 GMT" } } }, "domainName": "id.execute-api.us-east-1.amazonaws.com", "domainPrefix": "id", "http": { "method": "POST", "path": "/my/path", "protocol": "HTTP/1.1", "sourceIp": "IP", "userAgent": "agent" }, "requestId": "id", "routeKey": "$default", "stage": "$default", "time": "12/Mar/2020:19:03:58 +0000", "timeEpoch": 1583348638390 }, "pathParameters": { "parameter1": "value1" }, "stageVariables": { "stageVariable1": "value1", "stageVariable2": "value2" } }
1.0
{ "version": "1.0", "type": "REQUEST", "methodArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request", "identitySource": "user1,123", "authorizationToken": "user1,123", "resource": "/request", "path": "/request", "httpMethod": "GET", "headers": { "X-AMZ-Date": "20170718T062915Z", "Accept": "*/*", "HeaderAuth1": "headerValue1", "CloudFront-Viewer-Country": "US", "CloudFront-Forwarded-Proto": "https", "CloudFront-Is-Tablet-Viewer": "false", "CloudFront-Is-Mobile-Viewer": "false", "User-Agent": "..." }, "queryStringParameters": { "QueryString1": "queryValue1" }, "pathParameters": {}, "stageVariables": { "StageVar1": "stageValue1" }, "requestContext": { "path": "/request", "accountId": "123456789012", "resourceId": "05c7jb", "stage": "test", "requestId": "...", "identity": { "apiKey": "...", "sourceIp": "...", "clientCert": { "clientCertPem": "CERT_CONTENT", "subjectDN": "www.example.com", "issuerDN": "Example issuer", "serialNumber": "a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1", "validity": { "notBefore": "May 28 12:30:02 2019 GMT", "notAfter": "Aug 5 09:36:04 2021 GMT" } } }, "resourcePath": "/request", "httpMethod": "GET", "apiId": "abcdef123" } }

Formato de respuesta del autorizador de Lambda

La versión del formato de carga también determina la estructura de la respuesta que debe devolver de su función de Lambda.

Respuesta de función de Lambda para el formato 1.0

Si elige la versión de formato 1.0, los autorizadores de Lambda deben devolver una política de IAM que permita o deniegue el acceso a su ruta de la API. Puede utilizar la sintaxis de política de IAM estándar en la política. Para obtener algunos ejemplos de políticas de IAM, consulte Controlar el acceso para invocar una API. Puede transmitir propiedades de contexto a integraciones o registros de acceso de Lambda mediante $context.authorizer.property. El objeto context es opcional y claims es un marcador de posición reservado y no se puede utilizar como objeto de contexto. Para obtener más información, consulte Personalización de registros de acceso de las API HTTP.

{ "principalId": "abcdef", // The principal user identification associated with the token sent by the client. "policyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Allow|Deny", "Resource": "arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/[{resource}/[{child-resources}]]" } ] }, "context": { "exampleKey": "exampleValue" } }

Respuesta de función de Lambda para el formato 2.0

Si elige la versión de formato 2.0, puede devolver un valor booleano o una política de IAM que utilice la sintaxis de la política de IAM estándar de la función de Lambda. Para devolver un valor booleano, habilite respuestas simples para el autorizador. Los siguientes ejemplos muestran el formato que debe utilizar para codificar la devolución de la función de Lambda. El objeto context es opcional. Puede transmitir propiedades de contexto a integraciones o registros de acceso de Lambda mediante $context.authorizer.property. Para obtener más información, consulte Personalización de registros de acceso de las API HTTP.

Simple response
{ "isAuthorized": true/false, "context": { "exampleKey": "exampleValue" } }
IAM policy
{ "principalId": "abcdef", // The principal user identification associated with the token sent by the client. "policyDocument": { "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Allow|Deny", "Resource": "arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/[{resource}/[{child-resources}]]" } ] }, "context": { "exampleKey": "exampleValue" } }

Ejemplo de funciones de autorizador de Lambda

El siguiente ejemplo de funciones de Lambda Node.js muestran los formatos de respuesta necesarios que debe devolver desde la función de Lambda para la versión del formato de carga 2.0.

Simple response - Node.js
export const handler = async(event) => { let response = { "isAuthorized": false, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": true, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } }; if (event.headers.authorization === "secretToken") { console.log("allowed"); response = { "isAuthorized": true, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": true, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } }; } return response; };
Simple response - Python
import json def lambda_handler(event, context): response = { "isAuthorized": False, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": True, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } } try: if (event["headers"]["authorization"] == "secretToken"): response = { "isAuthorized": True, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": True, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } } print('allowed') return response else: print('denied') return response except BaseException: print('denied') return response
IAM policy - Node.js
export const handler = async(event) => { if (event.headers.authorization == "secretToken") { console.log("allowed"); return { "principalId": "abcdef", // The principal user identification associated with the token sent by the client. "policyDocument": { "Version": "2012-10-17", "Statement": [{ "Action": "execute-api:Invoke", "Effect": "Allow", "Resource": event.routeArn }] }, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": true, "arrayKey": ["value1", "value2"], "mapKey": { "value1": "value2" } } }; } else { console.log("denied"); return { "principalId": "abcdef", // The principal user identification associated with the token sent by the client. "policyDocument": { "Version": "2012-10-17", "Statement": [{ "Action": "execute-api:Invoke", "Effect": "Deny", "Resource": event.routeArn }] }, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": true, "arrayKey": ["value1", "value2"], "mapKey": { "value1": "value2" } } }; } };
IAM policy - Python
import json def lambda_handler(event, context): response = { # The principal user identification associated with the token sent by # the client. "principalId": "abcdef", "policyDocument": { "Version": "2012-10-17", "Statement": [{ "Action": "execute-api:Invoke", "Effect": "Deny", "Resource": event["routeArn"] }] }, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": True, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } } try: if (event["headers"]["authorization"] == "secretToken"): response = { # The principal user identification associated with the token # sent by the client. "principalId": "abcdef", "policyDocument": { "Version": "2012-10-17", "Statement": [{ "Action": "execute-api:Invoke", "Effect": "Allow", "Resource": event["routeArn"] }] }, "context": { "stringKey": "value", "numberKey": 1, "booleanKey": True, "arrayKey": ["value1", "value2"], "mapKey": {"value1": "value2"} } } print('allowed') return response else: print('denied') return response except BaseException: print('denied') return response

Fuentes de identidad

Opcionalmente, puede especificar orígenes de identidad para un autorizador de Lambda. Los orígenes de identidad especifican la ubicación de los datos necesarios para autorizar una solicitud. Por ejemplo, puede especificar valores de cabecera o cadena de consulta como orígenes de identidad. Si especifica orígenes de identidad, los clientes deben incluirlos en la solicitud. Si la solicitud del cliente no incluye los orígenes de identidad, API Gateway no invoca el autorizador de Lambda y el cliente recibe un error 401. Se admiten los siguientes orígenes de identidad:

Expresiones de selección
Tipo Ejemplo Notas
Valor del encabezado $request.header.name Los nombres del encabezado no distinguen entre mayúsculas y minúsculas.
Valor de la cadena de consulta $request.querystring.name Los nombres de las cadenas de consulta distinguen mayúsculas y minúsculas.
Variable de contexto $contexto.variableName El valor de una variable de contexto compatible.
Variable de etapa $stageVariables.variableName El valor de una variable de etapa.

Almacenamiento en caché de las respuestas de los autorizadores

Para habilitar el almacenamiento en caché de un autorizador de Lambda debe especificar un authorizerResultTtlInSeconds. Cuando el almacenamiento en caché está habilitado para un autorizador, API Gateway utiliza los orígenes de identidad del autorizador como clave de caché. Si un cliente especifica los mismos parámetros en orígenes de identidad dentro del TTL configurado, API Gateway utiliza el resultado del autorizador almacenado en caché, en lugar de invocar su función de Lambda.

Para habilitar el almacenamiento en caché, el autorizador debe tener al menos un origen de identidad.

Si habilita respuestas simples para un autorizador, la respuesta del autorizador permite o deniega completamente todas las solicitudes de la API que coincidan con los valores de origen de identidad almacenados en caché. Para obtener permisos pormenorizados, desactive las respuestas simples y devuelva una política de IAM.

De forma predeterminada, API Gateway utiliza la respuesta del autorizador almacenada en caché para todas las rutas de una API que utiliza el autorizador. Para almacenar en caché las respuestas por ruta, agregue $context.routeKey a las fuentes de identidad del autorizador.

Crear un autorizador de Lambda

Al crear un autorizador de Lambda, se especifica la función de Lambda que utilizará API Gateway. Debe conceder permiso de API Gateway para invocar la función de Lambda mediante la política de recursos de la función o un rol de IAM. En este ejemplo, actualizamos la política de recursos de la función para que otorgue a API Gateway permiso para invocar la función de Lambda.

aws apigatewayv2 create-authorizer \ --api-id abcdef123 \ --authorizer-type REQUEST \ --identity-source '$request.header.Authorization' \ --name lambda-authorizer \ --authorizer-uri 'arn:aws:apigateway:us-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:us-west-2:123456789012:function:my-function/invocations' \ --authorizer-payload-format-version '2.0' \ --enable-simple-responses

El siguiente comando otorga permiso a API Gateway para invocar la función de Lambda. Si API Gateway no tiene permiso para invocar la función, los clientes reciben un 500 Internal Server Error.

aws lambda add-permission \ --function-name my-authorizer-function \ --statement-id apigateway-invoke-permissions-abc123 \ --action lambda:InvokeFunction \ --principal apigateway.amazonaws.com \ --source-arn "arn:aws:execute-api:us-west-2:123456789012:api-id/authorizers/authorizer-id"

Una vez se haya creado un autorizador y concedido permiso a API Gateway para invocarlo, actualice la ruta para poder utilizarlo.

aws apigatewayv2 update-route \ --api-id abcdef123 \ --route-id acd123 \ --authorization-type CUSTOM \ --authorizer-id def123

Resolución de problemas de los autorizadores de Lambda

Si API Gateway no puede invocar su autorizador de Lambda, o su autorizador de Lambda devuelve una respuesta en un formato no válido, los clientes recibirán un 500 Internal Server Error.

Para solucionar errores, habilite el registro de acceso en la etapa de la API. Incluya la variable de registro $context.authorizer.error en su formato de registro.

Si los registros indican que API Gateway no tiene permiso para invocar la función, actualice la política de recursos de la función o proporcione un rol de IAM para conceder permiso a API Gateway para invocar el autorizador.

Si los registros indican que la función de Lambda devuelve una respuesta no válida, compruebe que la función de Lambda devuelve una respuesta en el formato requerido.