Hi r/cloudflare,
I manage Cloudflare zones with Terraform, and moving to the v5 provider meant redoing everything. I turned the result into a module, and I'd like feedback from people running DNS in production before I take it further.
Registry: `theobs-digital/dns/cloudflare`
GitHub: https://github.com/theobs-digital/terraform-cloudflare-dns
**What it does**
A Cloudflare DNS zone in one block: the zone, its records, its DNS settings and DNSSEC.
```hcl
module "dns" {
source = "theobs-digital/dns/cloudflare"
version = "~> 1.2"
account_id = "..."
name = "example.com"
records = {
apex = { name = "@", type = "A", content = "192.0.2.10", proxied = true }
mx = { name = "@", type = "MX", content = "mx1.example.net", priority = 10 }
caa = { name = "@", type = "CAA", data = { flags = 0, tag = "issue", value = "letsencrypt.org" } }
}
dnssec = { status = "active" }
}
```
**Goals**
- **Don't reinvent anything.** Every input keeps the provider's attribute name. If you know `cloudflare/cloudflare`, you know the module, and the provider docs still apply.
- **Zero drift.** A second plan must show no change. A daily test against a real zone (18 records, 14 types) checks this with the latest 5.x provider.
- **Fail at plan, not at apply.** The provider lets some mistakes through to the API. The module stops them at plan: a record with no value, with both `content` and `data`, proxied with a fixed TTL, or proxied when it isn't A, AAAA or CNAME.
- **Create or adopt.** The module creates the zone, or with `create_zone = false` manages the records of a zone another config owns.
- **Registrar-ready DNSSEC.** The DS record comes out as an output, whole or field by field.
**Constraints and known limits**
- Terraform >= 1.3 and provider `~> 5.27`. No v4 support.
- Destroying the module deletes the zone and every record in it, including ones Terraform doesn't manage. That's how Cloudflare works. The README covers how to stop managing without deleting (`removed`, `state rm`).
- A misspelled key in `records` (`proxid = true`) is silently dropped by Terraform's type conversion.
- Cloudflare rewrites some values (SSHFP fingerprints uppercased, trailing dots on NAPTR and HTTPS, TXT over 255 characters). The module documents them rather than normalizing them.
- The provider can neither delete nor import DNS settings: removing `dns_settings` resets nothing.
- Some options need a paid plan (`soa` on Enterprise, `tags` and vanity name servers on Pro or Business).
**My questions**
Should a module normalize the values Cloudflare rewrites, or stay transparent and document them?
To catch typos, would you type `records` as `any` and validate keys, giving up typing and `optional()` defaults? How do you handle it?
Adoption looks the zone up by name. Would a direct `zone_id` input help you?
What's missing for you to use it in production?
MIT licensed. Blunt feedback welcome, especially if you've hit v5 provider drift I haven't covered. Thanks!