Automate Multi‑Domain AWS ACM DNS Validation with Terraform for_each
This guide shows how to use Terraform's for_each expression to dynamically create the required DNS validation records for an AWS ACM certificate that covers multiple domain names, eliminating repetitive code and keeping the infrastructure as code clean and maintainable.
In modern web services a single application often serves several hostnames, requiring an SSL/TLS certificate that includes those names as Subject Alternative Names (SANs). When requesting an AWS ACM certificate with DNS validation, AWS generates a unique CNAME record for each domain, and those records must be added to Route 53 (or another DNS provider) to prove ownership.
Problem
Manually creating a separate aws_route53_record for each domain defeats the purpose of Infrastructure as Code (IaC) and leads to duplicated, hard‑to‑maintain configuration.
Solution with for_each
Terraform 0.12.6 introduced the for_each meta‑argument, which can iterate over a map or a set of strings to create multiple similar resources. By converting the list of domain_validation_options returned by the aws_acm_certificate resource into a map, we can let Terraform generate a aws_route53_record for each domain automatically.
data "aws_route53_zone" "selected" {
name = "core.org."
private_zone = false
}
resource "aws_route53_record" "cloudfront_validation" {
for_each = {
for dvo in aws_acm_certificate.cloudfront.domain_validation_options : dvo.domain_name => dvo
}
zone_id = data.aws_route53_zone.selected.zone_id
name = each.value.resource_record_name
type = each.value.resource_record_type
records = [each.value.resource_record_value]
ttl = 60
}The for expression transforms the list of objects into a map where the key is the domain name (ensuring uniqueness) and the value is the full validation object. Terraform then creates one aws_route53_record per map entry, using each.key and each.value to reference the domain and its validation data.
Key Code Walk‑through
name = each.value.resource_record_name– sets the CNAME record name provided by ACM. type = each.value.resource_record_type – usually CNAME. records = [each.value.resource_record_value] – the unique validation string.
Practical Tips & Caveats
Dependencies: The aws_route53_record.cloudfront_validation implicitly depends on aws_acm_certificate.cloudfront, ensuring the certificate request is created before the DNS records.
Validation Wait: After the records are created the certificate remains in PENDING_VALIDATION. In production you should add an aws_acm_certificate_validation resource to wait for successful validation before provisioning dependent resources.
Stable Keys: Use a stable, unique string such as dvo.domain_name as the map key; this guarantees deterministic resource naming.
Conclusion
Using for_each turns a repetitive, error‑prone task into a concise, scalable pattern that embodies the core principles of IaC: declarative, automated, and easy to maintain. Adding or removing SANs only requires updating the certificate's subject_alternative_names list, and Terraform will automatically adjust the DNS validation records.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Ops Development & AI Practice
DevSecOps engineer sharing experiences and insights on AI, Web3, and Claude code development. Aims to help solve technical challenges, improve development efficiency, and grow through community interaction. Feel free to comment and discuss.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
