我们正在CloudFront和S3上托管我们的Web应用程序。该基础结构是在Terraform模块中配置的。我们正在使用同一模块(由Terragrunt管理)将Web应用程序部署到暂存和生产环境。
很显然,我们不希望公众访问我们的暂存环境。因此,我们创建了一个Lambda函数来启用基本HTTP身份验证,并使用lambda_function_association
资源中的aws_cloudfront_distribution
来启用它。
问题是我们不希望Lambda也能在我们的产品环境中运行。我无法有条件地在资源上设置关联。
我还尝试过创建两个具有相同名称的资源并设置count
属性,以便仅存在这些资源。
例如
# Basic Auth Guard
resource "aws_cloudfront_distribution" "default" {
count = "${var.behind_auth_guard}"
...
}
# No Basic Auth Guard
resource "aws_cloudfront_distribution" "default" {
count = "${var.behind_auth_guard ? 0 : 1}"
}
但是,当我尝试部署代码时,却得到aws_cloudfront_distribution.default: resource repeated multiple times
。
有什么方法可以实现我想要的吗?
我考虑过的另一个选项是在两个版本上都设置Lambda,但是在生产中什么也不做。但是,这似乎效率低下且成本高昂,因为每次请求都会调用Lamdba,并且希望在可能的情况下避免这种情况。
答案 0 :(得分:2)
使用Terraform v0.12.0,这将非常容易解决,因为它支持Dynamic Nested Blocks。不幸的是,该版本不会在2019年第一季度之前发布。
同时,您可以稍作改动,接受您自己提出的建议。您只需要进行很小的更改,因为不支持重复的名称。
# Basic Auth Guard
resource "aws_cloudfront_distribution" "cf_with_guard" {
count = "${var.behind_auth_guard}"
...
}
# No Basic Auth Guard
resource "aws_cloudfront_distribution" "cf_no_guard" {
count = "${var.behind_auth_guard ? 0 : 1}"
}
如果现在要使用此资源的任何输出,则必须使用小的hack。例如,如果要输出分布的id
:
output "cf_id" {
value = "${var.behind_auth_guard ? join("", aws_cloudfront_distribution.cf_with_guard.*.id) : join("", aws_cloudfront_distribution.cf_no_guard.*.id)}"
}
join()
是必需的,因为您不能引用不存在的资源。即使在if语句中也没有。 join()
通过引用所有资源的列表来解决此问题,如果资源的count
为0,则为空。
注意事项,以备将来参考:如果v0.12.0已发布,则不再需要上述解决方法。只需参考动态嵌套块即可。
答案 1 :(得分:0)
正如 Joris 在上面指出的动态嵌套块是要走的路。以下是对我有用的方法:
dynamic "lambda_function_association" {
for_each = var.ENV == "prod" ? [] : [0]
content {
event_type = "viewer-request"
lambda_arn = "${aws_lambda_function.my_auth_lambda.qualified_arn}"
}
}
这会为除生产环境之外的所有内容打开 lambda 函数。