Reputation: 565
I am trying to enable CORS on my aws project which consists of API Gateway
and Lambda
function.
I'm creating an API Gateway with GET
and OPTIONS
methods.
OPTIONS
is meant to be a mock endpoint for enabling CORS as per aws documentation.
There is a lambda function (aws_lambda_function.app_lambda
) which is invoked by GET
method and in response headers has:
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
But still, I cannot pass CORS.
resource "aws_api_gateway_rest_api" "rest_api" {
name = "appAPIGateway"
description = "App App App"
}
resource "aws_api_gateway_resource" "rest_api_resource" {
depends_on = ["aws_api_gateway_rest_api.rest_api"]
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
parent_id = "${aws_api_gateway_rest_api.rest_api.root_resource_id}"
path_part = "playground"
}
resource "aws_api_gateway_method" "opt" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
resource_id = "${aws_api_gateway_resource.rest_api_resource.id}"
http_method = "OPTIONS"
authorization = "NONE"
api_key_required = true
}
resource "aws_api_gateway_integration" "opt" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
resource_id = "${aws_api_gateway_resource.rest_api_resource.id}"
http_method = "${aws_api_gateway_method.opt.http_method}"
type = "MOCK"
}
resource "aws_api_gateway_integration_response" "opt" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
resource_id = "${aws_api_gateway_resource.rest_api_resource.id}"
http_method = "${aws_api_gateway_method.opt.http_method}"
status_code = 200
response_parameters = {
"method.response.header.Access-Control-Allow-Origin" = "'*'",
"method.response.header.Access-Control-Allow-Headers" = "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Requested-With'",
"method.response.header.Access-Control-Allow-Methods" = "'GET,OPTIONS,POST,PUT'"
}
depends_on = ["aws_api_gateway_integration.opt", "aws_api_gateway_method_response.opt"]
}
resource "aws_api_gateway_method_response" "opt" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
resource_id = "${aws_api_gateway_resource.rest_api_resource.id}"
http_method = "${aws_api_gateway_method.opt.http_method}"
status_code = 200
response_parameters = {
"method.response.header.Access-Control-Allow-Origin" = true,
"method.response.header.Access-Control-Allow-Methods" = true,
"method.response.header.Access-Control-Allow-Headers" = true
}
response_models = {
"application/json" = "Empty"
}
depends_on = ["aws_api_gateway_method.opt"]
}
resource "aws_api_gateway_method" "app_api_gateway_method" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
resource_id = "${aws_api_gateway_resource.rest_api_resource.id}"
http_method = "GET"
authorization = "NONE"
api_key_required = true
}
resource "aws_api_gateway_method_response" "app_cors_method_response_200" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
resource_id = "${aws_api_gateway_resource.rest_api_resource.id}"
http_method = "${aws_api_gateway_method.app_api_gateway_method.http_method}"
status_code = "200"
response_parameters = {
"method.response.header.Access-Control-Allow-Origin" = true,
"method.response.header.Access-Control-Allow-Methods" = true,
"method.response.header.Access-Control-Allow-Headers" = true
}
depends_on = ["aws_api_gateway_method.app_api_gateway_method"]
}
resource "aws_api_gateway_integration" "app_api_gateway_integration" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
resource_id = "${aws_api_gateway_method.app_api_gateway_method.resource_id}"
http_method = "${aws_api_gateway_method.app_api_gateway_method.http_method}"
integration_http_method = "POST"
type = "AWS_PROXY"
uri = "${aws_lambda_function.app_lambda.invoke_arn}"
depends_on = [
"aws_api_gateway_method.app_api_gateway_method",
"aws_lambda_function.app_lambda"
]
}
resource "aws_api_gateway_integration_response" "app_api_gateway_integration_response" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
resource_id = "${aws_api_gateway_resource.rest_api_resource.id}"
http_method = "${aws_api_gateway_method.app_api_gateway_method.http_method}"
status_code = 200
response_parameters = {
"method.response.header.Access-Control-Allow-Origin" = "'*'",
"method.response.header.Access-Control-Allow-Headers" = "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Requested-With'",
"method.response.header.Access-Control-Allow-Methods" = "'GET,OPTIONS,POST,PUT'"
}
depends_on = [
"aws_api_gateway_integration.app_api_gateway_integration",
"aws_api_gateway_method_response.app_cors_method_response_200",
]
}
resource "aws_api_gateway_deployment" "app_api_gateway_deployment" {
rest_api_id = "${aws_api_gateway_rest_api.rest_api.id}"
stage_name = "app_stage"
depends_on = [
"aws_api_gateway_integration_response.app_api_gateway_integration_response",
"aws_api_gateway_integration_response.opt"
]
}
Any help would be appreceated.
Upvotes: 15
Views: 24204
Reputation: 848
You can use the terraform module to enable cors:
module "api-gateway-enable-cors" {
source = "squidfunk/api-gateway-enable-cors/aws"
version = "0.3.3"
api_id = "<your_api_id>"
api_resource_id = "<your_api_resource_id>"
}
Source : api-gateway-enable-cors
Upvotes: 4
Reputation: 3813
It is useful to check the API GW logs in Cloudwatch to see what is the status code. In my scenario, I had two routes configured with aws_apigatewayv2_route
, one for POST and one for OPTIONS, for the same route key. The OPTIONS request was failing with statuscode 429
which is too many requests. This status code is usually returned by throttling settings when its over allowed limit.
Turns out, since the OPTIONS request was not passing CORS, it was because I did not specify throttling in default_route_settings
in terraform, so the default throttling for "Default route throttling" was defaulting to 0
for burst and rate. So my OPTIONS request was not passing CORS because it was getting hit by this throttling defaulting to zero. The hint in AWS console is clear:
This throttling limit applies to each route in the stage except those defined for specific routes.
Moral of the story - on your OPTIONS requests, really pay attention to the status code returned by API GW, and check the Cloudwatch logs for API GW.
So: all worked, when I added this in terraform, under my resource "aws_apigatewayv2_stage" "lambda"
:
default_route_settings {
throttling_burst_limit = 1000
throttling_rate_limit = 5000
}
Upvotes: -1
Reputation: 5808
For newer HTTP API (v2), you can use:
resource "aws_apigatewayv2_api" "lambda" {
name = "lambda_gw_api"
protocol_type = "HTTP"
cors_configuration {
allow_origins = ["https://www.mywebsite.fr"]
allow_methods = ["POST", "GET", "OPTIONS"]
allow_headers = ["content-type"]
max_age = 300
}
}
PS: you may also need to check your OPTIONS route has an "integration" and does not return 401.
Upvotes: 13
Reputation: 565
Found out a simple solution. The problem was that on applying newer changes to existing API Gateway, was NOT re-deploying those gateways. So I had to redeploy them by myself manually and think of how to do that in terraform too.
Upvotes: 2