Upgrading fail2ban to a Permanent Banhammer

I don’t keep many logs on this site – on purpose – but I do keep logs on who’s trying to break into my SSH service. I use a popular tool called fail2ban that monitors service logs (such as sshd – but also many others) and then based upon throttles that you set will ban that IP from hitting the service for a certain period of time by inserting a rule into iptables. By default that ban is an hour and is usually enough to dissuade your typical script kiddies.

What I’ve noticed, however, is the same bunch of IP address trying again and again. They’d get banned and then within minutes of the hour ban being up, be back again for 5 more tries before being banned again. I presume these are machines that have become compromised and malware is simply rolling through IP addresses with SSH open and trying various combinations of usernames and passwords trying to find an opening.

Time to upgrade my banhammer to permanent. Here’s how to do it – it’s really easy.

First edit your jail file. Best practice is to use a .local file and not edit the .conf. .local will overwrite anything in your .conf so if you have only a couple settings to tweak it’s a good idea to use a .local. .locals also survive fail2ban updates.

jail.local

bantime = -1

By changing your bantime parameter to -1, this will be a permanent ban. This is the easy part. What we need to do now is make sure these permanent bans survive across fail2ban service restarts. (For instance if you run updates and then reboot your box.)

By default, fail2ban’s action is iptables-multiport. There’s an associated configuration file for that in

/action.d/iptables-multiport.conf

Find the block that begins with:

actionstart = <iptables> -N f2b-<name>

There should be 3 lines there. Add this to the bottom of the block:

cat /etc/fail2ban/persistent.bans | awk '/^fail2ban-<name>/ {print $2}' \
| while read IP; do iptables -I fail2ban-<name> 1 -s $IP -j <blocktype>; done

When you’re done the entire block should read:

actionstart = <iptables> -N f2b-<name>

              <iptables> -A f2b-<name> -j <returntype>

              <iptables> -I <chain> -p <protocol> -m multiport --dports <port> -j f2b-<name>

        cat /etc/fail2ban/persistent.bans | awk '/^fail2ban-<name>/ {print $2}' \

        | while read IP; do iptables -I fail2ban-<name> 1 -s $IP -j <blocktype>; done

Now further down find:

actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>

add an additional line:

echo "fail2ban-<name> <ip>" >> /etc/fail2ban/persistent.bans

When you’re done the entire block should read:

actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>

        echo "fail2ban-<name> <ip>" >> /etc/fail2ban/persistent.bans

Now restart fail2ban:

sudo service fail2ban restart

And you should be good to go! Just this morning I’ve brought the banhammer down on IPs from the Russian Federation, The Netherlands, Islamic Republic of Iran, and China.