Cloudflare DNS & WAF
Zone DNS records, security settings, and managed WAF rulesets for a Cloudflare zone — provider v5 ready.
Verification
Plan-validatedPassed: module logic verified on a mocked plan — inputs, validation rules, conditional creation and outputs resolve (no real provider, no cloud).
Conformance
- Static validation (fmt · validate · tflint)
- No applicable security policies for this provider
- Plan tests (mocked: validation rules · outputs)
Provenance
- SHA-256 checksum
- Signature (pending)
Functional
- Live test pending (no cloud run yet)
Last verified 2026-06-28 · how we verify
Documentation
cloudflare-dns
Zone DNS records, security settings, and managed WAF rulesets for a Cloudflare
zone — provider v5 ready. Built directly against the auto-generated v5 schema
(cloudflare_dns_record, cloudflare_zone_setting, cloudflare_ruleset), not
the v4 resource names (cloudflare_record, cloudflare_zone_settings_override)
that break on upgrade. Works with Terraform and OpenTofu (>= 1.6),
Cloudflare provider >= 5.0, < 6.0.
Secure defaults:
- A/AAAA/CNAME records are proxied (orange-cloud) unless you opt out, so origin IPs stay hidden; proxied records get TTL 1 (automatic) as Cloudflare requires.
- HTTPS posture enforced via zone settings:
always_use_https,automatic_https_rewrites, TLS 1.2 minimum, TLS 1.3 enabled. - Cloudflare Managed Ruleset + OWASP Core Ruleset deployed and enabled by default (OWASP blocks at the medium anomaly threshold, 40).
Usage
module "zone" {
source = "./cloudflare-dns"
zone_id = "0da42c8d2132a9ddaf714f9e7c920711"
records = {
apex = { name = "example.com", type = "A", content = "192.0.2.10" }
www = { name = "www.example.com", type = "CNAME", content = "example.com" }
}
custom_firewall_rules = [{
description = "Challenge empty user agents"
expression = "(http.user_agent eq \"\")"
action = "managed_challenge"
}]
}
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
zone_id | string | — | Cloudflare zone ID (32-hex, required) |
records | map(object) | {} | DNS records keyed by a stable logical name; content for simple records, data for structured (SRV/CAA/TLSA/...) |
zone_settings | map(string) | HTTPS/TLS hardening set | Zone settings keyed by setting ID |
enable_managed_waf | bool | true | Execute the Cloudflare Managed Ruleset (Pro+ plan) |
enable_owasp_core | bool | true | Execute the OWASP Core Ruleset (Pro+ plan) |
owasp_score_threshold | number | 40 | OWASP anomaly threshold (60 low / 40 medium / 25 high) |
owasp_action | string | "block" | Action when the OWASP threshold is exceeded |
custom_firewall_rules | list(object) | [] | Custom WAF rules (description, expression, action, enabled) |
Outputs
| Name | Description |
|---|---|
record_ids | Map of record key => DNS record ID |
record_hostnames | Map of record key => FQDN |
managed_waf_ruleset_id | Managed-WAF ruleset ID (null when disabled) |
custom_firewall_ruleset_id | Custom firewall ruleset ID (null when unused) |
zone_settings_applied | Zone setting IDs managed by this module |
Requirements & notes
- Terraform or OpenTofu
>= 1.6;cloudflare/cloudflare>= 5.0, < 6.0. - This module owns the zone's
http_request_firewall_managedandhttp_request_firewall_customruleset phases (Cloudflare allows exactly one zone ruleset per phase) — do not manage those phases elsewhere. - Managed WAF rulesets require a paid (Pro or higher) zone plan; on Free zones
set
enable_managed_waf = falseandenable_owasp_core = false. - Per-record
tagsare a Cloudflare Enterprise feature; leave unset otherwise. - Record
nameshould be the fully-qualified hostname (e.g.www.example.com).
Verification
Static-validated (fmt, validate, tflint). Live apply/destroy testing pending cloud sandbox availability — see catalog status.
License
Commercial — IaC Bazaar EULA. © IaC Bazaar. Original work (not derived from a third-party module).