Warum ist meine API-Gateway-Proxy-Ressource mit einem Lambda-Genehmiger, der den Cache aktiviert hat und HTTP 403 „Benutzer ist nicht berechtigt, auf diese Ressource zuzugreifen“-Fehler zurückgibt?

Letzte Aktualisierung: 17.08.2022

Meine Proxy-Ressource des Amazon API Gateways mit einem AWS Lambda Authorizer, der den Cache aktiviert hat, gibt die folgende HTTP 403-Fehlermeldung zurück: „Der Benutzer ist nicht berechtigt, auf diese Ressource zuzugreifen“. Was ist der Grund dafür und wie löse ich den Fehler?

Kurzbeschreibung

Hinweis: API Gateway kann aus verschiedenen Gründen 403-Fehler Benutzer ist nicht berechtigt, auf diese Ressource zuzugreifen zurückgeben. Dieser Artikel behandelt 403-Fehler im Zusammenhang mit API-Gateway-Proxy-Ressourcen mit einem Lambda-Genehmiger, bei dem nur der Cache aktiviert ist. Informationen zur Fehlerbehebung bei anderen Arten von 403-Fehlern finden Sie unter Wie behebe ich HTTP-403-Fehler von API Gateway?

Die Ausgabe eines Lambda-Genehmigers gibt eine AWS Identity and Access Management (IAM)-Richtlinie an API Gateway zurück. Die IAM-Richtlinie umfasst ein explizites „Ressourcen“-Element der API-Gateway-API im folgenden Format:

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

Wenn Autorisierungs-Caching auf einem Lambda-Genehmiger aktiviert ist, wird die zurückgegebene IAM-Richtlinie zwischengespeichert. Die zwischengespeicherte IAM-Richtlinie wird dann auf alle zusätzlichen API-Anforderungen angewendet, die innerhalb der angegebenen Gültigkeitsdauer (TTL) des Caches gestellt werden.

Wenn die API über eine Proxy-Ressource mit einer gierigen Pfadvariablen von {proxy+} verfügt, ist die erste Autorisierung erfolgreich. Alle zusätzlichen API-Anforderungen, die innerhalb der TTL-Periode des Caches an einen anderen Pfad gesendet werden, schlagen fehl und geben den folgenden Fehler zurück:

„message“: „Benutzer ist nicht berechtigt, auf diese Ressource zuzugreifen“

Die zusätzlichen Anforderungen schlagen fehl, da die Pfade nicht mit dem expliziten Element „Ressource“ der API Gateway API übereinstimmen, das in der zwischengespeicherten IAM-Richtlinie definiert ist.

Um das Problem zu beheben, können Sie den Code der Lambda-Autorisierungsfunktion so ändern, dass stattdessen eine Platzhalterressource (*/*) in der Ausgabe zurückgegeben wird. Weitere Informationen finden Sie unter Ressourcen und Bedingungen für Lambda-Aktionen.

Hinweis: Um das Genehmiger-Caching zu aktivieren, muss Ihr Genehmiger eine Richtlinie zurückgeben, die für alle Methoden in einem API-Gateway gilt. Der Code der Lambda-Genehmiger-Funktion muss in der Ausgabe eine Platzhalterressource (*/*) zurückgeben, um alle Ressourcen zu ermöglichen. Die Cache-Richtlinie erwartet, dass derselbe Ressourcenpfad zwischengespeichert wird, es sei denn, Sie haben dieselbe Anforderung zweimal für denselben Ressourcenpfad gestellt.

Auflösung

Hinweis: Ändern Sie die Codeausschnitte der Lambda-Genehmiger-Beispielfunktion in diesem Artikel, um sie an Ihren Anwendungsfall anzupassen.

In den folgenden Beispiel-Setups extrahieren die Lambda-Funktionen den ID-Wert des API-Gateways aus dem Amazon-Ressourcennamen (ARN) der Methode („event.methodArn“). Anschließend definieren die Funktionen eine Platzhaltervariable „Ressource“, indem sie die ARN-Pfade der Methode mit dem ID-Wert der API und einem Platzhalter (*/*) kombinieren.

Beispiel für einen Token-basierten Lambda-Autorisierungsfunktionscode, der eine Platzhaltervariable „Ressource“ zurückgibt

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

Beispiel für einen anforderungsparameterbasierten Lambda-Autorisierungsfunktionscode, der eine Platzhaltervariable „Ressource“ zurückgibt

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

Weitere Informationen zum Bearbeiten von Lambda-Funktionscode finden Sie unter Bereitstellen von Lambda-Funktionen, die als ZIP-Dateiarchive definiert sind.


War dieser Artikel hilfreich?


Benötigen Sie Hilfe zur Fakturierung oder technischen Support?