Terraform Cloudflare DNS replacing "A" record with "MX" record instead of creating two records

Module configuration:

module "cloudflare-dns-records-testing-com" {
  source = "./dns-records"
  providers = {
    cloudflare = cloudflare.devops
  }
  dns_records = var.dns-records-testing-com
  zone_id     = "23h4lkhj2345kb43kl2345hl2k34jh5lk23j4h"
}

variable "dns-records-testing-com" {
  type = map(object({
    type     = string
    value    = string
    priority = string
  }))

  default = {
    "@" = {
      type     = "A"
      value    = "127.0.0.1"
      priority = null
    }
    "@" = {
      type     = "MX"
      value    = "mx.testing.com"
      priority = "10"
    }
  }
}

Output from plan:

Terraform will perform the following actions:

  # module.cloudflare-dns-records-testing-com.cloudflare_record.dns_record["@"] must be replaced
-/+ resource "cloudflare_record" "dns_record" {
      ~ created_on      = "2022-12-14T16:35:40.603611Z" -> (known after apply)
      ~ hostname        = "testing.com" -> (known after apply)
      ~ id              = "f9cb520614422789734ca12046841931" -> (known after apply)
      ~ metadata        = {
          - "auto_added"             = "false"
          - "managed_by_apps"        = "false"
          - "managed_by_argo_tunnel" = "false"
          - "source"                 = "primary"
        } -> (known after apply)
      ~ modified_on     = "2022-12-14T16:35:40.603611Z" -> (known after apply)
        name            = "@"
      + priority        = 10
      ~ proxiable       = true -> (known after apply)
      ~ type            = "A" -> "MX" # forces replacement
      ~ value           = "127.0.0.1" -> "mx.testing.com"
        # (4 unchanged attributes hidden)
    }

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

This appears to be an issue with the for_each, I tested this with individual resources instead of using the module/for_each and it has no problems.

You have defined a map with multiple entries having the same key. This is not something supported by the map data type.

It is a shame that Terraform does not produce an explicit error here - it seems it is allowing one entry to silently overwrite the other.

1 Like

Thanks, this was it. I refactored like this and it works:

module "cloudflare-dns-records-testing-com" {
  source = "./dns-records"
  providers = {
    cloudflare = cloudflare.devops
  }
  dns_records = var.dns-records-testing-com
  zone_id     = "23h4lkhj2345kb43kl2345hl2k34jh5lk23j4h"
}

variable "dns-records-testing-com" {
  type = map(object({
    name = string          <--
    type     = string
    value    = string
    priority = string
  }))

  default = {
    root-a = {          <--
      name = "@"          <--
      type     = "A"
      value    = "127.0.0.1"
      priority = null
    }
    root-mx = {          <--
      name = "@"          <--
      type     = "MX"
      value    = "mx.testing.com"
      priority = "10"
    }
  }
}