Mismatch with AWS ACM certs validation record in Cloudflare DNS


Context

While integrating Cloudflare DNS with AWS ACM certificates, I ran into a recurring problem when running terraform plan on subsequent changes after deploying the following code:

resource "aws_acm_certificate" "example" {
  domain_name = "example.com"
  validation_method = "DNS"

  subject_alternative_names = [
    "*.example.com",
    "*.docs.example.com"
  ]

  lifecycle {
    create_before_destroy = true
  }
}

resource "cloudflare_zone" "example" {
  zone = "example.com"
  type = "full"
}

resource "cloudflare_record" "certificate_validation" {
  for_each = {
    for dvo in aws_acm_certificate.example.domain_validation_options : dvo.domain_name => {
      name   = dvo.resource_record_name
	  record = dvo.resource_record_value
	  type = dvo.resource_record_type
    }
  }

  zone_id = cloudflare_zone.example.id
  name    = each.value.name
  value   = each.value.record
  type    = each.value.type
  ttl     = 1
  proxied = false
}

Terraform complaint was as follows (with the output sanitized):

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # cloudflare_record.certificate_validation["*.example.com"] will be updated in-place
  ~ resource "cloudflare_record" "certificate_validation" {
        id          = "09fasljhdfa087adfnkaldf97d8"
        name        = "_0123456789abcdedfghijklmn.example.com."
      ~ value       = "_324fadahadkfh8327y49bjadf.kjhadfadfak.acm-validations.aws" -> "_324fadahadkfh8327y49bjadf.kjhadfadfak.acm-validations.aws."
        # (10 unchanged attributes hidden)
    }

  # cloudflare_record.certificate_validation["*.docs.example.com"] will be updated in-place
  ~ resource "cloudflare_record" "certificate_validation" {
        id          = "089724952khadja9a6adank"
        name        = "_701849akdhfaakd97465Ss452.docs.example.com."
      ~ value       = "_98472hjkadha98746kaldhf.bbhjkaddfafd.acm-validations.aws" -> "_98472hjkadha98746kaldhf.bbhjkaddfafd.acm-validations.aws."
        # (10 unchanged attributes hidden)
    }

Plan: 0 to add, 2 to change, 0 to destroy.

Notice how Terraform wants to add a trailing dot to the value of the validation record (a CNAME record in Cloudflare)

Solution

The solution is to explicitly remove the trailing dot for each validation record before Terraform compares them against what is stored in Cloudflare. With can achieve this with the help of the trimsuffix function as shown below:

resource "cloudflare_record" "certificate_validation" {
  for_each = {
    for dvo in aws_acm_certificate.example.domain_validation_options : dvo.domain_name => {
      name   = dvo.resource_record_name
	  record = dvo.resource_record_value
	  type = dvo.resource_record_type
    }
  }

  zone_id = cloudflare_zone.example.id
  name    = each.value.name
  value   = trimsuffix(each.value.record, ".")
  type    = each.value.type
  ttl     = 1
  proxied = false
}

References

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer’s view in any way.