ACM¶
Each environment owns its own ACM certificate for the asset hostname — assets-dev.tomoda.life for dev, assets.tomoda.life for prod. The cert is consumed by CloudFront's viewer config (see CloudFront) and provisioned by acm.tf.
Why us-east-1¶
CloudFront is a global service whose certificate store lives in us-east-1. Even though every other AWS resource in this repo is in ap-northeast-1, the cert resource explicitly pins to the us_east_1 provider alias:
provider "aws" {
alias = "us_east_1"
region = "us-east-1"
}
resource "aws_acm_certificate" "cert" {
provider = aws.us_east_1
domain_name = local.full_domain_name
validation_method = "DNS"
lifecycle {
create_before_destroy = true
}
}
Without this alias the cert would land in ap-northeast-1 and CloudFront would refuse to use it.
DNS validation via Cloudflare¶
validation_method = "DNS" means ACM emits a randomised CNAME that the certificate's owner must publish under the apex domain. Terraform takes the validation options from the ACM resource and writes them straight into Cloudflare using the cloudflare/cloudflare provider:
resource "cloudflare_record" "acm_validation" {
for_each = {
for dvo in aws_acm_certificate.cert.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}
zone_id = data.cloudflare_zone.this.id
name = each.value.name
content = each.value.record
type = each.value.type
proxied = false # ACM validation MUST NOT be proxied
ttl = 60
}
proxied = false is mandatory — ACM resolves the CNAME on the public internet without going through Cloudflare's CDN, so proxying it would break validation. Once the CNAME is live, ACM completes the challenge within a minute or two and the certificate's status moves to ISSUED.
The Cloudflare-side record management is documented in full on the Cloudflare page.
Renewal¶
AWS renews DNS-validated ACM certificates automatically, as long as the validation CNAME stays in place. Since the CNAME is managed by Terraform, accidental deletion is unlikely — but if the Cloudflare zone is ever torn down and recreated, the validation record must be restored before renewal time, otherwise the cert will eventually expire.
The create_before_destroy = true lifecycle on the certificate ensures that if the cert ever has to be replaced (for example, adding a SAN), the new cert is issued and validated before the old one is removed, so CloudFront never sees a gap in trust.
Outputs¶
acm.tf exposes the validation records via an output (acm_certificate_validation_records), which is useful for inspecting what CNAMEs Terraform is about to write into Cloudflare. There is no separate output for the certificate ARN — cloudfront.tf consumes it directly via the resource reference.