I’m trying to improve aws_acm_certificate module to make possible create multiple certificates in one time. But, I’m running in an annoying issue. This is my current code:
variable "aws_region" {
default = "eu-west-2"
}
variable "certs" {
default = {
"wildcard-my.zone.com" = {
domain_name = "*.my.zone.com"
validation_method = "DNS"
dns_zone = "myzone.com."
subject_alternative_names = [
"*.us-east-2.my.zone.com",
]
}
}
}
provider "aws" {
version = "~> 2.7"
region = var.aws_region
}
resource "aws_acm_certificate" "certs" {
for_each = var.certs
domain_name = each.value.domain_name
subject_alternative_names = lookup(each.value, "subject_alternative_names", [])
validation_method = each.value.validation_method
tags = {
Environment = lookup(each.value, "environment", "shared")
Terraform = true
Name = each.key
}
}
data "aws_route53_zone" "cert_zones" {
for_each = var.certs
name = each.value.dns_zone
}
locals {
validation_records = flatten([
for k, v in aws_acm_certificate.certs:
[
for a, b in v.domain_validation_options:
merge(
b,
{ zone_id = lookup(lookup(data.aws_route53_zone.cert_zones,k,{}), "id", "") },
{ cert_arn = v.arn },
{ fqdn = replace(b.resource_record_name, "/(.*)\\./", "$1") }
)
]
])
}
resource "aws_route53_record" "records" {
count = length(local.validation_records)
zone_id = local.validation_records[count.index].zone_id
name = local.validation_records[count.index].resource_record_name
type = local.validation_records[count.index].resource_record_type
ttl = 60
records = [
local.validation_records[count.index].resource_record_value
]
allow_overwrite = true
depends_on = [
aws_acm_certificate.certs,
data.aws_route53_zone.cert_zones
]
}
output "validation_records" {
value = local.validation_records
}
output "validation_records_l" {
value = length(local.validation_records)
}
output "route53" {
value = aws_route53_record.records
}
When I run terraform plan, I get this result:
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
data.aws_route53_zone.cert_zones["wildcard-my.zone.com"]: Refreshing state...
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_acm_certificate.certs["wildcard-my.zone.com"] will be created
+ resource "aws_acm_certificate" "certs" {
+ arn = (known after apply)
+ domain_name = "*.my.zone.com"
+ domain_validation_options = (known after apply)
+ id = (known after apply)
+ subject_alternative_names = [
+ "*.us-east-2.my.zone.com",
]
+ tags = {
+ "Environment" = "shared"
+ "Name" = "wildcard-my.zone.com"
+ "Terraform" = "true"
}
+ validation_emails = (known after apply)
+ validation_method = "DNS"
}
# aws_route53_record.records[0] will be created
+ resource "aws_route53_record" "records" {
+ allow_overwrite = true
+ fqdn = (known after apply)
+ id = (known after apply)
+ name = (known after apply)
+ records = (known after apply)
+ ttl = 60
+ type = (known after apply)
+ zone_id = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy.
------------------------------------------------------------------------
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
As you can see, only 1 route53 record will be created. But, local.validation_records is a list with 2 objects. This is the result of terraform apply:
terraform apply -auto-approve
data.aws_route53_zone.cert_zones["wildcard-my.zone.com"]: Refreshing state...
aws_acm_certificate.certs["wildcard-my.zone.com"]: Creating...
aws_acm_certificate.certs["wildcard-my.zone.com"]: Creation complete after 6s [id=arn:aws:acm:eu-west-2:11111111111111:certificate/eeeeeeeee-xxxxx-yyyy-aaaaa-fffffffffff]
aws_route53_record.records[0]: Creating...
aws_route53_record.records[0]: Still creating... [10s elapsed]
aws_route53_record.records[0]: Still creating... [20s elapsed]
aws_route53_record.records[0]: Still creating... [30s elapsed]
aws_route53_record.records[0]: Creation complete after 38s [id=ZZZZZZZZZZZ__66666666666666666666666666666.my.zone.com._CNAME]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Outputs:
route53 = [
{
"alias" = []
"allow_overwrite" = true
"failover_routing_policy" = []
"fqdn" = "_66666666666666666666666666666.my.zone.com"
"geolocation_routing_policy" = []
"id" = "ZZZZZZZZZZZ__66666666666666666666666666666.my.zone.com._CNAME"
"latency_routing_policy" = []
"name" = "_66666666666666666666666666666.my.zone.com"
"records" = [
"_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.olprtlswtu.acm-validations.aws.",
]
"ttl" = 60
"type" = "CNAME"
"weighted_routing_policy" = []
"zone_id" = "ZZZZZZZZZZZ"
},
]
validation_records = [
{
"cert_arn" = "arn:aws:acm:eu-west-2:11111111111111:certificate/eeeeeeeee-xxxxx-yyyy-aaaaa-fffffffffff"
"domain_name" = "*.my.zone.com"
"fqdn" = "_66666666666666666666666666666.my.zone.com"
"resource_record_name" = "_66666666666666666666666666666.my.zone.com."
"resource_record_type" = "CNAME"
"resource_record_value" = "_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.olprtlswtu.acm-validations.aws."
"zone_id" = "ZZZZZZZZZZZ"
},
{
"cert_arn" = "arn:aws:acm:eu-west-2:11111111111111:certificate/eeeeeeeee-xxxxx-yyyy-aaaaa-fffffffffff"
"domain_name" = "*.us-east-2.my.zone.com"
"fqdn" = "_55555555555555555555555555.us-east-2.my.zone.com"
"resource_record_name" = "_55555555555555555555555555.us-east-2.my.zone.com."
"resource_record_type" = "CNAME"
"resource_record_value" = "_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.olprtlswtu.acm-validations.aws."
"zone_id" = "ZZZZZZZZZZZ"
},
]
validation_records_l = 2
After apply, if I run terraform plan, it will inform that will create the missing record. I would like to know if this behavior is expected and if there is a solution for it.