Centralize Fail2Ban - Part 2

fail2ban centralized control from a database Read attacker IP's from a database and lock

At our first part of this HowTo has already explained how to write the IP addresses of potential attackers in a central database.
In the second part, you now want to read these IP addresses from the database and to achieve a real blocking by Fail2Ban.

This second part should be just a thought. It is not a complete solution, but with the basics of this HowTo you are capable to build a security system which is adaptable to your own requirements.

System Requirements

This HowTo assumes that fail2ban, iptables and php is installed functional on the system.
On Ubuntu, you can quickly do:

root@devserv3:~# sudo apt-get install php5 fail2ban iptables

Now the Fail2Ban configuration file will be prepared. For this purpose, the supplied with Fail2Ban file is copied and edited (Nano is the editor) opened.

cd /etc/fail2ban && cp jail.conf jail.local && nano jail.local

In the jail.local a jail at the end of the default block is inserted. The name of the jail "blocklist"

enabled  =  true
port     =  ssh
filter   =  sshd
logpath  =  /etc/fail2ban/empty.log
maxretry =  1
banaction = iptables-allports
action   = %(action_)s

With this blocklist we define a file /etc/fail2ban/empty.log to be monitored. The maximum break-in attempt is set to 1, so that the first appearance of an IP address will be blocked. The type of blocking is set with banaction and means in the example a blocking of the IP on all ports.
For the attacker behind the locked IP, the server is no longer accessible. Here it is important to ensure that you do not lock out yourself!

Now must Fail2Ban be restarted once and it can be tested whether Fail2Ban IP takes in the blocklist.
For this purpose, an IP address will be passed to Fail2Ban to be locked and a "-" is written into emptly-log to indicate a change to Fail2Ban. Then Fail2Ban will block the given IP.

root@devserv3:~# service fail2ban restart
 * Restarting authentication failure monitor fail2ban             [ OK ]
fail2ban-client set blocklist banip echo "-" > /etc/fail2ban/empty.log;

If there was no error message has all worked out. If an error occurs take a look in the log file to get more informations (/var/log/fail2ban.log). In iptables, the IP should now be also listed.

root@devserv3:~# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
fail2ban-blocklist  tcp  --  anywhere             anywhere
fail2ban-ssh  tcp  --  anywhere             anywhere             multiport dports ssh

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain fail2ban-blocklist (1 references)
target     prot opt source               destination
DROP       all  --  1-168-100-1.dynamic.hinet.net  anywhere
RETURN     all  --  anywhere             anywhere

Chain fail2ban-ssh (1 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere

PHP script to get the IP from the database

Now a small PHP script is used, the read from the central database, the IP addresses.
To prevent that all IP addresses are repeatedly read from the database, the database column "created" be used as a helper. So only the entries of the last 60 seconds are fetched in the script.
The name of the script is fail2ban.get.php

#!/usr/bin/php -n
// connect to mysql by hostname, username and password
$link = mysql_connect('devserv3', 'fail2ban', 'password') or die('Could not connect: ' . mysql_error());
mysql_select_db('fail2ban') or die('Could not select database');
$query = 'SELECT ip FROM `fail2ban` where created>DATE_ADD(NOW(), INTERVAL -60 SECOND)';
$result = mysql_query($query) or die('Query failed: ' . mysql_error());
$cmd = null;
while ($row = mysql_fetch_object($result)) {
    $cmd .= 'fail2ban-client set blocklist banip ' . $row->ip . ' && ';
if ($cmd) {
    $cmd .= "echo \"-\" > /etc/fail2ban/empty.log";
    $cmd = $cmd . ' >/dev/null 2>/dev/null &';
    exec($cmd, $output, $returnValue);

Now briefly test the script ....

root@devserv3:~# ./fail2ban.get.php

No error ? Great.
Now we put the script into a cron job, so it is called every minute and read IP's to lock. The call cycle can also raise, if it is should not be any minute - but then adjust accordingly the 60 seconds in the script.
We modify with nano this file: /etc/crontab and add the following at the end.

*/1 * * * * root nice -n 19 /usr/bin/php -c /etc/php5/apache2/php.ini -f /root/fail2ban.get.php > /dev/null 2>&1


Back to part 1 - Centrally collect Fail2ban IP's in a database

Status: 2015-10-15