Terraform:创建和验证多个ACM证书 [英] Terraform: Creating and validating multiple ACM certificates

本文介绍了Terraform:创建和验证多个ACM证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个非常令人困惑的Terraform资源问题,它会自动生成ACM中针对(Terraform管理的)托管区域的列表的SSL证书的生成和DNS验证.也可以在此要旨中找到该代码.

I'm running into a really confusing Terraform resource issue automating the generation and DNS validation of SSL certificates in ACM for a list of (Terraform-managed) hosted zones. Code can also be found in this gist.

我首先通过引导托管区域来引用此特定于环境的变量.

I'm starting by bootstrapping hosted zones referencing this environment-specific variable.

hosted_zones = [
    {
        domain = "site1.com"
        zone_id = "MANUALLY FILL"
    }
]

我用来构建区域的块似乎可以可靠地工作.

The block I am using to build the zones seems to work reliably.

resource "aws_route53_zone" "zones" {
    count = "${length(var.hosted_zones)}"
    name  = "${lookup(var.hosted_zones[count.index], "domain")}"
}

在构建区域之后,由于存在HCL的局限性以及我缺乏经验,因此我没有提出一种聪明的方法来自动执行区域ID的复制,因此我将手动将区域ID复制到变量中.

After the zones are built, I am manually copying the zone ID into the variable because I haven't come up with a clever way to automate it given a combination of limitations of HCL and my lack of experience with it.

我可以使用...为每个托管区域可靠地生成裸证书和splat证书.

I can reliably generate naked and splat certificates for each hosted zone using...

resource "aws_acm_certificate" "cert" {
    count = "${length(var.hosted_zones)}"
    domain_name = "${lookup(var.hosted_zones[count.index], "domain")}"
    subject_alternative_names = ["*.${lookup(var.hosted_zones[count.index], "domain")}"]
    validation_method = "DNS"

    tags {
        Project = "${var.project}"
        Environment = "${var.environment}"
    }
}

当我尝试自动执行证书的DNS验证时,事情变得很繁琐.对于单个托管区域,有一个很好的示例 ,但我无法将其成功移植到多个托管区域.我的尝试...

Where things get hairy is when I try to automate the DNS validation for the certs. There is a good example in the documentation for a single hosted zone, but I haven't been able to successfully port it to multiple hosted-zones. My attempt...

resource "aws_route53_record" "cert_validation" {
    count = "${length(var.hosted_zones)}"

    name = "${aws_acm_certificate.cert.*.domain_validation_options.0.resource_record_name[count.index]}"
    type = "${aws_acm_certificate.cert.*.domain_validation_options.0.resource_record_type[count.index]}"
    zone_id = "${var.zone_override != "" ? var.zone_override : lookup(var.hosted_zones[count.index], "zone_id")}"
    records = ["${aws_acm_certificate.cert.*.domain_validation_options.0.resource_record_value[count.index]}"]
    ttl = 60
}

resource "aws_acm_certificate_validation" "cert" {
    count = "${length(var.hosted_zones)}"

    certificate_arn = "${aws_acm_certificate.cert.*.arn[count.index]}"
    validation_record_fqdns = ["${aws_route53_record.cert_validation.*.fqdn[count.index]}"]
}

我在第一次运行时看到的错误是:

The error I am seeing on first run is:

* module.acm.aws_route53_record.cert_validation: 1 error(s) occurred:
* module.acm.aws_route53_record.cert_validation: Resource 'aws_acm_certificate.cert' does not have attribute 'domain_validation_options.0.resource_record_value' for variable 'aws_acm_certificate.cert.*.domain_validation_options.0.resource_record_value'

令人讨厌的是,如果我注释validation资源,则apply成功,然后取消注释它们并重新运行也成功.

The obnoxious part is that if I comment the validation resources, the apply succeeds, and then uncommenting them and re-running also succeeds.

我已经尝试(感觉)element() lookup()list()map()的每个排列,以第一个资源块的输出中的索引为目标来定向证书,但是遇到了文档列表"的限制,这是我最接近成功的方法.我想了解为什么需要这种解决方法,所以我可以消除它.这感觉像是语法问题,还是我试图使HCL的行为更像是一种OO语言.

I've tried (what feels like) every permutation of element() lookup(), list() and map() to target certificates by index in the output from the first resource block, but am running into documented "flat list" limitations and this is the closest I've gotten to success. I'd like to understand why the workaround is necessary so I can eliminate it. This feels like a syntax issue or me trying to get HCL to behave more like an OO language than it is.

感谢您提供的任何经验!

Thank you for any experience that may help!

推荐答案

我有一个类似的场景,解决这个问题的关键是使用 flatten().该方法也应该对您有用,这样您就不需要两次通过就可以创建资源.

