Skip to content

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.