'Trigger Lambda from API Gateway in Terraform

I'm trying to deploy a basic API consisting in a lambda function as main endpoint and API gateway as proxy to this function. With the following configuration i'm able to build up the infrastructure, but I cannot set to trigger the lambda function through IaC, I have to go to the AWS console in order to manually set the trigger.

resource "aws_lambda_function" "main_endpoint_function" {
  function_name = "main_endpoint_function"


  s3_bucket = module.s3.function_bucket_name
  s3_key = "index.zip"


  handler = "index.handler"
  runtime = var.runtime_handler

  role = aws_iam_role.lambda_role.arn
}

resource "aws_iam_role" "lambda_role" {
  name = "role_lambda_test"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}
//lambda has to be manually triggered from api gateway
resource "aws_api_gateway_rest_api" "apiLambda" {
  name        = "myAPI"
  description = "terraform test"
}

resource "aws_api_gateway_resource" "proxy" {
   rest_api_id = aws_api_gateway_rest_api.apiLambda.id
   parent_id   = aws_api_gateway_rest_api.apiLambda.root_resource_id
   path_part   = "{proxy+}"
}

resource "aws_api_gateway_method" "proxyMethod" {
   rest_api_id   = aws_api_gateway_rest_api.apiLambda.id
   resource_id   = aws_api_gateway_resource.proxy.id
   http_method   = "ANY"
   authorization = "NONE"
}

resource "aws_api_gateway_integration" "lambda" {
   rest_api_id = aws_api_gateway_rest_api.apiLambda.id
   resource_id = aws_api_gateway_method.proxyMethod.resource_id
   http_method = aws_api_gateway_method.proxyMethod.http_method

   integration_http_method = "POST"
   type                    = "AWS_PROXY"
   uri                     = aws_lambda_function.main_endpoint_function.invoke_arn
}

resource "aws_api_gateway_method" "proxy_root" {
   rest_api_id   = aws_api_gateway_rest_api.apiLambda.id
   resource_id   = aws_api_gateway_rest_api.apiLambda.root_resource_id
   http_method   = "ANY"
   authorization = "NONE"
}

resource "aws_api_gateway_integration" "lambda_root" {
   rest_api_id = aws_api_gateway_rest_api.apiLambda.id
   resource_id = aws_api_gateway_method.proxy_root.resource_id
   http_method = aws_api_gateway_method.proxy_root.http_method

   integration_http_method = "POST"
   type                    = "AWS_PROXY"
   uri                     = aws_lambda_function.main_endpoint_function.invoke_arn
}

resource "aws_api_gateway_deployment" "apideploy" {
   depends_on = [
     aws_api_gateway_integration.lambda,
     aws_api_gateway_integration.lambda_root,
   ]

   rest_api_id = aws_api_gateway_rest_api.apiLambda.id
   stage_name  = "test"
}


Without the manually set trigger through the console I get Internal Server Error. With triggering functions correctly. Perhaps there is something wrong with my configuration ?

Update::

After adding the permission resources for Lambda and API Gateway I also created aws_api_gateway_method_response and aws_api_gateway_integration_response. On first run errors, on second run completes. I tried adding explicit implications but they didn't solve the issue..

resource "aws_api_gateway_method_response" "response_200" {
  rest_api_id = aws_api_gateway_rest_api.apiLambda.id
  resource_id = aws_api_gateway_resource.proxy.id
  http_method = aws_api_gateway_method.proxy_root.http_method
  status_code = "200"
  depends_on = [
    aws_api_gateway_rest_api.apiLambda,
    aws_api_gateway_resource.proxy,
    aws_api_gateway_method.proxy_root
  ]
}

resource "aws_api_gateway_integration_response" "MyDemoIntegrationResponse" {
  rest_api_id = aws_api_gateway_rest_api.apiLambda.id
  resource_id = aws_api_gateway_resource.proxy.id
  http_method = aws_api_gateway_method.proxy_root.http_method
  status_code = aws_api_gateway_method_response.response_200.status_code
  depends_on = [
    aws_api_gateway_rest_api.apiLambda,
    aws_api_gateway_resource.proxy,
    aws_api_gateway_method.proxy_root,
    aws_api_gateway_method_response.response_200
  ]

  # Transforms the backend JSON response to XML
  response_templates = {
    "application/xml" = <<EOF
#set($inputRoot = $input.path('$'))
<?xml version="1.0" encoding="UTF-8"?>
<message>
    $inputRoot.body
</message>
EOF
  }
}

the Error is: │ Error: Error creating API Gateway Method Response: NotFoundException: Invalid Method identifier specified │ │ with aws_api_gateway_method_response.response_200, │ on main.tf line 130, in resource "aws_api_gateway_method_response" "response_200": │ 130: resource "aws_api_gateway_method_response" "response_200" {



Solution 1:[1]

It seems you are missing the aws_lambda_permission resource [1]. In your case, you would need to add the following (similar to example from the reference):

resource "aws_lambda_permission" "apigw_lambda" {
  statement_id  = "AllowExecutionFromAPIGateway"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.main_endpoint_function.function_name
  principal     = "apigateway.amazonaws.com"

  source_arn = "arn:aws:execute-api:${var.myregion}:${var.accountId}:${aws_api_gateway_rest_api.apiLambda.id}/*/${aws_api_gateway_method.proxyMethod.http_method}${aws_api_gateway_resource.proxy.path}"
}

Since I don't know which region and account you are using (I don't need to know that), you just have to replace the var.myregion with the API Gateway region and var.accountId with the AWS account where the API Gateway is created. You can achieve that by using data sources. In theory, you might as well leave out the method reference from the source_arn and use something like:

source_arn = "arn:aws:execute-api:${var.myregion}:${var.accountId}:${aws_api_gateway_rest_api.apiLambda.id}/*/*/*"

I have removed the second reference from the code and it is now referenced in [2].


[1] https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration#lambda-integration

[2] http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-control-access-using-iam-policies-to-invoke-api.html

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Marko E