Terraform-provider-cloudflare: Argument in resource cloudflare_record to overwrite existing DNS records

Created on 18 Feb 2021  ·  5Comments  ·  Source: cloudflare/terraform-provider-cloudflare

Current Terraform version

Terraform v0.14.7

Description

Support an argument in resource cloudflare_record to overwrite existing DNS records, similar to route53_record allow_overwrite.

Use-cases

When creating a resource aws_acm_certificate and its respective aws_acm_certificate_validation, the DNS validation record requested is a hash of the name of the certificate (at least, not sure about multi-account scenarios) and doesn't change across AWS regions.

If the same certificate name is created in different AWS regions (since certificates are scoped per-region), the DNS validation record is the same.

resource "aws_acm_certificate" "cert" {
  domain_name       = "*.example.com"
  validation_method = "DNS"
}

resource "cloudflare_record" "cert_validation" {
  zone_id = var.cloudflare_zone_id
  name    = element(aws_acm_certificate.cert.domain_validation_options[*].resource_record_name, 0)
  value   = element(aws_acm_certificate.cert.domain_validation_options[*].resource_record_value, 0)
  type    = element(aws_acm_certificate.cert.domain_validation_options[*].resource_record_type, 0)
}

resource "aws_acm_certificate_validation" "cert" {
  certificate_arn         = aws_acm_certificate.cert.arn
  validation_record_fqdns = [cloudflare_record.cert_validation.hostname]
}

Either cloudflare_record.cert_validation is imported into Terraform state, or (preferred IMHO) it allows overwrite.

Potential Terraform configuration

In the example above:

resource "cloudflare_record" "cert_validation" {
  zone_id         = var.cloudflare_zone_id
  name            = element(aws_acm_certificate.cert.domain_validation_options[*].resource_record_name, 0)
  value           = element(aws_acm_certificate.cert.domain_validation_options[*].resource_record_value, 0)
  type            = element(aws_acm_certificate.cert.domain_validation_options[*].resource_record_type, 0)
  allow_overwrite = true
}

References

https://github.com/hashicorp/terraform/issues/10065
https://github.com/hashicorp/terraform/pull/10910

Community note

  • Please vote on this issue by adding a 👍 reaction
    to the original issue to help the community and maintainers prioritize this request
  • If you are interested in working on this issue or have submitted a pull
    request, please leave a comment
kinenhancement triagaccepted workflopr-attached

Most helpful comment

Completely agree with you on the consistency bit, I understand this is an edge case.

In my scenario with multiple regions, the first region provisioned TF creates the TLS certificate resource in that region and also creates the DNS validation record on CF.

When provisioning more regions (with the same set of resources, using TF workspaces), if the TLS certificate common name is the same (say for example you want to serve api.example.com and have failover across regions), the DNS validation record AWS expects is the same, causing this issue and the following error:

Error: expected DNS record to not already be present but already exists

A workaround would be having a flag to only create the DNS record once and enable it in 1 region only (it doesn't really matter which one) or import the cloudflare_record resource when provisioning a new region.

In this specific case, I still feel having a allow_overwrite works, leaving to me the responsibility to use it with parsimony. :smile:

All 5 comments

Having a look at this use case, I'm not really seeing the benefit of it and I'm a little hesitant due to it going against the grain of consistently managing your infrastructure as code. It suggests that you have potentially multiple sources updating this value and you don't really track the underlying value -- instead you're open to updating it with any value blindly in place.

In the scenario you mentioned, I would have assumed you would have already had the existing record and update it in an apply with an expected non-empty plan. Can you elaborate why this use case wouldn't work for you to help me understand this?

Completely agree with you on the consistency bit, I understand this is an edge case.

In my scenario with multiple regions, the first region provisioned TF creates the TLS certificate resource in that region and also creates the DNS validation record on CF.

When provisioning more regions (with the same set of resources, using TF workspaces), if the TLS certificate common name is the same (say for example you want to serve api.example.com and have failover across regions), the DNS validation record AWS expects is the same, causing this issue and the following error:

Error: expected DNS record to not already be present but already exists

A workaround would be having a flag to only create the DNS record once and enable it in 1 region only (it doesn't really matter which one) or import the cloudflare_record resource when provisioning a new region.

In this specific case, I still feel having a allow_overwrite works, leaving to me the responsibility to use it with parsimony. :smile:

I've put up a PR for this over at #1124. Due to the nature of the acceptance tests, it did require manual testing and not something I can find a good way of automating at the moment so in order to land this, can you please pull that branch locally, build the provider and test this with your use case to confirm it works as desired?

It works as expected. :raised_hands:

I have manually created the record test-overwrite.example.com and tried to create the following resource

resource "cloudflare_record" "test_overwrite" {
  zone_id = [REDACTED]
  name    = "test-overwrite"
  value   = "cloudflare.com."
  type    = "CNAME"
  ttl     = 60
}

Fails because the record already exists:

[REDACTED].cloudflare_record.test_overwrite: Creating...
[REDACTED].cloudflare_record.test_overwrite: Still creating... [10s elapsed]
[REDACTED].cloudflare_record.test_overwrite: Still creating... [20s elapsed]
╷
│ Error: expected DNS record to not already be present but already exists
│ 
│   with [REDACTED].cloudflare_record.test_overwrite,
│   on [REDACTED]/AAA-test.tf line 1, in resource "cloudflare_record" "test_overwrite":
│    1: resource "cloudflare_record" "test_overwrite" {
│ 
╵

Addded allow_overwrite in the resource:

resource "cloudflare_record" "test_overwrite" {
  zone_id         = [REDACTED]
  name            = "test-overwrite"
  value           = "cloudflare.com."
  type            = "CNAME"
  ttl             = 60
  allow_overwrite = true
}

Record correctly updated (used to CNAME to www.cloudflare.com.):

[REDACTED].cloudflare_record.test_overwrite: Creating...
[REDACTED].cloudflare_record.test_overwrite: Creation complete after 7s [id=cbc039c525cfec8814814c9d9c749ed5]
$ dig +short test-overwrite.example.com
cloudflare.com.
104.16.133.229
104.16.132.229

Thank you, @jacobbednarz!

Thanks for the confirmation! I've just landed this and it will be in the next release. Use it wisely!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DingGGu picture DingGGu  ·  3Comments

sc0ttbeardsley picture sc0ttbeardsley  ·  6Comments

azhurbilo picture azhurbilo  ·  6Comments

lneves75 picture lneves75  ·  5Comments

dijitali picture dijitali  ·  3Comments