¿Por qué mi recurso proxy de API Gateway con un autorizador de Lambda que tiene activado el almacenamiento en caché devuelve errores HTTP 403 “User is not authorized to access this resource” (El usuario no está autorizado a acceder a este recurso)?

6 minutos de lectura
0

Mi recurso proxy de Amazon API Gateway con un autorizador de AWS Lambda que tiene activado el almacenamiento en caché devuelve el siguiente mensaje de error HTTP 403: “User is not authorized to access this resource” (El usuario no está autorizado a acceder a este recurso). ¿Por qué sucede este error y cómo puedo resolverlo?

Descripción corta

Nota: API Gateway puede devolver errores 403 El usuario no está autorizado a acceder a este recurso por varias razones. En este artículo, se abordan los errores 403 relacionados con los recursos proxy de API Gateway con un autorizador de Lambda que solo tiene activado el almacenamiento en caché. Para obtener información sobre cómo solucionar otros tipos de errores 403, consulte ¿Cómo soluciono los errores HTTP 403 de API Gateway?

La salida de un autorizador de Lambda devuelve una política de AWS Identity and Access Management (IAM) a API Gateway. La política de IAM incluye un elemento de “recurso” explícito de la API de API Gateway que está en este formato:

"arn:aws:execute-api:<region>:<account>:<API_id>/<stage>/<http-method>/[<resource-path-name>/[<child-resources-path>]"

Cuando se activa el almacenamiento en caché de autorización en un autorizador de Lambda, la política de IAM devuelta se almacena en caché. La política de IAM almacenada en caché se aplica a cualquier solicitud de API adicional realizada dentro del periodo de vida (TTL) especificado de la memoria caché.

Si la API tiene un recurso proxy con una variable de ruta voraz de {proxy+}, la primera autorización se realiza correctamente. Las solicitudes de API adicionales realizadas a una ruta diferente dentro del período de vida de la caché fallan y devuelven el siguiente error:

“mensaje”: “El usuario no está autorizado a acceder a este recurso”

Las solicitudes adicionales fallan porque las rutas no coinciden con el elemento de “recurso” explícito de la API de API Gateway definido en la política de IAM en caché.

Para resolver el problema, puede modificar el código de la función de autorización de Lambda para que devuelva un recurso comodín (*/*) en la salida. Para obtener más información, consulte Recursos y condiciones para las acciones de Lambda.

Nota: Para activar el almacenamiento en caché del autorizador, el autorizador debe devolver una política que sea aplicable a todos los métodos en API Gateway. El código de la función de autorización de Lambda debe devolver un recurso comodín (*/*) en la salida para permitir todos los recursos. La política de caché espera que se almacene en caché la misma ruta de recursos, a menos que haya realizado la solicitud dos veces en la misma ruta de recursos.

Resolución

Nota: Modifique los fragmentos de código de la función de autorizador de Lambda de ejemplo en este artículo para que se ajusten a su caso de uso.

En las siguientes configuraciones de ejemplo, las funciones de Lambda extraen el valor de identificación de API Gateway del nombre de recurso de Amazon (ARN) del método (“event.methodArn”). A continuación, las funciones definen una variable comodín de “recurso” que combina las rutas de ARN del método con el valor de identificación de la API y un comodín (*/*).

Ejemplo de código de función de autorizador de Lambda basado en token que devuelve una variable comodín de “recurso”

exports.handler =  function(event, context, callback) {
    var token = event.authorizationToken;
    var tmp = event.methodArn.split(':');
    var apiGatewayArnTmp = tmp[5].split('/');
    
    // Create wildcard resource
    var resource = tmp[0] + ":" + tmp[1] + ":" + tmp[2] + ":" + tmp[3] + ":" + tmp[4] + ":" + apiGatewayArnTmp[0] + '/*/*'; 
    switch (token) {
        case 'allow':
            callback(null, generatePolicy('user', 'Allow', resource));
            break;
        case 'deny':
            callback(null, generatePolicy('user', 'Deny', resource));
            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;
}

Ejemplo de código de función de autorizador de Lambda basado en parámetros de solicitud que devuelve una variable comodín de “recurso”

exports.handler = function(event, context, callback) {        
   
    // 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('/');

    // Create wildcard resource
    var resource = tmp[0] + ":" + tmp[1] + ":" + tmp[2] + ":" + tmp[3] + ":" + tmp[4] + ":" + apiGatewayArnTmp[0] + '/*/*'; 
    console.log("resource: " + 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', resource));
    }  else {
        callback("Unauthorized");
    }
}
     
// Help function to generate an IAM policy
var generatePolicy = function(principalId, effect, resource) {
    // Required output:
    console.log("Resource in generatePolicy(): " + resource);
    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;
        console.log("***Resource*** " + resource);
        policyDocument.Statement[0] = statementOne;
        console.log("***Generated Policy*** ");
        console.log(policyDocument);
        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);
}

Para obtener más información sobre cómo editar el código de la función de Lambda, consulte Implementación de funciones de Lambda definidas como archivos .zip.


Información relacionada

Editar código con el editor de la consola

OFICIAL DE AWS
OFICIAL DE AWSActualizada hace 2 años