Anleitung: Fail2ban mit mehreren Servern synchronisieren

Fail2ban ist schon eine feine Sache. Gerade auf Servern die Ihre Dienste im Netz öffentlich bereitstellen die man nicht einfach komplett mit iptables verriegeln kann. Da ist es schon wirklich hilfreich wenn man mit Fail2ban einfach die Leute aussperrt die einem böses wollen.

Aber ich will hier gar nicht soweit auf die Funktionen oder die Funktionsweise von Fail2ban eingehen sondern auf die Besonderheiten im Einsatz mit mehreren Servern und die Möglichkeit die gesperrten IP’s auch den anderen Servern zugänglich zu machen und auch dort direkt zu sperren, da es sehr oft ja Bots oder tatsächliche Hacker die probieren ins System zu kommen.

Wenn man also schon weiß, dass die IP “bösartig” ist, wieso sollte man also warten bis eine andere Instanz diesen nach erneuten X versuchen auf dem anderen Server sperrt? Genau. Es gibt keinen Grund dafür.

Das Problem ist nur, dass Fail2ban mit eigenen mitteln keine anderen Server kennt und auch keinem anderem Server mitteilen kann “ich habe IP X und Y gesperrt, tue du das auch”.

Man kann diese Funktion allerdings mittels kleinerer Anpassungen einbauen. Vorausgesetzt man will dies auch.

Es gibt dazu übrigens etliche Anleitungen im Netz allerdings sind sie meistens out of Date. Viele PHP Scripte sind dazu im Umlauf aber die meisten sind mit PHP Versionen 5.6 oder neuer einfach nicht mehr kompatibel oder werfen Fehler weil sich die Bash Versionen usw. geändert haben und anders auf Befehle reagieren oder aber einfach schlecht geschriebene oder unvollständige Scripte.

Sei es weil mysql_connect schon lange veraltet ist und mit neueren Methoden via PDO oder mysqli gibt es gar keins im Netz.

So und wie bringe ich nun meine Systeme dazu miteinander zu sprechen? Mit den Lösungen, die im Umlauf sind, jedenfalls gar nicht. Und ich habe wirklich lange gesucht um anschließend mir doch selbst die Mühe zu machen und die Sachen selbst zu schreiben, damit ich auch neuere Systeme einbinden kann ohne großartige extra Repos am System. Klar könnte man auch einfach andere Paketquellen nutzen und mittels dieser alte PHP Versionen etc. installieren aber dann stellt sich die Frage wie lange man die alten Pakete noch rum schleppen will. Zudem ist da die Wartung und schließen der Sicherheitslücken aufwändiger als einmal die Scripte zu schreiben.

Die Sachen teile ich natürlich gerne.

Was brauchen wir also alles? Eigentlich recht wenig. Eine MySQL Datenbank, 2 Scripte und ein paar Abhängigkeiten auf der Konsole. Fangen wir also an mit den Abhängigkeiten. 

 

Installieren von Abhängigkeiten für unser Vorhaben

 

Ich gehe mal davon aus, dass es sich um einen frisch installierten Server handelt (In meinem Beispiel verwende ich ein Debian Stretch System). Sollte dem nicht so sein auch kein Problem. 

apt-get install fail2ban php-cli php-mysqlnd mysql-client iptables ipset cron

Bei den Paketen muss man natürlich auf seine Version und sein System aufpassen und diese ggf. anpassen. Debian Jessie hat zum Beispiel kein Paket Namens php-cli oder php-mysqlnd. Dort heißen diese php5-cli und php5-mysqlnd.

Damit haben wir den ersten und wichtigsten Schritt schon erledigt.

 

Datenbank für die gesperrten IPs erstellen

 

Nun können wir die Datenbank für die IP’s erstellen.

Entweder macht Ihr das per PHPMyAdmin oder per Konsole. Per PHPMyAdmin könnt Ihr einfach die SQL Datei aus diesem Archiv in eine vorhandene Datenbank importieren.

Alternativ könnt Ihr dieses SQL in eurer Datenbank ausführen:

