WP-003 Infrastructure

Two-Phase ACM Validation with External DNS

Issuing a certificate when Terraform doesn't own the zone

Version
1.1
Status
published
Published

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/