Terraform 中的可选 CloudFront Lambda 函数关联
Optional CloudFront Lambda function association in Terraform
我们在 CloudFront 和 S3 上托管我们的网络应用程序。此基础架构在 Terraform 模块中配置。我们正在使用相同的模块(由 Terrag运行t 管理)将我们的 webapp 部署到我们的暂存和生产环境中。
显然,我们不希望 public 访问我们的暂存环境。因此,我们创建了一个 Lambda 函数来启用基本 HTTP 身份验证,并使用 aws_cloudfront_distribution
资源中的 lambda_function_association
来启用它。
问题是我们不希望 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 将在每次请求时被调用,并且希望尽可能避免它。
对于 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,则不再需要上述解决方法。简单参考动态嵌套块。
正如 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 函数。
我们在 CloudFront 和 S3 上托管我们的网络应用程序。此基础架构在 Terraform 模块中配置。我们正在使用相同的模块(由 Terrag运行t 管理)将我们的 webapp 部署到我们的暂存和生产环境中。
显然,我们不希望 public 访问我们的暂存环境。因此,我们创建了一个 Lambda 函数来启用基本 HTTP 身份验证,并使用 aws_cloudfront_distribution
资源中的 lambda_function_association
来启用它。
问题是我们不希望 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 将在每次请求时被调用,并且希望尽可能避免它。
对于 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,则不再需要上述解决方法。简单参考动态嵌套块。
正如 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 函数。