Cloudflare Docs
Terraform
Visit Terraform on GitHub
Set theme to dark (⇧+D)

Configure WAF custom rules

This page provides examples of creating WAF custom rules in a zone or account using Terraform. The examples cover the following scenarios:

For more information on custom rules, refer to Custom rules in the Cloudflare WAF documentation.

​​ Zone-level configurations

​​ Add a custom rule to a zone

The following example configures a custom rule in the zone entry point ruleset for the http_request_firewall_custom phase for zone with ID <ZONE_ID>. The rule will block all traffic on non-standard HTTP(S) ports:

resource "cloudflare_ruleset" "zone_custom_firewall" {
zone_id = "<ZONE_ID>"
name = "Phase entry point ruleset for custom rules in my zone"
description = ""
kind = "zone"
phase = "http_request_firewall_custom"
rules {
action = "block"
expression = "(not cf.edge.server_port in {80 443})"
description = "Block ports other than 80 and 443"
enabled = true
}
}

​​ Account-level configurations

​​ Create and deploy a custom ruleset

The following example creates a custom ruleset in the account with ID <ACCOUNT_ID> containing a single custom rule. This custom ruleset is then deployed using a separate cloudflare_ruleset Terraform resource. If you do not deploy a custom ruleset, it will not execute.

The following configuration creates the custom ruleset with a single rule:

resource "cloudflare_ruleset" "account_firewall_custom_ruleset" {
account_id = "<ACCOUNT_ID>"
name = "Custom ruleset blocking traffic in non-standard HTTP(S) ports"
description = ""
kind = "custom"
phase = "http_request_firewall_custom"
rules {
action = "block"
expression = "(not cf.edge.server_port in {80 443})"
description = "Block ports other than 80 and 443"
enabled = true
}
}

The following configuration deploys the custom ruleset at the account level. It defines a dependency on the account_firewall_custom_ruleset resource and uses the ID of the created custom ruleset in action_parameters:

resource "cloudflare_ruleset" "account_firewall_custom_entrypoint" {
account_id = "<ACCOUNT_ID>"
name = "Account-level entry point ruleset for the http_request_firewall_custom phase deploying a custom ruleset"
description = ""
kind = "root"
phase = "http_request_firewall_custom"
depends_on = [cloudflare_ruleset.account_firewall_custom_ruleset]
rules {
action = "execute"
action_parameters {
id = cloudflare_ruleset.account_firewall_custom_ruleset.id
}
expression = "(cf.zone.name eq \"example.com\")"
description = "Deploy custom ruleset for example.com"
enabled = true
}
}

For more information on configuring and deploying custom rulesets, refer to Work with custom rulesets in the Ruleset Engine documentation.

​​ Add a custom rule checking for exposed credentials

The following configuration creates a custom ruleset with a single rule that checks for exposed credentials.

resource "cloudflare_ruleset" "account_firewall_custom_ruleset_exposed_creds" {
account_id = "<ACCOUNT_ID>"
name = "Custom ruleset checking for exposed credentials"
description = ""
kind = "custom"
phase = "http_request_firewall_custom"
rules {
action = "rewrite"
action_parameters {
headers {
name = "Exposed-Credential-Check"
operation = "set"
value = "1"
}
}
exposed_credential_check {
username_expression = "url_decode(http.request.body.form[\"username\"][0])"
password_expression = "url_decode(http.request.body.form[\"password\"][0])"
}
expression = "http.request.method == \"POST\" && http.request.uri == \"/login.php\""
description = "Add header when there is a rule match and exposed credentials are detected"
enabled = true
}
}

The following configuration deploys the custom ruleset. It defines a dependency on the account_firewall_custom_ruleset_exposed_creds resource and obtains the ID of the created custom ruleset:

resource "cloudflare_ruleset" "account_firewall_custom_entrypoint" {
account_id = "<ACCOUNT_ID>"
name = "Account-level entry point ruleset for the http_request_firewall_custom phase deploying a custom ruleset checking for exposed credentials"
description = ""
kind = "root"
phase = "http_request_firewall_custom"
depends_on = [cloudflare_ruleset.account_firewall_custom_ruleset_exposed_creds]
rules {
action = "execute"
action_parameters {
id = cloudflare_ruleset.account_firewall_custom_ruleset_exposed_creds.id
}
expression = "(cf.zone.name eq \"example.com\")"
description = "Deploy custom ruleset for example.com"
enabled = true
}
}