API gateway lacks permissions to trigger lambda when made by terraform

3

My environments includes an API gateway with two methods: POST and OPTIONS. The POST one requires an API key and the OPTIONS one do not. Each triggers a different lambda. I am using terraform to build the environments.

When I build an environment the AWS console shows that everything is as it should: The gateway, the methods and the lambda shows that the gateway has permissions. Calling the POST method works well. Calling the OPTIONS method fails and on Cloudwatch it shows an empty error:

Lambda invocation failed with status: 403. Lambda request id: 43284993-c96d-4416-8db4-5c05b18eb2e1

Execution failed due to configuration error:

Method completed with status: 500

If I manually remove the OPTION method, and re-make it manually and deploy the API - it works.

A difference I have noticed after the manual change is that under the lambda "Triggers" view the trigger is a bit different:

The triggers made by terraform have these fields:

API key: <value of the the api key>

API type: REST

Authorization: None

Method: OPTIONS

Resource Path: /my_url_path

Stage: <name of the API stage>

And the one made manually lacks the "API key" one. Although my terraform code does not specify an API key at the lambda permission configuration. I am not sure whether it is a terraform mis-configuration or mis-feature in AWS API.

Would love any suggestion for debugging it or a solution.

Thank you!

1 Answer
3

AWS Lambda and many other AWS services support** resource-based permission policies**. Resource-based policies let you grant usage permission to other AWS Services or accounts on a per-resource basis. You also use a resource-based policy to allow an AWS service to invoke your function on your behalf.

When we use console to build the environment some resources are automatically created to make it easier for us. It is opposite when we build it via terraform/CloudFormation/CDK/SDK or CLI, every single resource must be defined in the code.

Example AWS Lambda resource-based policy:

{
  "Version": "2012-10-17",
  "Id": "default",
  "Statement": [
    {
      "Sid": "nodejs-apig-functiongetEndpointPermissionProd-BWDBXMPLXE2F",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "lambda:InvokeFunction",
      "Resource": "arn:aws:lambda:us-east-2:111122223333:function:nodejs-apig-function-1G3MXMPLXVXYI",
      "Condition": {
        "StringEquals": {
          "aws:SourceAccount": "111122223333"
        },
        "ArnLike": {
          "aws:SourceArn": "arn:aws:execute-api:us-east-2:111122223333:ktyvxmpls1/*/GET/"
        }
      }
    }
  ]

Terraform resource for AWS Lambda resource-based permission policy is called aws_lambda_permission. So you can check if this resource exists it the current terraform code that you use. If not you can add it and properly configured.

Example configuration:

resource "aws_api_gateway_rest_api" "MyDemoAPI" {
  name        = "MyDemoAPI"
  description = "This is my API for demonstration purposes"
}

resource "aws_lambda_permission" "lambda_permission" {
  statement_id  = "AllowMyDemoAPIInvoke"
  action        = "lambda:InvokeFunction"
  function_name = "MyDemoFunction"
  principal     = "apigateway.amazonaws.com"

  # The /*/*/* part allows invocation from any stage, method and resource path
  # within API Gateway REST API.
  source_arn = "${aws_api_gateway_rest_api.MyDemoAPI.execution_arn}/*/*/*"
}

For more information:

  1. Lambda resource-based policies
  2. Using AWS Lambda with Amazon API Gateway
  3. Terraform Resource: aws_lambda_permission
c3nIvo
answered 2 years ago
  • Thanks for the detailed answer!

    I have tried this approach and when I used the "///*" suffix the permissions failed. It wrote me that there is no such path. Any idea?

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions