我有以下Terraform用于在API网关上为我的API设置CORS方法:
resource "aws_api_gateway_method" "default" {
rest_api_id = "${var.rest_api_id}"
resource_id = "${var.resource_id}"
http_method = "OPTIONS"
authorization = "NONE"
}
resource "aws_api_gateway_method_response" "default" {
rest_api_id = "${var.rest_api_id}"
resource_id = "${var.resource_id}"
http_method = "${aws_api_gateway_method.default.http_method}"
status_code = "200"
response_parameters = {
"method.response.header.Access-Control-Allow-Headers" = true,
"method.response.header.Access-Control-Allow-Methods" = true,
"method.response.header.Access-Control-Allow-Origin" = true,
}
}
resource "aws_api_gateway_integration" "default" {
rest_api_id = "${var.rest_api_id}"
resource_id = "${var.resource_id}"
http_method = "${aws_api_gateway_method.default.http_method}"
type = "MOCK"
passthrough_behavior = "WHEN_NO_MATCH"
request_templates {
"application/json" = "{ \"statusCode\": 200 }"
}
}
resource "aws_api_gateway_integration_response" "default" {
rest_api_id = "${var.rest_api_id}"
resource_id = "${var.resource_id}"
http_method = "${aws_api_gateway_method.default.http_method}"
status_code = "${aws_api_gateway_method_response.default.status_code}"
response_parameters = {
"method.response.header.Access-Control-Allow-Headers" = "'${join(",", var.allow_headers)}'",
"method.response.header.Access-Control-Allow-Methods" = "'${join(",", var.allow_methods)}'",
"method.response.header.Access-Control-Allow-Origin" = "'${var.allow_origin}'",
}
}
我的变量定义为:
variable "allow_headers" {
type = "list"
default = ["Content-Type", "X-Amz-Date", "Authorization", "X-Api-Key", "X-Amz-Security-Token", "X-Requested-With"]
}
variable "allow_methods" {
type = "list"
default = ["*"]
}
variable "allow_origin" {
default = "*"
}
variable "resource_id" {
description = "The API Gateway Resource id."
}
variable "rest_api_id" {
description = "The API Gateway REST API id."
}
当我使用API网关Web控制台测试端点时,它按预期工作:
但是,当我尝试卷曲端点时,我得到403:
$ curl -is -X OPTIONS https://api.naftuli.wtf/echo.json
HTTP/1.1 403 Forbidden
Content-Type: application/json
Content-Length: 42
Connection: keep-alive
Date: Fri, 23 Feb 2018 20:45:09 GMT
x-amzn-RequestId: 70089d6b-18da-11e8-9042-c3baac8eebde
x-amzn-ErrorType: MissingAuthenticationTokenException
X-Cache: Error from cloudfront
Via: 1.1 5a582ba7fbecfc5948507c13d8d2078a.cloudfront.net (CloudFront)
X-Amz-Cf-Id: VB2j87V6_wfSqXkyIPeqz8vjdDF5vBIi0DsJmIAn8kgyIjSAfkcf7A==
{"message":"Missing Authentication Token"}
该方法使用authorization = "NONE"
进行了明确配置,我可以毫无问题地从API网关控制台触发它。
如何允许访问此方法?我觉得我已尽我所能。
TL; DR添加/更改每个新资源/方法后,必须创建新部署。
Terraform会创建一次部署,并且永远不会更新它,因为它的数据都没有更改。我找到了一个解决方法:
resource "aws_api_gateway_stage" "default" {
stage_name = "production"
rest_api_id = "${aws_api_gateway_rest_api.default.id}"
deployment_id = "${aws_api_gateway_deployment.default.id}"
lifecycle {
# a new deployment needs to be created on every resource change so we do it outside of terraform
ignore_changes = ["deployment_id"]
}
}
我告诉舞台忽略deployment_id
属性,以便Terraform不会在没有任何变化的地方显示变化。
为了创建新部署,我只是将此命令添加到我的Makefile deploy
目标:
deploy:
terraform apply -auto-approve
aws apigateway create-deployment \
--rest-api-id $(terraform output -json | jq -r .rest_api_id.value) \
--stage-name $(terraform output -json | jq -r .stage_name.value)
这将为给定阶段创建REST API的新部署。
我确信有更好的方法可能完全在Terraform中完成这项工作,但目前他们还是没弄到我。
这是一个更好的方法
resource "aws_api_gateway_deployment" "petshop" {
provider = "aws.default"
stage_description = "${md5(file("apigateway.tf"))}"
rest_api_id = "${aws_api_gateway_rest_api.petshop.id}"
stage_name = "prod"
}
这样可以节省您在每次微小更改时的重新部署,并且只会由apigateway.tf
文件中的更改触发