Search code examples
amazon-web-servicesaws-lambdaaws-api-gatewaylambda-authorizer

Custom request-based lambda authorizer for AWS API Gateway is not triggered for API innovations


Have created a simple basic request-based authorizer for my AWS API Gateway following documentation (https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html)

While testing the Authorizer (with dummy setup which validates if Authorization header has key 'test' in it) the authorizer works fine, but while calling the API directly from the endpoint the authorizer is not called at all and I get my API response (which should be blocked as no header is passed).

Authorizer test with invalid key: getting expected 401

enter image description here

Authorizer test with valid key: getting expected 200

enter image description here

Directly calling API endpoing from web with success:

enter image description here

My resource policy for API Gateway as want to limit the innvocation from specific IP ranges only:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:us-east-1:111111111111:6mm9kw17uf/*/*/*"
        },
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:us-east-1:111111111111:6mm9kw17uf/*/*/*",
            "Condition": {
                "NotIpAddress": {
                    "aws:SourceIp": "XXXXXXX"
                }
            }
        }
    ]
}

Authorizer Lambda Code:

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;
        
    // 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.Authorization === "test") {
        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';
        policyDocument.Statement = [];
        var statementOne = {};
        statementOne.Action = 'execute-api:Invoke';
        statementOne.Effect = effect;
        statementOne.Resource = resource;
        policyDocument.Statement[0] = statementOne;
        authResponse.policyDocument = policyDocument;
    }
    return authResponse;
}
     
var generateAllow = function(principalId, resource) {
    return generatePolicy(principalId, 'Allow', resource);
}
     
var generateDeny = function(principalId, resource) {
    return generatePolicy(principalId, 'Deny', resource);
}

What I have tried already:

  1. I already re-deployed the APIs again after adding the authorizer.
  2. I am testing this from postman and web browser, not Gateway test as it will bypass authorizer.

Solution

  • I tried to replicate that issue using my own API Gateway, and I haven't identified any problems with your lambda function. It works as expected.

    enter image description here

    Example of authorized call:

    curl -i -w "\n" --http1.1 -H 'Authorization: test' https://xxxxx.execute-api.us-east-1.amazonaws.com/dev/helloworld
    
    
    HTTP/1.1 200 OK
    Date: Sun, 06 Sep 2020 11:22:30 GMT
    Content-Type: application/json
    Content-Length: 67
    Connection: keep-alive
    x-amzn-RequestId: 4213f276-737c-4481-bbac-3c4ecd767b6f
    x-amz-apigw-id: ScPyeFInoAMFYKg=
    X-Amzn-Trace-Id: Root=1-5f54c676-9e0c8bbe6093d8889f6b2035;Sampled=0
    
    {
        "statusCode": 200,
        "message": "Hello from API Gateway!"
    }
    

    Example of non-authorized call:

    curl -i -w "\n" --http1.1 -H 'Authorization: invalid' https://xxxx.execute-api.us-east-1.amazonaws.com/dev/helloworld
    
    
    HTTP/1.1 401 Unauthorized
    Date: Sun, 06 Sep 2020 11:25:36 GMT
    Content-Type: application/json
    Content-Length: 26
    Connection: keep-alive
    x-amzn-RequestId: 42a1d47c-aab5-4b72-b8eb-469fed383b26
    x-amzn-ErrorType: UnauthorizedException
    x-amz-apigw-id: ScQPpFUwoAMFRdA=
    
    {"message":"Unauthorized"}
    

    Example of no-header value provided:

    curl -i -w "\n" --http1.1  https://xxxx.execute-api.us-east-1.amazonaws.com/dev/helloworld
    
    HTTP/1.1 401 Unauthorized
    Date: Sun, 06 Sep 2020 11:26:15 GMT
    Content-Type: application/json
    Content-Length: 26
    Connection: keep-alive
    x-amzn-RequestId: 982944f2-ac1d-4eee-8776-7bfa76314d2b
    x-amzn-ErrorType: UnauthorizedException
    x-amz-apigw-id: ScQVwGmpoAMFfSA=
    
    {"message":"Unauthorized"}
    
    

    Things to consider though:

    1. When you add your authorizer to your api method, you have to deploy stage again.
    2. It takes time until new authorizer starts working. Thus after you enable it and create new stage, have to wait few minutes until it starts working