CREATE TABLE `sync_fail2ban` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`hostname` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`created` datetime NOT NULL,
`name` text COLLATE utf8_unicode_ci NOT NULL,
`protocol` varchar(16) COLLATE utf8_unicode_ci NOT NULL,
`port` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
`ip` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `hostname` (`hostname`,`ip`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

 

Synchronisation zwischen mehreren Servern einrichten

Kommen wir nun zum eigentlichen Sync Job. In diesem Archiv sind 2 Scripte. Ein PHP Script und ein Bash Script. Das PHP Script pusht die gesperrten IP’s in eure Datenbank und das Bash Script holt die IP’s ab die auf den anderen Servern gesperrt wurden.

Fangen wir mit der PHP Datei an.

#!/usr/bin/php
<?php
$name = $_SERVER["argv"][1];
$protocol = $_SERVER["argv"][2];
$port = $_SERVER["argv"][3];
if (!preg_match('/^\d{1,5}$/', $port))
$port = getservbyname($_SERVER["argv"][3], $protocol);
$ip = $_SERVER["argv"][4];
$date = date("Y-m-d H:i:s");
$hostname = gethostname();

// Verbindungsdaten einfügen | insert your database settings
$link = new mysqli("IP-DB-SERVER", "DB-USERNAME", "DB-PASSWORT", "DATENBANKNAME");
// Ab hier nix verändern | don't change anything below
if ($link->connect_error) {
die("Verbindung fehlgeschlagen: " . $link->connect_error());
}
$query = "INSERT INTO sync_fail2ban (name, protocol, port, ip, created, hostname)
VALUES ('$name', '$protocol', '$port', '$ip', '$date','$hostname')";
if ($link->query($query) === TRUE ){
echo "Eintrag erfolgreich geschrieben";
} else {
echo "ERROR: " .$query . "<br>" . $link->error;
}
$link->close ();
?>

In dieser Datei müsst Ihr natürlich eure Daten noch anpassen und mit euren ersetzen und unter /etc/fail2ban/fail2ban-push.php abspeichern. Kein großer Akt oder?

Fail2ban Konfigurationen anpassen

Als nächstes müssen wir noch die Actionen bei einem Ban anpassen. Dazu gibt es unter /etc/fail2ban/action.d 2 Dateien. Die iptables-allports.conf und die iptables-multiport.conf

Diese beiden Dateien haben eine Zeile in der “actionban” am Anfang der Zeile steht.

Ans Ende fügt ihr

|/etc/fail2ban/fail2ban-push.php <name> <protocol> <port> <ip>

ein, sodass die Zeile dann in etwa so aussieht

actionban = iptables -I fail2ban-<name> 1 -s <ip> -j <blocktype> |/etc/fail2ban/fail2ban-push.php <name> <protocol> <port> <ip>

Die Platzhalter dürft Ihr nicht verändern. Wenn das in beiden Dateien geschehen ist könnt ihr das Script mal ausprobieren. Wechselt in das Verzeichnis /etc/fail2ban und führt dort folgenden Befehl aus:

/usr/bin/php fail2ban-push.php test ssh tcp 10.8.0.101

Wenn keine Fehlermeldung kommt solltet Ihr den Eintrag in eurer Datenbank sehen. Soweit also so gut.

Als nächstes müssen wir noch einen Jail anlegen indem wir die gesyncten IP’s für den Ban eintragen können.

Dazu tragt in /etc/fail2ban/jail.conf diese Jail ein

[globalsync]
 enabled = true
port = anyport
filter = sshd
logpath = /var/log/auth.log
maxretry = 1
banaction = iptables-allports
action = %(action_)s

Also nun haben wir es schon fast geschafft. Anschließend starten wir den Dienst neu mit Beispielsweise “service fail2ban restart” aber das ist abhängig von eurem System.

IP Adressen aus der Datenbank holen und Bannen

Des weiteren müssen wir noch die IP’s aus der Datenbank holen und sperren. Wir sperren die IP mit diesem Script komplett also nicht nur auf bestimmte Ports.

 

#!/bin/bash

#Autor: www.DL-Host.Info

#Löschen der älteren Einträge nach Ablauf 720 Min um Müll zu entfernen
mysql -uDEIN-USERNAME -pDEIN-PASSWORT -h IP-DB-Server -e 'use DEIN-DATENBANKNAME; DELETE FROM sync_fail2ban WHERE DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL 720 MINUTE) > created;'
#doppelte Einträge ausschließen
touch /etc/fail2ban/doppelteips
doppelteips=`/sbin/iptables -L f2b-globalsync -n | grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"`
for IP in $doppelteips
do
echo "$IP" >> /etc/fail2ban/doppelteips
done
#Löschen von 0.0.0.0 Adressen falls vorhanden
sed -i '/^0/d' /etc/fail2ban/doppelteips
#Auslesen der DB und doppelte IPs ignorieren und Sperren einrichten
test=`mysql -uDEIN-USERNAME-pDEIN-PASSWORT -h IP-DB-Server -e 'use DEIN-DATENBANKNAME; SELECT DISTINCT ip FROM sync_fail2ban;'`
for IP in $test
do
if [[ `grep -c $IP /etc/fail2ban/doppelteips` == 0 ]] then
/sbin/iptables -I f2b-globalsync -s $IP -j DROP
else
echo "$IP bereits gesperrt"
fi
done

rm -R /etc/fail2ban/doppelteips

#######

touch /etc/fail2ban/blacklist
touch /etc/fail2ban/blacklisth

datenbank=`mysql -uDEIN-USERNAME-pDEIN-PASSWORT -h IP-DB-Server -e 'use DEIN-DATENBANKNAME; SELECT DISTINCT ip FROM fail2ban;'`

for IP in $datenbank
do
echo "$IP" >> /etc/fail2ban/blacklist
done

/sbin/iptables -L f2b-globalsync -n | grep -E -o "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" >> /etc/fail2ban/blacklisth

 

sed -i '/^0/d' /etc/fail2ban/blacklisth
ipblock=`grep -c $IP /etc/fail2ban/blacklisth`

for IP in $ipblock
do
if [[ `grep -c $IP /etc/fail2ban/blacklist` == 0 ]] then
/sbin/iptables -D f2b-globalsync -s $IP -j DROP
else
echo "$IP entfernt"
fi
done

rm -R /etc/fail2ban/blacklist
rm -R /etc/fail2ban/blacklisth
exit 0;

 

Das Script wird anschließend unter /etc/fail2ban/fail2ban-get-ip.sh gespeichert. Danach müssen beide Scripte noch per chmod +x ausführbar gemacht werden.

Abschließender Test

Dann solltet Ihr das Script natürlich testen indem ihr es einmal mittels ./fail2ban-get-ip.sh ausführt. Sollte anschließend eine Meldung wie “iptables: No chain/target/match by that name.” auftauchen müsst Ihr das Script noch mal anpassen und entsprechend f2b-globalsynvc gegen fail2ban-globalsync in den iptables Befehlen austauschen.

Wie eure Jail genau heißt könnt Ihr mittels iptables -L herausfinden. Es werden damit alle Jails aufgelistet.

Anschließend wird noch ein Cron eingerichtet der alle 2 Minuten die aktualisierte IP Liste aus der Datenbank holt und die IP’s anschließend direkt sperrt

Mittels crontab -e einfach folgenden Cron einrichten

*/2 * * * * /bin/bash /etc/fail2ban/fail2ban-get-ip.sh

Weiterhin sind sagt euch das Script bei einer manuellen Ausführung welche IP’s bereits gesperrt sind, löscht alte Einträge aus der Datenbank, entfernt die Sperren in iptables und gibt auch Feedback darüber in der Konsole.

 

Die Scripte sind so geschrieben dass sie auf Debian sowie auch auf anderen Systemen funktionieren. Somit eventuell nur eine Anpassung der iptables Befehle nötig sein um es einsetzen zu können. 

Das PHP Script ist mit der mysqli Schnittstelle geschrieben. Somit sollte es da auf keinem System Probleme geben und auch die nächsten Jahre einwandfrei funktionieren.

Für andere Lösungen oder Verbesserungsvorschläge bin ich immer offen. Hinterlasst Sie mir gern mittels Kommentar oder Mail.

Alle benötigten Scripte und die SQL findet Ihr auch hier in diesem Archiv. Könnt Ihr ebenfalls downloaden und die Dateien einfach auf eure Server schieben.

 

In diesem Sinne, bis zum nächsten mal.

Share it!Share on FacebookEmail this to someoneShare on Google+Tweet about this on Twitter

Schreibe einen Kommentar