fail2ban doesn't add IPs to ipset (firewalld)

Solution 1:

I have spent an absolute age trying to get this working today on a VPS (CentOS Linux 7.6.1810) with fail2ban installed through VirtualMin.

In my situation Fail2Ban was working correctly from its logs

tail -f /var/log/fail2ban.log

And correctly recording decisions to ban, however these were not being processed into firewalll rules. Having read through all of the comments in the answer posted by Moshe and trying three of the solutions there without success, I found that the solution by Geraden07 on a GitHub discussion linked from that forum post worked on Centos.

1. Create a new action rule (/etc/fail2ban/action.d/custom-firewalld.conf)

[INCLUDES]
before  =

[Definition]
actionstart =
actionstop =
actioncheck =

actionflush = sed -i '/<source address=/d' /etc/firewalld/zones/drop.xml
actionban = firewall-cmd --change-source=<ip> --zone=drop && firewall-cmd --change-source=<ip> --zone=drop --permanent
actionunban = firewall-cmd --remove-source=<ip> --zone=drop && firewall-cmd --remove-source=<ip> --zone=drop --permanent || echo 0

[Init]

2. Create/update jail config to use this new rule as the default (/etc/fail2ban/jail.local)

[DEFAULT]
banaction = custom-firewalld

3. Update any jails that override the default to use the new rule if needed

I have tested this for banning and unbanning and it is the only thing that has worked for me.

Solution 2:

Check to make certain that firewallcmd-ipset actually exists on your system; it no longer exists on CentOS 7.3 and above.

This firewalld-based work-around recreates firewallcmd-ipset. I'm about to implement it on my system.

Solution 3:

I had the same problem and I think there are several bugs in fail2ban that need to be fixed, for instance, the 00-firewalld.conf seems to be ignored completely.

To solve it set the desired action in your sshd filter section. My sshd jail looks like this (/etc/fail2ban/jail.d/sshd.local)

[sshd]
enabled = true
port = ssh
# set the action explicitly or the default iptables-allports will be used
# ==============================
action = firewallcmd-ipset
# ==============================
logpath = %(sshd_log)s
findtime = 600
maxretry = 3
bantime = 86400

Now the problem is that the bantime in your jail is ignored and the one defined in /etc/fail2ban/action.d/firewalld-ipset.conf takes precedence. So edit that action configuration file to include your new bantime

...
bantime=86400
...

And the last problem is that bantime=-1 for permanent bans does not seem to work. The developers fixed this in fail2ban +0.9 but it does not work for me although I am using fail2ban-0.9.7-1.el7

For your commodity what I exactly did was to copy firewallcmd-ipset.conf to firewalldcmd-ipset-custom.conf and edit the bantime there. Finally in your sshd jail definition set the action to action=firewallcmd-ipset-custom

Restart your fail2ban service after the changes.

Some output:

# firewall-cmd --direct --get-all-rules
ipv4 filter INPUT_direct 0 -p tcp -m multiport --dports ssh -m set --match-set fail2ban-default src -j REJECT --reject-with icmp-port-unreachable
# iptables -L -n | grep fail2ban
REJECT tcp -- 0.0.0.0/0   0.0.0.0/0    multiport dports 22 match-set fail2ban-default src reject-with icmp-port-unreachable
# ipset list | head
Name: fail2ban-default
Type: hash:ip
Revision: 1
Header: family inet hashsize 1024 maxelem 65536 timeout 86400
Size in memory: 53520
References: 1
Members:
x.x.x.x timeout 78498
y.y.y.y timeout 78506
z.z.z.z timeout 78454

What I still don't get is why the ipset is called fail2ban-default instead of fail2ban-sshd, probably I have something misconfigured, but the steps I describe are working and now IPs are being blocked from the set and I don't have +1000 rules in iptables anymore.