hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.
https://www.terraform.io/
Other
42.72k stars 9.55k forks source link

Bug: Scripts for AWS API Gateway causing status 200 error #23988

Closed MagnusBrzenk closed 4 years ago

MagnusBrzenk commented 4 years ago

Terraform Version

v0.12.19

Terraform Configuration Files

I'm building an aws-lambda-emailer service through api gateway. My terraform scripts for provisioning are here

Expected Behavior

Post requests submitted from a browser will succeed.

Actual Behavior

The browser will first perform an OPTIONS request to check that CORS is enabled before following up with a POST request. I attempt to provision such an OPTIONS request from the lambda_api.tf file with {status_code: 200}. However, when this options method is called, API Gateway will encounter a {statusCode: 500} server error with the following message:

Execution failed due to configuration error: statusCode should be an integer which defined in request template

And since this error response does not have headers enabling CORS, the browser will fail to do a follow-up POST request (and the whole thing fails).

So it seems that terraform is causing the value of the statusCode in AWS to be set with a non-integer. I am totally stumped why this is happening.

Steps to Reproduce

  1. You'll need to have an AWS account with credentials set in CLI
  2. Clone this branch
  3. npm i
  4. cp .env-template .env and edit variables (you'll need to use emails verified with AWS SES if you want to test the entire api-lambda-ses pipeline)
  5. Run terraform init terraform/lambda_emailer
  6. Run ./_run_terraform 2
  7. At this point, running ./_test_email_api ought to successfully send an email (since curl doesn't attempt an OPTIONS request and goes straight to POST)
  8. Run ./_set_email_endpoint to inject email endpoint into source code at build time
  9. Launch angular app in dev mode with ng serve
  10. Go to localhost:4200/contact and try sending a message to the lambda emailer service; will error
  11. In AWS Api Gateway console, find api just created (ng9-lambda-api-gateway if you use .env-template value), and try testing the OPTIONS method -- this will give you the error "Execution failed due to configuration error: statusCode should be an integer which defined in request template"

Additional Context

I've found elsewhere that this problem can be caused if you set your statusCode using a string status_code = "200". But, as you can see in my scripts, I tried this (even with the hyper explicit tonumber(200)), and it still thinks I'm not using integers :(

MagnusBrzenk commented 4 years ago

In case anyone else struggles with this, I managed to fix the problem by:

  1. Running the script as it was and causing the options method to fail
  2. Manually deleting the options method in the aws console, recreating it, enabling CORS, and confirming that the api-gateway-lambda-ses resources will succesfully trigger the sending of an email from a browser,
  3. Running terraform plan and carefully inspecting the differences between what was provisioned by my manual actions and what would be provisioned were I to run my terraform scripts again (and making appropriate changes to my terraform scripts).

It appears that the key difference between working and breaking was adding:

  request_templates = {
    "application/json" = jsonencode(
      {
        statusCode = 200
      }
    )
  }

to my resource "aws_api_gateway_integration" "options_integration" block. I'm glad I got this working but I'm also a bit disconcerted by how (1) far from obvious this was, and (2) the fact that this essential block was not recommended in any template/demo I came across. (And this essentially all pieced together from templates offered on the terraform website.)

ghost commented 4 years ago

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.