Created
June 6, 2025 02:33
-
-
Save bruceharrison1984/a87e46821d85253a0a36a19e8aa686e0 to your computer and use it in GitHub Desktop.
fail2ban - Cloudflare WAF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Version 2025/6/4 | |
# Author: leeharrison1984 | |
# | |
# IMPORTANT | |
# | |
# This action utilizes the new WAF rulesets instead of the deprecated Firewall IP Access Rules | |
# | |
# This action depends on curl and jq being present on the system running fail2ban. | |
# | |
# To get your Cloudflare Account API token: Manage Account > Account API Tokens | |
# Cloudflare WAF Ruleset API: https://developers.cloudflare.com/api/resources/rulesets/ | |
[Definition] | |
# Option: actionstart | |
# Notes.: command executed on demand at the first ban (or at the start of Fail2Ban if actionstart_on_demand is set to false). | |
# Values: CMD | |
# | |
actionstart = | |
# Option: actionstop | |
# Notes.: command executed at the stop of jail (or at the end of Fail2Ban) | |
# Values: CMD | |
# | |
actionstop = | |
# Option: actioncheck | |
# Notes.: command executed once before each actionban command | |
# Values: CMD | |
# | |
actioncheck = | |
# Option: actionban | |
# Notes.: command executed when banning an IP. Take care that the | |
# command is executed with Fail2Ban user rights. | |
# Tags: <ip> IP address | |
# <failures> number of failures | |
# <time> unix timestamp of the ban time | |
# Values: CMD | |
actionban = curl -s -X POST <_cf_api_url_ruleset> <_cf_api_prms> \ | |
--data '{"description":"<notes>","expression":"(ip.src eq <ip>)","action":"<cfmode>","enabled":true}' | |
# Option: actionunban | |
# Notes.: command executed when unbanning an IP. Take care that the | |
# command is executed with Fail2Ban user rights. | |
# Tags: <ip> IP address | |
# <failures> number of failures | |
# <time> unix timestamp of the ban time | |
# Values: CMD | |
# | |
actionunban = rule_id=$(curl -s -X GET <_cf_api_url_entrypoint> <_cf_api_prms> | <_rules_query_by_timestamp>) | |
if [ -z "$rule_id" ]; then echo "<name>: id for <ip> cannot be found using target <time>"; exit 0; fi; \ | |
curl -s -X DELETE <_cf_api_url_ruleset>/$rule_id <_cf_api_prms> | |
_cf_api_url_base = https://api.cloudflare.com/client/v4/zones/<cfzone>/rulesets | |
_cf_api_prms = -H "Authorization: Bearer <cftoken>" -H "Content-Type: application/json" | |
_cf_api_url_entrypoint = <_cf_api_url_base>/phases/http_request_firewall_custom/entrypoint | |
## retrieve the id of the default ruleset for custom rules | |
_ruleset_id = $(curl -X GET <_cf_api_url_entrypoint> <_cf_api_prms> | jq .result.id -r) | |
## base url for queries including the ruleset id | |
_cf_api_url_ruleset = https://api.cloudflare.com/client/v4/zones/<cfzone>/rulesets/<_ruleset_id>/rules | |
## jq query used to find matching rules based on ban timestamp - for unbans | |
_rules_query_by_timestamp = jq '.result.rules.[] | select([ .description | contains("<time>") ] | any) .id' -r | |
[Init] | |
# Declare your Cloudflare Authorization Bearer Token in the [DEFAULT] section of your jail.local file. | |
# The Cloudflare <ZONE_ID> of the domain you want to manage. | |
# ie vbf47280fbceb034e842dd7631a484op | |
# | |
cfzone = >>CF_ALPHANUMERIC_ZONE_ID<< | |
# Cloudflare Account API token. Ideally restricted to just have "Zone.Zone WAF" permissions. | |
# | |
cftoken = >>CF_TOKEN_GOES_HERE<< | |
# The firewall mode Cloudflare should use. Default is "block" (deny access). | |
# Consider also "js_challenge" or other "allowed_modes" if you want. | |
# | |
cfmode = block | |
# The message to include in the firewall IP banning rule. | |
# | |
notes = Fail2Ban <name> - <time> | |
[Init?family=inet6] | |
cftarget = ip6 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment