Perché la mia risorsa proxy API Gateway con un autorizzazione per Lambda con la memorizzazione nella cache attivata restituisce gli errori HTTP 403 "L'utente non è autorizzato ad accedere a questa risorsa"?

Ultimo aggiornamento: 04/02/2022

La mia risorsa proxy Amazon API Gateway con un'autorizzazione per AWS Lambda con memorizzazione nella cache attivata restituisce il seguente messaggio di errore HTTP 403: "L'utente non è autorizzato ad accedere a questa risorsa". Perché si verifica questo problema e come posso risolverlo?

Breve descrizione

Nota: API Gateway può restituire gli errori 403 L'utente non è autorizzato ad accedere a questi errori di risorsa per una serie di motivi. Questo articolo affronta errori 403 relativi alle risorse proxy API Gateway con una autorizzazione per Lambda con memorizzazione nella cache attivata. Per informazioni sulla risoluzione di altri tipi di errori 403, consulta In che modo posso risolvere gli errori HTTP 403 da API Gateway?

Un output di un'autorizzazione per Lambda restituisce una policy AWS Identity and Access Management (IAM) a API Gateway. La policy IAM include un elemento "Resource" dell'API di API Gateway esplicito nel seguente formato:

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

Quando la memorizzazione nella cache delle autorizzazioni è attivata su un'autorizzazione per Lambda, questa policy IAM viene memorizzata nella cache. La policy memorizzata nella cache viene quindi applicata a qualsiasi richiesta API aggiuntiva effettuata entro il periodo di durata (TTL) specificato dalla cache.

Se l'API ha una risorsa proxy con una variabile di percorso greedy di {proxy+}, la prima autorizzazione ha esito positivo. Eventuali richieste API aggiuntive effettuate su un percorso diverso all'interno del periodo TTL della cache non riescono e restituiscono il seguente errore:

"messaggio": "L'utente non è autorizzato ad accedere a questa risorsa"

Le richieste aggiuntive non riescono, perché i percorsi non corrispondono all'elemento "Resource" dell'API di API Gateway esplicito definito nella policy IAM memorizzata nella cache.

Per risolvere il problema, puoi modificare il codice della funzione dell'autorizzazione per Lambda per restituire invece una risorsa jolly (*/*) nell'output. Per ulteriori informazioni, consulta Risorse e condizioni per le operazioni Lambda.

Risoluzione

Nota: potrebbe essere necessario modificare i frammenti di codice della funzione di autorizzazione Lambda di esempio in questo articolo in modo da adattarli al proprio caso d'uso.

Nelle seguenti configurazioni di esempio, le funzioni Lambda estraggono il valore id dell'API dall'Amazon Resource Name (ARN) del metodo ("event.methodArn"). Quindi, le funzioni definiscono una variabile jolly "Resource" combinando i percorsi dell'ARN del metodo con il valore id dell'API e un carattere jolly (*/*).

Esempio di codice funzione di autorizzazione Lambda basato su token che restituisce una variabile jolly "Resource"

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;
}

Esempio di codice funzione di autorizzazione Lambda basata su parametri che restituisce una variabile jolly "Resource"

exports.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('/');

    // 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);
}

Per ulteriori informazioni su come modificare il codice funzione Lambda, vedere Creazione di funzioni Lambda definite come archivi di file .zip. Inoltre, consulta Modifica del codice utilizzando l'editor della console nella Guida per gli sviluppatori di AWS Lambda.


Questo articolo è stato utile?


Hai bisogno di supporto tecnico o per la fatturazione?