I was going to write this up separately but it probably belongs as a subsection to this article.
Setting up Fail2Ban
Fail2ban is a nice little service that will update your firewall to ban connections from certain IP addresses after a certain number of failed login attempts in a certain amount of time. It provides an extra layer of protection to your server now that it is exposed to the Internet and every script kiddie in the world sees your open port and starts knocking on the door.
If you have ssh exposed to the Internet, openHAB 1.x, or a whole host of other services, this is a great tool to filter out sources of attack once bad actors are detected.
For the most part the bulk of the attacks will be bots trying combinations of common and/or default usernames and passwords (ALWAYS reset the default password people!) but there is no reason why your server needs to be spending CPU cycles and wasting bandwidth processing these sorts of attacks.
Basic setup is pretty easy but I found and have been using a little bit of extra special sauce to make the bans permanent because Iāve seen some IPs which hit me once a day rather than a bunch of times in a row.
#Installation
These instructions are for Ubuntu. They should work for raspbian as well but I donāt know for sure.
Installation is just a quick:
apt-get update
apt-get install fail2ban
It will probably have a bunch of dependencies to install as well.
Configuration
In good Debian fashion, the config files are in /etc/fail2ban
. The config file to be concerned with is jail.conf. This is the default config but unfortunately this file gets overwritten during updates so what you want to do is create a jail.local file and comment out everything. This gives you an example of all the configs without overriding everything in the main .conf file. You can do this with the following command:
sudo awk '{ printf "# "; print; }' /etc/fail2ban/jail.conf | sudo tee /etc/fail2ban/jail.local
Now you will want to change a few settings.
Find the section that starts with [DEFAULT]
. Uncomment the [DEFAULT]
and ignoreip line and add your LAN, openVPN subnet, Docker subnet, et al (i.e. any internal subnets that should be allowed to fail to login without being banned). If you have some known external IPs or IP ranges that you know you will be logging in from add those as well. You donāt want to accidentally ban yourself when you know the access is you.
Next find the bantime
parameter. By default the ban time is 10 minutes. If there are maxretry
failed attempts in failtime
the IP will be banned for this long. I set mine to -1 which means any failed login attempt results in a ban. Uncomment and set to an appropriate value for you.
Next find the findtime
parameter and set it to an appropriate value. I set mine to 48 hours (i.e. 2880 minutes) so I can catch those guys coming after me slowly.
The next field is the maxretry
field. I use 1 so they get banned on the first attempt.
Scroll down a bit and configure destemail
and mta
to an appropriate value. I use ssmtp on my system so system emails get sent to my gmail address. This will give you an alert email every time fail2ban bans an IP. We will configure it to include a bunch of information from whois as well so you can see where the attempt is coming from.
Now find the [nginx-http-auth]
section. Uncomment this section, add an enabled=true
and if necessary change the path to the nginx error.log file. Iām using a Dockerified nginx so my log is in /opt/nginx/logs. Finally add the action. This is what fail2ban will do when it finds a failed login. I use action_mwl
which bans the IP and sends an email with whois report and relevant log lines to destmail we configured. Look at the commented out sections for alternatives actions.
I donāt know if this is required but the SSHD tutorials I used have you do this so Iām doing it too. There are a number of files in the filters.conf directory which contain regular expressions that are used to determine if a line in the log file represents a failed attempt. Below I specify to use the nginx-http-auth.conf file but I donāt know if that is required.
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
action = %(action_mwl)s
#logpath = %(nginx_error_log)s
logpath = /opt/nginx/logs/error.log
If you have a standard install the default %(nginx_error_log)s
can be left unchanged.
Now stop fail2ban so we can set a default firewall configuration.
Firewall
If you havenāt already, install iptables-persistent which will let you save your iptables configuration when the machine reboots.
If you already have a good iptables configuration skip this step. If not, the following will create a basic base firewall table that allows incoming connections for ssh (port 22) and HTTP (port 80) and HTTPS (port 443).
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
sudo iptables -A INPUT -j DROP
If you want to access to other ports from other machines beyond localhost add additional -A INPUT lines like above to accept those connections as well.
You can see the current firewall rules by typing:
sudo iptables -S
You can save firewalls so they survive a reboot using:
sudo dpkg-reconfigure iptables-persistent
Create a blacklist
Now we need to make a minor change to /etc/fail2ban/iptables-multiport.conf
. In the section actionstart
add a line to cat the offending IP to ip.blacklist. It should look like this:
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/ip.blacklist \
| while read IP; do iptables -I f2b-<name> 1 -s $IP -j REJECT --reject-with icmp-port-unreachable; done
The above will take all of the IP addresses in ip.blacklist and add a rule to ban them in iptables when fail2ban startsup. Thus once fail2ban flags an IP as bad it will permanently be banned until you remove the IP from the blacklist.
To populate the blacklist add an echo to add the banned IP to the blacklist to actionban.
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>
# Persistent banning of IPs
echo '<ip>' >> /etc/fail2ban/ip.blacklist
Start fail2ban
Now start up the service.
Fail2ban works by scrolling through your log files so every time you start it will see all the failed attempts currently in your relevant log files. If you are under particular amount of attack that will mean you will be deluged with dozens if not a hundred emails every time you restart fail2ban.
Likewise, because it follows the log file it isnāt always really fast about recognizing all the IPs right away. Some attacks have dozens of attempts before fail2ban sees them.
Finally, Iām not 100% certain that it catches every attempt every time. But it is better than nothing. In the month or so that Iāve been running it on ssh Iāve banned close to 10,000 IPs.
#Removing an IP from the Ban
First find and remove the IP from /etc/fail2ban/ip.blacklist
.
Next find the rule blocking the IP you want to now allow using the following command:
sudo iptables -S | grep <ip address>
where <ip address>
is the IP you want to unban.
Copy the rule you found with the above command and delete it with:
sudo iptables -D <rule specification>
where <rule specification>
is the rule copied.
#References
I donāt remember where I got the trick to create and use the ip.blacklist