I had a similar scenario and the key to solving it was the use of locals and flatten(). The approach should also work for you such that you shouldn't need two passes to create the resources.

在这种情况下,有多个域,每个域都有子域,这些子域将出现在证书的subjectAltName部分中.例如:

In this scenario there are multiple domains that each have subdomains that will appear in the subjectAltName section of the certificate. For example:

├── preview.example.com
│   ├── app.preview.example.com
│   └── www.preview.example.com
├── demo.example.com
│   ├── app.demo.example.com
│   └── www.demo.example.com
├── staging.example.com
│   ├── app.staging.example.com
│   └── www.staging.example.com
└── example.com
    ├── app.example.com
    └── www.example.com

为此,我们首先设置一些变量:

To achieve this we first set some variables:

variable "domains" {
    type = "list"
    default = [
        "demo.example.com",
        "preview.example.com",
        "staging.example.com",
        "example.com"
    ]
}
variable "subdomains" {
    type = "list"
    default = [
        "app",
        "www"
    ]
}

接下来,我们创建包含作为SAN的子域的证书资源.

Next we create the certificate resources that contain the subdomains as SANs.

resource "aws_acm_certificate" "cert" {
  count             = "${length(var.domains)}"
  domain_name       = "${element(var.domains, count.index)}"
  validation_method = "DNS"

  subject_alternative_names = ["${
    formatlist("%s.%s",
      var.subdomains,
      element(var.domains, count.index)
    )
  }"]
}

接下来,我们将需要一个局部变量来平整结果集的域和子域. 这是必需的,因为从0.11.7版本开始,terraform不支持​​嵌套列表语法, 通过element()插值或`list [count].

Next we're going to need a local variable to flatten the resulting set of domains and subdomains. This is needed because terraform doesn't support nested list syntax as of version 0.11.7, neither via the element() interpolation nor the `list[count].

locals {
  dvo = "${flatten(aws_acm_certificate.cert.*.domain_validation_options)}"
}

接下来,我们需要查找Route 53区域,我们可以在后续的Route 53记录中使用该区域:

We'll next need a lookup of the Route 53 zone that we can use in the subsequent Route 53 records:

data "aws_route53_zone" "zone" {
  count        = "${length(var.domains) > 0 ? 1 : 0}"
  name         = "example.com."
  private_zone = false
}

然后我们创建Route 53 DNS记录,这些记录中将填充来自证书的数据 DNS验证的资源.我们将一个添加到子域中,以便我们也有一个 记录未包含在子域列表中的基本域.

We then create the Route 53 DNS records that will be populated with data from the certificate resource for DNS validation. We're adding one to the subdomains so that we also have a record for the base domain not included in the list of subdomains.

resource "aws_route53_record" "cert_validation" {
  count   = "${length(var.domains) * (length(var.subdomains) + 1)}"
  zone_id = "${data.aws_route53_zone.zone.id}"
  ttl     = 60

  name    = "${lookup(local.dvo[count.index], "resource_record_name")}"
  type    = "${lookup(local.dvo[count.index], "resource_record_type")}"
  records = ["${lookup(local.dvo[count.index], "resource_record_value")}"]
}

最后,我们创建证书验证资源,它将等待证书被提交. 发布.

Finally we create the certificate validation resource that will wait for the certificate to be issued.

resource "aws_acm_certificate_validation" "cert" {
  count                   = "${length(var.domains) * (length(var.subdomains) + 1)}"
  certificate_arn         = "${element(aws_acm_certificate.cert.*.arn, count.index)}"
  validation_record_fqdns = ["${aws_route53_record.cert_validation.*.fqdn}"]
}

最后一个资源的一个警告是,它将为每个资源创建一个资源实例. 请求的证书,但每个实例将取决于所有域中的所有FQDN,并且 子域.这不会影响AWS中的任何内容,但是terraform代码不会继续/完成 直到所有证书都签发为止.

The one caveat for this last resource is that it'll create one instance of the resource for every certificate requested, but each instance will depend on all the FQDNs across all domains and subdomains. This won't affect anything in AWS but the terraform code won't continue/complete until all certs are issued.

这应该在一次应用运行中有效,而无需在第一遍中-target任何资源, 尽管围绕验证需要多长时间,显然存在一个已知问题 完成 通过terraform执行,因此即使不更改代码或计划/应用调用,也可能需要第二次通过.

This should work in a single apply run with no need to -target any resources in a first pass, though there is an apparently known issue around how long it takes for the validations to complete when performed via terraform, and for this reason it may require a second pass, albeit without changing the code or plan/apply invocation.

这篇关于Terraform:创建和验证多个ACM证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