-
-
Save Xunnamius/6057a660d06bcf13cc1f478af9131423 to your computer and use it in GitHub Desktop.
# This version works with CF WAF (using zone rulesets) and obsoletes previous | |
# versions. This works will all CF account types. This action depends on curl | |
# and jp and will add/remove IPs from the $known_hostile_ips list. Creating the | |
# WAF rules need only be done once per zone. Creating the list need only be done | |
# once per account. | |
# | |
# Author: Bernard Dickens III (Xunnamius) | |
# | |
# Inspired by work from: Mike Rushton | |
# https://github.com/fail2ban/fail2ban/blob/master/config/action.d/cloudflare.conf | |
# | |
# 1. REQUIRES jp TO BE INSTALLED IN THE USER PATH! Install it here: | |
# https://github.com/jmespath/jp | |
# | |
# 2. ! IMPORTANT ! Set jail.local's permission to 640 because it contains one of | |
# your CF API tokens. Grab your account id, your api token, and your "hostile | |
# ip" list id before continuing (see end of file for details). | |
# | |
# 3. Create a new custom list. Name it known_hostile_ips. | |
# https://developers.cloudflare.com/waf/tools/lists | |
# | |
# 4. Ensure every zone you want fail2ban to protect has an enabled WAF ban rule | |
# referencing $known_hostile_ips. | |
# https://developers.cloudflare.com/waf/custom-rules | |
# | |
# 5. Use the fail2ban CLI and the Cloudflare dashboard/Traces to test and make | |
# sure everything is working properly. You may need to add a permission to | |
# your api token to ensure proper function. See the end of this file for | |
# details. | |
# | |
# To get your CloudFlare API Key: | |
# https://www.cloudflare.com/a/account/my-account | |
# | |
# CloudFlare API error codes: https://www.cloudflare.com/docs/host-api.html#s4.2 | |
# | |
# Note that if you're using Nginx, Apache, Litespeed, etc, you need to modify | |
# your logs and/or your filters such that the real client IP is being captured | |
# and not Cloudflare's IPs. | |
[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 | |
# | |
# API v4 WAF | |
actionban = curl -s -o /dev/null -X POST <_cf_api_prms> \ | |
-d '[{"ip":"<ip>","comment":"Created by fail2ban <name>"}]' \ | |
<_cf_api_url> | |
# 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 | |
# | |
# API v4 WAF | |
actionunban = id=$(curl -s -X GET <_cf_api_prms> \ | |
"<_cf_api_url>?search=<ip>&per_page=1" \ | |
| { jp --unquoted 'result[0].id | not_null(@, `""`)' 2>/dev/null; }) | |
if [ -z "$id" ]; then echo "<name>: id for <ip> cannot be found"; exit 0; fi; | |
curl -s -o /dev/null -X DELETE <_cf_api_prms> \ | |
-d '{"items":[{"id":"'"$id"'"}]}' \ | |
<_cf_api_url> | |
_cf_api_url = https://api.cloudflare.com/client/v4/accounts/<cfaccountid>/rules/lists/<cfbanlistid>/items | |
_cf_api_prms = -H 'Authorization: bearer <cfapitoken>' -H 'Content-Type: application/json' | |
[Init] | |
# If you like to use this action with mailing whois lines, you could use the | |
# composite action action_cf_mwl predefined in jail.conf, just define in your | |
# jail: | |
# | |
# action = %(action_cf_mwl) | |
# # Your CF API Key | |
# cfapitoken = | |
# cfaccountid = | |
# cfbanlistid = | |
# Your Cloudflare User API Token. It will need "EDIT" level on the "Account | |
# Filter Lists" permission. | |
# https://dash.cloudflare.com/profile/api-tokens | |
cfapitoken = | |
# The identifier of the Cloudflare account used to update the hostile IP list. | |
cfaccountid = | |
# Your Cloudflare WAF "hostile ip" List id. You can find it using the API or or | |
# following the instructions here: | |
# https://community.cloudflare.com/t/what-token-permissions-for-ip-list-edits/525222/6 | |
# https://api.cloudflare.com/client/v4/accounts/:cfaccountid/rules/lists | |
# | |
# Note that even free CF accounts get 1 free list with 10,000 slots, yay! | |
# https://dash.cloudflare.com/:cfaccountid/configurations/lists | |
cfbanlistid = |
You have to add this action to the jails action
parameter (in jail.local), like here:
https://github.com/fail2ban/fail2ban/blob/1ea8a6de58e6d982b5e42db5b1761281e91c51e1/config/jail.conf#L236-L237 (or below or above)...
To check the action is applied to the jail in config you can see the dump fail2ban-client --dp
...
And then restart (not just reload) the jail or fail2ban.
You have to add this action to the jails
action
parameter (in jail.local), like here: https://github.com/fail2ban/fail2ban/blob/1ea8a6de58e6d982b5e42db5b1761281e91c51e1/config/jail.conf#L236-L237 (or below or above)... To check the action is applied to the jail in config you can see the dumpfail2ban-client --dp
... And then restart (not just reload) the jail or fail2ban.
Thanks, this was what was missing from my jail.local
For those who are using a docker-compose. This is how I installed jp as the instructions require. Add this to your docker-compose.yaml file underneath the fail2ban container.
command: /bin/sh -c "apk add --update jp && fail2ban-server -f"
For this to work I have append > /dev/null to the end of the curl commands. For some reason my curl version was ignoring the -o param...
actionban = curl -s -o /dev/null -X POST <_cf_api_url> \
<_cf_api_prms> \
-d '[{"ip":"'"<cfip>"'","comment":"<cfcomment>"}]' \
> /dev/null
For a more confortable solution because I've already work with jq but not jp command I end using the solution in this thread https://community.cloudflare.com/t/does-cloudflares-fail2ban-action-still-work/640904/3 that display the { jq -r '.result[0].id' 2>/dev/null || tr -d '\n' | sed -nE 's/^.*"result"\s*:\s*\[\s*\{\s*"id"\s*:\s*"([^"]+)".*$/\1/p'; }
command to the pipe part of the actionunban.
I'm not getting any errors related to the banning action
2024-09-05 15:13:01,875 fail2ban.actions [1856146]: NOTICE [sshd] Ban 10.10.10.10