I am using Terraform v0.13.5. If I create a single AWS certificate resource for a domain registered in AWS, I can also successfully create a Route53 DNS validation record using:
resource "aws_acm_certificate" "api" {
domain_name = "api.example.com"
validation_method = "DNS"
lifecycle {
create_before_destroy = true
}
}
resource "aws_route53_record" "api_validation" {
for_each = {
for dvo in aws_acm_certificate.api.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}
allow_overwrite = true
name = each.value.name
records = [each.value.record]
ttl = 60
type = each.value.type
zone_id = data.aws_route53_zone.example.zone_id # already exists
}
However I want to create multiple certificates using a for_each
with map variable. I have defined the aws_acm_certificate
resources using:
variable "sub_domains" {
type = map
default = {
"api" = "api"
"api_test" = "api.test"
}
}
resource "aws_acm_certificate" "certs" {
for_each = var.sub_domains
domain_name = "${each.value}.example.com"
validation_method = "DNS"
lifecycle {
create_before_destroy = true
}
}
I cannot work out how to refer to the dynamic certificates created when defining the validation records. The following snippet now does not work:
resource "aws_route53_record" "api_validation" {
for_each = {
for dvo in aws_acm_certificate.certs.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}
allow_overwrite = true
name = each.value.name
records = [each.value.record]
ttl = 60
type = each.value.type
zone_id = data.aws_route53_zone.myzone.zone_id # already exists
}
Terraform complains with the following error:
Because aws_acm_certificate.certs has "for_each" set, its attributes must be
accessed on specific instances.
So how do I get the domain_validation_options
for each dynamically created certificate?
A couple ways you can handle this.
It looks like you are using the same high level domain. In this case it's example.com. You should consider using the subject_alternative_names
option in the aws_acm_certificate
resource. This would request just one cert with multiple SANs, and the logic you have there from the provider doc would create the validation record sets as needed.
If you're looking to create unique individual certs, I suggest a modular approach. If simply looking at certs being validated through DNS, you can take all of the code you have there (plus the aws_acm_certificate_validation
resource not shown) and package it up into a module in its own folder. You can then call that module with something like this:
module "acm_certs" {
for_each = var.sub_domains
source = "../modules/acm_certificate/"
certificate_domain_name = "${each.value}.example.com"
validation_domain_name = "example.com"
}
Notice we can use for_each
to call modules in Terraform v0.13+, giving us more flexibility in accomplishing what you are asking, but without introducing complexity in the re-usable code itself.
Each variable you see there are inputs to the module. If you need a more detailed explanation of what I mean by modules, just reply and I'll dive a bit deeper.