Installation and Configuration of Fail2Ban

The world of Linux is fascinating, and security is a crucial chapter of this journey. Fail2Ban is one of those essential tools for any Linux administrator concerned about protecting their servers. By monitoring system logs, it detects intrusion attempts on services such as SSH, HAProxy, or Postfix. And if an intruder becomes too persistent? Fail2Ban steps in, blocking the offender’s IP address via IPTables. One of the major strengths of Fail2Ban is its flexibility. You can create and tailor your own filters according to your needs. In this article, I will guide you through the installation and configuration of Fail2Ban on Debian.

Diagram illustrating the operation of Fail2Ban

Operation of Fail2ban in 5 steps:

1. Monitoring: Fail2Ban continuously scans log files.

2. Detection: It identifies suspicious activities based on established rules.

3. Consultation: Before taking action, it checks if the offending IP is already listed in its “jail”.

4. Transmission: If the IP is deemed malicious, it is sent to IPTables.

5. Blocking: IPTables takes over and blocks the concerned IP address.

We start by installing the necessary packages.

apt-get update
apt-get install fail2ban iptables iptables-persistent

Then we configure IPtables to avoid blocking the flows we use. In this example, I won’t dwell too much on the rules or do something advanced like SSH filtering by source IP.

We set the default rules for the INPUT, FORWARD, and OUTPUT chains:

iptables -P INPUT ACCEPT 

iptables -P FORWARD ACCEPT 

iptables -P OUTPUT ACCEPT

Next, we need to allow traffic on the ports in use.

For an Apache or HAproxy server: 22 (SSH), 80 (HTTP) and 443 (HTTPS)

iptables -A INPUT -p tcp --dport 22 -j ACCEPT 

iptables -A INPUT -p tcp --dport 80 -j ACCEPT 

iptables -A INPUT -p tcp --dport 443 -j ACCEPT

Very important, we also need to allow traffic for already established or related connections. It took me quite some time to understand why my DNS flow wasn’t coming back…

iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Then, finally, we block all other incoming traffic:

iptables -A INPUT -j DROP

Once you have configured IPtables as desired, you can save the current configuration so that it persists after the server restarts.

iptables-save > /etc/iptables/rules.v4

We list all the rules to ensure that they have been taken into account.

iptables -L -n -v

Now, we’re going to set up a Fail2Ban rule. The filtering rules are stored in /etc/fail2ban/filter.d/, but it’s also possible to create custom ones based on your needs.

Thus, we’ll create a rule for HAproxy to protect against <NOSRV> attempts.

So, we create the configuration file haproxy-noserv.conf.

nano /etc/fail2ban/filter.d/haproxy-noserv.conf

And then, we add our new rule:


[Definition]

failregex = ^.*haproxy\[\d+\]: <HOST>:\d+ \[\.*\] http_fe http_fe/<NOSRV> .*

ignoreregex =

Now that the filtering rule is added, we will define the conditions and actions of it in what’s called the jail (Jail).

We create a new file named haproxy.conf.

nano /etc/fail2ban/jail.d/haproxy.conf

And we add the parameters:

[haproxy-noserv]
enabled = true
filter = haproxy-noserv
action = iptables-allports sendmail-whois[name=Haproxy-noserv, dest=mail@mydomain.com]
bantime = 72000
maxretry = 4
findtime = 6000
logpath = /var/log/haproxy.log
ignoreip = 127.0.0.0/8 10.10.10.1/16

Some explanations:

    1. [haproxy-noserv]
      This defines the name of the “jail” in Fail2Ban. Each jail corresponds to a specific configuration to monitor a specific service or log.

    1. enabled = true
      This line activates the jail. If set to false, the jail will not be used even if it is configured.

    1. filter = haproxy-noserv
      This indicates the filter to use for this jail. This is the filter we created earlier that contains the necessary regular expressions to parse the logs and identify suspicious behaviors.

    1. action = iptables-allports
      This line defines the actions to take when an IP is banned. Here, iptables-allports blocks traffic on all ports for the banned IP.

    1. bantime = 72000
      Duration (in seconds) for which an IP will be banned. Here, it is set to 72000 seconds, or 20 hours.

    1. maxretry = 4
      Number of attempts allowed before an IP is banned. Here, after 4 attempts, the IP will be banned.

    1. findtime = 6000
      Duration (in seconds) during which Fail2Ban counts attempts. In this case, if an IP makes 4 attempts (or more) in less than 6000 seconds (i.e., 1 hour 40 minutes), it will be banned.

    1. logpath = /var/log/haproxy.log
      Path of the log file that Fail2Ban should monitor for this jail.

    1. ignoreip = 127.0.0.0/8 10.10.10.1/16
      List of IP addresses or IP address ranges that should never be banned. Here, it ignores all local IPs (127.0.0.0/8) and a specific range (10.10.10.1/16).

We now need to reload Fail2Ban.

systemctl restart fail2ban.service

With the following command, we can list the active jails.

fail2ban-client status

To see more details on a particular jail, we will use the same command but add the filtering rule at the end.

fail2ban-client status haproxy-noserv

So, we can appreciate the result and confirm that it works!

Status for the jail: haproxy-noserv
|- Filter
|  |- Currently failed: 4
|  |- Total failed:     65
|  `- File list:        /var/log/haproxy.log
`- Actions
   |- Currently banned: 5
   |- Total banned:     8
   `- Banned IP list:   XXX.XXX.XXX.XXX XXX.XXX.XXX.XXX XXX.XXX.XXX.XXX XXX.XXX.XXX.XXX XXX.XXX.XXX.XXX

You’ll notice that my filter has banned 8 addresses of which 5 are still in jail and which I’ve anonymized, of course…

Leave a Comment