4

I have a CloudFormation stack template that creates an API Gateway resource where the method is of Type: LAMBDA_PROXY. It initially works fine for accessing the root domain, for example https://28af295f439b5f0aef7c7805864ba3981f282e1e.guacchain.com/ - but when I try accessing https://28af295f439b5f0aef7c7805864ba3981f282e1e.guacchain.com/about the network request gives back status code 500 and response {"message": "Internal server error"}

The generated Lambda function has this as its Resource-based Policy:

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "stack-28af295f439b5f0aef7c7805864ba3981f282e1e-lambdaApiGatewayInvoke-128TRSSUE8WDQ",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-1:378688096774:function:lambda-28af295f439b5f0aef7c7805864ba3981f282e1e",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:execute-api:us-east-1:378688096774:bccwb0kvvd/*/*/*"
        }
      }
    }
  ]
}

When going to the API Gateway Integration Request page and simply editing the Lambda Function field (cutting the existing value then pasting it back, then hitting the checkmark), I get this "Add permission" popup: enter image description here

After clicking OK and then refreshing the Lambda console page, its Resource-base Policy updates to include two seemingly duplicate statements (only difference being the Sid field):

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "stack-28af295f439b5f0aef7c7805864ba3981f282e1e-lambdaApiGatewayInvoke-128TRSSUE8WDQ",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-1:378688096774:function:lambda-28af295f439b5f0aef7c7805864ba3981f282e1e",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:execute-api:us-east-1:378688096774:bccwb0kvvd/*/*/*"
        }
      }
    },
    {
      "Sid": "d6d795d4-8461-4774-bd6e-ae8d8ea3bcee",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-1:378688096774:function:lambda-28af295f439b5f0aef7c7805864ba3981f282e1e",
      "Condition": {
        "ArnLike": {
          "AWS:SourceArn": "arn:aws:execute-api:us-east-1:378688096774:bccwb0kvvd/*/*/*"
        }
      }
    }
  ]
}

After deploying the API Gateway and waiting about a minute, https://28af295f439b5f0aef7c7805864ba3981f282e1e.guacchain.com/about finally becomes accessible. So my question is, what's inadequate with the original Lambda Resource-based Policy that prevents all requests except for the / one to be accessed on the domain?

One subtle note I want to point out is that after cutting the Lambda function name and pasting it on the Integration Request page, it doesn't show as an autocomplete option, while others do.

This is the lambdaIAMRole I have defined in the CloudFormation stack:

  lambdaIAMRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Action:
              - 'sts:AssumeRole'
            Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
      Policies:
        - PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Effect: Allow
                Resource:
                  - !Sub >-
                    arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${lambdaFunctionName}:*
          PolicyName: lambda

And the Lambda function resource has Role: !GetAtt lambdaIAMRole.Arn as part of its Properties field.

Pat Needham
  • 5,698
  • 7
  • 43
  • 63
  • Try `StringLike` instead of `ArnLike`. Check https://stackoverflow.com/a/56145538/643500 – Sully May 25 '20 at 19:26
  • That `ArnLike` field only appears on the Lambda console page - how can I edit it via the CloudFormation template? – Pat Needham May 25 '20 at 20:29
  • There should be no difference. Is it something that you observe regularly, or was it a one-time thing? – Marcin May 25 '20 at 21:46
  • The `{"message": "Internal server error"}` response is happening regularly. I don't understand what you mean by no difference - between what? – Pat Needham May 25 '20 at 22:18
  • Check this template https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/quickref-lambda.html – Sully May 25 '20 at 22:23
  • That template doesn't mention `StringLike` anywhere - would it go somewhere inside the `LambdaExecutionRole` resource included there? – Pat Needham May 26 '20 at 00:18
  • I should not matter whether you add permissions to lambda using API gateway console or in CloudFormation. I will try to recreate your scenario using my own API gateway with lambda integrations. – Marcin May 26 '20 at 01:24
  • 1
    I checked your template. I see one mistake there which could explain why your {proxy+} does not work. In your `apiGatewayLambdaResourceMethod` you should have `IntegrationHttpMethod: POST`, not GET. Because you use `AWS_PROXY` this must always be POST. When you do this in console, it will be correctly set to POST. – Marcin May 26 '20 at 01:30
  • 1
    That. Did. It. @Marcin if you post it as an answer I'll accept. This feels like deja vu lol. – Pat Needham May 26 '20 at 03:01

1 Answers1

2

Based on the comments and inspection of the CloudFormation template, it was found that the issue was caused by the incorrect setup of IntegrationHttpMethod in apiGatewayLambdaResourceMethod.

Instead of

IntegrationHttpMethod: GET

it should be

IntegrationHttpMethod: POST

This is because AWS_PROXY for lambda requires POST method, not GET.

Marcin
  • 215,873
  • 14
  • 235
  • 294