Creating a WAF rule, where do I find {ruleset_id}?

If I use the dashboard, I go to Security > WAF > Create Rule, then use this title:

Block Unapproved Countries

and this expression:

(ip.geoip.country ne “US” and ip.geoip.country ne “MP” and ip.geoip.country ne “PR” and ip.geoip.country ne “CA” and ip.geoip.country ne “TH”)

then “Block”.

I’m trying to move this to an API so that I can do it 50 more times.

I found this:

And using Example A, I’ve gotten this far:

curl https://api.cloudflare.com/client/v4/zones/[domain_id]/rulesets/{ruleset_id}/rules
–header “X-Auth-Email: [my email]”
–header “X-Auth-Key: [my key]”
–data ‘{
“description”: “Block Unapproved Countries”,
“expression”: “(ip.geoip.country ne "US" and ip.geoip.country ne "MP" and >ip.geoip.country ne "PR" and ip.geoip.country ne "CA" and ip.geoip.country ne "TH")”,
“action”: “block”
}’

Where do I find {ruleset_id} for this?

You would use the list rulesets end to find it.

If you want to do it for 50 domains you need to look at terraform and set it as needed. Rule ID in the current zone won’t matter you are defining it per zone.

1 Like

Using the example at your link, I see that it returns a list of {zone_id}s that already exist. One of which being for “firewall_custom”:

{
“id”: “12345”,
“name”: “default”,
“description”: “”,
“source”: “firewall_custom”,
“kind”: “zone”,
“version”: “1”,
“last_updated”: “2023-11-24T22:53:24.269046Z”,
“phase”: “http_request_firewall_custom”
}

Since I’m creating a WAF rule, does this mean that I would insert the “12345” variable as the zone_id? Or am I way off base?

Honestly, I had this script mostly written so I was hoping I could use it instead of starting over with Terraform :slight_smile: I haven’t done any bash scripting in years (decades, maybe), and playing with it is kinda fun! But I also realize that in the time I’ve spent doing it, I could have already created the accounts manually! LOL

You would use this ID as the ruleset_id parameter.

1 Like

Well, I was wrong about that, too :frowning: When I run this on a new zone with no rules, this is the result:

{
“result”: [
{
“id”: “123”,
“name”: “Cloudflare Normalization Ruleset”,
“description”: “Created by the Cloudflare security team, this ruleset provides normalization on the URL path”,
“kind”: “managed”,
“version”: “5”,
“last_updated”: “2023-05-02T16:19:06.119072Z”,
“phase”: “http_request_sanitize”
},
{
“id”: “456”,
“name”: “Cloudflare Managed Log4J Ruleset”,
“description”: “Created by the Cloudflare security team, this ruleset is designed to provide protection for free zones”,
“source”: “firewall_managed”,
“kind”: “managed”,
“version”: “56”,
“last_updated”: “2023-10-11T14:34:33.86359Z”,
“phase”: “http_request_firewall_managed”
},
{
“id”: “789”,
“name”: “DDoS L7 ruleset”,
“description”: “Automatic mitigation of HTTP-based DDoS attacks. Cloudflare routinely adds signatures to address new attack vectors. Additional configuration allows you to customize the sensitivity of each rule and the performed mitigation action.”,
“kind”: “managed”,
“version”: “1854”,
“last_updated”: “2023-11-27T14:13:45.690356Z”,
“phase”: “ddos_l7”
}
],
“success”: true,
“errors”: ,
“messages”:
}

I’m trying to add a new rule under Security > WAF > Custom rules, another one under Security > WAF > Rate Limiting rules, and a third under Caching > Cache rules. Am I supposed to use one of those IDs as the ruleset_id?

Update: I figured it out! Check if the ruleset exists, and if not then create a new one. This is what I did in my bash script:

ruleset_id=$(curl --request GET
–silent
–url https://api.cloudflare.com/client/v4/zones/$zone_id/rulesets
–header “X-Auth-Email: $email”
–header “X-Auth-Key: $key”
–header ‘Content-Type: application/json’ | jq -r ‘first(.result | select(.phase==“http_request_firewall_custom”).id)’)

if [[ -z $ruleset_id ]]
then
ruleset_id=$(curl https://api.cloudflare.com/client/v4/zones/$zone_id/rulesets
–silent
–header “X-Auth-Email: $email”
–header “X-Auth-Key: $key”
–header “Content-Type: application/json”
–data ‘{
“name”: “default”,
“kind”: “zone”,
“description”: “”,
“phase”: “http_request_firewall_custom”
}’ | jq -r ‘.result.id’)
fi

“kind” might need to be “root”. This works for inserting a WAF rule, but when I try to insert a cache rule it fails because of the phase and kind.

How are you guys formatting code in your posts? All I see is blockquote, and it’s removing my pretty spaces and oddly formatting my comments :frowning: