WP-003 in Infrastructure

Two-Phase ACM Validation with External DNS

Issuing a certificate when Terraform doesn't own the zone

Version
1.1
Status
published
Published
2 min read · 404 words

Abstract

When the DNS zone lives with an external provider, Terraform cannot create the ACM validation records itself, and a naive single apply deadlocks: CloudFront wants a validated certificate that cannot validate until records exist that the apply is waiting to finish before emitting. This paper documents the two-phase apply that breaks the cycle, and why the distribution is gated behind a flag.

The deadlock

A CloudFront distribution with a custom domain needs an issued ACM certificate in us-east-1. ACM issues a DNS-validated certificate only after a specific CNAME appears in the domain’s zone.1 When Terraform owns the zone, it writes that record in the same apply. When the zone is external, Terraform cannot — and a single apply that both requests the certificate and builds the distribution cannot complete, because:

Distribution waits for certCert waits for DNS recordRecord is external, not written
Figure 1. The single-apply cycle: each step waits on the next.

The approach: split the apply

The fix is to make certificate issuance a human-in-the-loop boundary and gate the distribution behind a variable. The environment exposes two flags:

`create_distribution`
false on first apply, true on second
`wait_for_certificate_validation`
defers the validated-cert dependency
Region
ACM certificate pinned to us-east-1
DNS
records created manually with the external provider

Phase 1 — request and surface

The first apply creates the bucket, requests the certificate, and outputs the validation records — without attempting to build the distribution.

terraform apply
terraform output acm_dns_validation_records

The operator copies those records into the external DNS provider and waits for ACM to report the certificate as ISSUED.

Why a flag, not a separate module
Gating with create_distribution keeps the whole environment in one state file and one mental model. The phases are a property of applying, not of the topology.

Phase 2 — build the edge

Once the certificate is issued, the second apply enables the distribution:

terraform apply -var="create_distribution=true"
terraform output cloudfront_domain_name

Finally the apex hostname is pointed at the CloudFront domain. Because apex records can’t be plain CNAMEs, the provider’s ALIAS/ANAME equivalent is used.

ResourceAfter phase 1After phase 2
S3 bucket
ACM certificaterequestedissued
CloudFront
Public site
Table 1. What exists after each phase.

Why this is acceptable

The two-phase apply trades a one-time manual step for keeping DNS authority where it belongs. The boundary is explicit, the outputs make the required action obvious, and subsequent applies (after the certificate exists) are single-shot again. For a site provisioned once and rarely touched, that is the right trade-off.

Operational note
The validation CNAME must stay in the zone for the life of the certificate — ACM re-checks it on renewal. Removing it after issuance will break auto-renewal.

  1. ACM DNS validation requires a provider-issued CNAME to remain resolvable for issuance and renewal. 1 ↩︎

References

  1. Amazon Web Services (2024). DNS validation for ACM certificates. AWS Certificate Manager User Guide.
Cite this paper
Jon (2026). Two-Phase ACM Validation with External DNS (v1.1). Prosyon Research. https://research.prosyon.ca/papers/external-dns-acm-flow/