Fail2ban¶
Siehe auch
- Verwandte Artikel
- Offizielle Dokumentation
man fail2ban,man fail2ban-client,man jail.conf
- Linuxfabrik
Das 2004 erschienene Intrusion Prevention System Fail2ban (sinngemäss „Fehlschlag führt zum Bann“) scannt beliebige Log-Dateien mit Filtern auf bestimmte Muster und löst daraufhin eine oder mehrere frei definierbare Actions aus.
Als Aktionen kann Fail2ban beispielsweise:
die zugreifende IP-Adresse für einen definierten Zeitraum per iptables, firewalld, pf, ipfw oder nftables sperren
Mails inkl. Informationen über den Angreifer senden
die verdächtige IP auf Blocklists eintragen
dynamische DNS-Updates vornehmen
Filter werden durch anpassbare reguläre Ausdrücke definiert. Fail2ban wird mit einem umfangreichen Filter-Satz für verschiedenste Daemons wie Apache, SSH und andere geliefert.
Filter finden sich unter /etc/fail2ban/filter.d, Aktionen unter /etc/fail2ban/action.d (wo sie auch direkt konfiguriert werden können, z.B. für den Mail-Versand).
Die Kombination aus Filter, Action und einigen weiteren Konfigurationsparametern wird als Jail (Gefängnis) bezeichnet. Für jede Software, die Logdateien erstellt, kann ein Jail erstellt werden.
Fail2ban ist in Python geschrieben und arbeitet seit v0.9 intern mit einer SQLite-Datenbank in /var/lib/fail2ban/fail2ban.sqlite3, um seine Zustandsinformationen zu speichern. Die Datenbank wird auf im Internet hängenden Systemen auch mal 1 GB gross, kann jederzeit gelöscht werden; beim Neustart legt Fail2ban diese einfach wieder an.
Fail2ban besticht durch seine Schlichtheit, seine Unabhängigkeit von den zu prüfenden Diensten und durch die breite Anwendbarkeit.
Die Verzeichnisstruktur:
/etc/fail2ban
├── action.d:
│ Aktionen, die in einem Jail als "action"
│ angegeben werden können
│── filter.d:
│ Definition regulärer Ausdrücke, um Log-
│ Dateien zu untersuchen
└── jail.local:
Definition des "Gefängnisses" - welche Log-
Dateien sollen mit welchem Filter untersucht werden,
welche Aktionen sind anzuwenden, wie lange soll
geblockt werden usw.
- Begriffe
Action: in
action.d/<name>.confhinterlegte Prozedur, die bei einem Ban ausgeführt wird - per Default ein Firewall-Eintrag, optional E-Mail, Blocklist oder beliebiges Shell-Skript.Backend: Quelle, aus der Fail2ban die Logs liest. Ab v0.10 können
systemd(Journal viajournal_match=),polling(periodisches Scannen),pyinotifyodergamineingesetzt werden. Auf RHEL 8+ istsystemdder Default.bantime: Ban-Dauer in Sekunden (Default 600 s,
-1für permanent).Filter: regulärer Ausdruck (bzw.
failregex/ignoreregex) infilter.d/<name>.conf, der ein verdächtiges Log-Event erkennt.findtime: Zeitfenster in Sekunden, über das
maxretryzählt (Default 600 s).Incremental Banning: Mehrfach-Wiederholungstäter werden progressiv länger gebannt. Aktiviert durch
bantime.increment = trueinjail.local.Jail: Kombination aus Filter, Logpfad, Action und Timing-Parametern. Pro Service meist ein Jail (
[sshd],[apache-auth],[postfix], …).maxretry: Anzahl der Filter-Treffer pro
findtime, nach denen gebannt wird (Default 5).
Tipp
In Fail2ban-Konfigurationsdateien Kommentare nie an das Ende von Konfigurationsanweisungen stellen - sonst wird die ganze Zeile deaktiviert. Kommentare gehören immer in eigene Zeilen.
Installation und Konfiguration¶
Fail2ban muss dort installiert werden, wo die auszuwertenden Log-Dateien liegen. Installiert wird es aus dem EPEL-Repo:
dnf --assumeyes install epel-release
dnf --assumeyes install fail2ban whois
systemctl enable --now fail2ban
Fail2ban sollte nach dem Start der lokalen Firewall hochfahren, im Beispiel fwb.service. Bei Bedarf ist daher das Unit-File anzupassen:
After=default.target fwb.service #PartOf=firewalld.service
Der Installer für CentOS ignoriert schon seit Jahren (Stand 2020-11) ein paar Actions, von denen aber zugegeben auch nicht alle auf einem CentOS Sinn machen. Der Vollständigkeit halber:
# get the missing mail action files from GitHub
VER=$(fail2ban-server -V)
cd /etc/fail2ban/action.d
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/bsd-ipfw.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/cloudflare.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/hostsdeny.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/ipfilter.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/ipfw.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/mail-buffered.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/mail-whois-lines.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/mail-whois.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/mail.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/osx-afctl.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/osx-ipfw.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/pf.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/shorewall.conf
Ob Fail2ban arbeitet und was es macht, lässt sich per tail -f /var/log/messages /var/log/fail2ban.log überprüfen - in der Regel genügt ein LogLevel ab NOTICE aufwärts. Von besonderem Interesse sind die Meldungen fail2ban.actions ... NOTICE [sshd] Ban 10.80.32.156 und ... Unban 10.80.32.156 in /var/log/fail2ban.log.
Deinstallation¶
systemctl disable --now fail2ban
dnf --assumeyes remove fail2ban
Danach Residuen entfernen, die das Paket nicht aufräumt:
rm --recursive --force /etc/fail2ban
rm --force /etc/logrotate.d/fail2ban
rm --recursive --force /run/fail2ban
rm --recursive --force /var/lib/fail2ban
rm --force /var/log/fail2ban*
Fail2ban konfigurieren¶
Vorgehensweise¶
Optional: Filter entwickeln und testen
Optional: Action entwickeln und testen
Jail konfigurieren - Filter, Actions und Rahmenbedingungen zusammenführen
Filter entwickeln¶
In den regulären Ausdrücken kann <HOST> verwendet werden, wenn man die anfragende IP-Adresse matchen möchte - diese Variable ist daher auch in jedem Ausdruck Pflicht.
Reguläre Ausdrücke können so getestet werden:
fail2ban-regex -v /var/log/httpd/access_log 'myregex'
Im Beispiel soll ein Filter entwickelt werden, der eine übermässige Nutzung des Apache httpd verhindert. Erkennbar wird dies in /var/log/httpd/access*log-Dateien durch eine massive Flutung von GET-Requests von der gleichen IP. Am Ende möchten wir also einfach gegen die Anzahl aller Requests in einem bestimmten Zeitraum matchen.
# Fail2Ban filter to massive web requests for any ressources on Apache servers
#
# if bantime is low, it effectively slows down a ``ab -n 5000 http://ip-of-my-host/``
[INCLUDES]
# overwrite with apache-common.local if _apache_error_client is incorrect.
before = apache-common.conf
[Definition]
failregex = ^<HOST>
datepattern = ^[^\[]*\[({DATE})
{^LN-BEG}
# DEV Notes:
#
# example log lines:
# 10.80.32.156 - - [27/Nov/2020:14:10:55 +0100] "GET / HTTP/1.0" 200 252910 9921 www.linuxfabrik.ch -
# 10.80.32.156 - - [27/Nov/2020:14:10:55 +0100] "GET / HTTP/1.0" 200 252910 8355 www.linuxfabrik.ch -
# 10.80.32.156 - - [27/Nov/2020:14:10:55 +0100] "GET / HTTP/1.0" 200 252910 8961 www.linuxfabrik.ch -
# 10.80.32.156 - - [27/Nov/2020:14:10:55 +0100] "GET / HTTP/1.0" 200 252910 8165 www.linuxfabrik.ch -
#
# Author: Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
# https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.
Test gegen das bestehende Logfile.
fail2ban-regex -v /var/log/httpd/access_log /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf
Die zweimalige Angabe der Filter-Datei füttert das Kommando einmal mit dem failregex- und das zweite mal mit dem ignoreregex-Ausdruck (der in unserem Filter nicht vorhanden ist):
fail2ban-regex -v /var/log/httpd/access_log /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf
Es geht noch etwas genauer:
fail2ban-regex /var/log/messages /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf --print-all-matched
fail2ban-regex /var/log/messages /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf --print-all-missed
fail2ban-regex /var/log/messages /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf --print-all-ignored
Tipp
Wer Variablen in Filtern nutzen möchte, definiert diese in der jail.local und übergibt sie dem filter =-Aufruf, und zwar so:
[linuxfabrik-apache-dos]
filter = linuxfabrik-apache-dos[var1="%(myvar1)s", var2="%(myvar2)s"]
myvar1 = myvalue1
myvar2 = myvalue2
und im Filter:
failregex = ^... <var1> ... <var2>$
Action entwickeln¶
Im Beispiel soll die IP-Adresse nicht nur gebannt, sondern auch per Rocket.Chat benachrichtigt werden. Es muss also eine neue Action her.
# Author: Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
# https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.
#
# 2020120101
[Init]
rockethook =
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = curl --silent --output /dev/null -X POST -H 'Content-Type: application/json' -d '{"text":":fail2ban: banned <ip> for <bantime> seconds after <failures> attempts in jail *<name>* on `<fq-hostname>`\nTo unban use `fail2ban-client set <name> unbanip <ip>`"}' <rockethook>
#actionunban = curl --silent --output /dev/null -X POST -H 'Content-Type: application/json' -d '{"text":":fail2ban: unbanned <ip> from jail *<name>* on `<fq-hostname>`"}' <rockethook>
Diese Aktion benötigt noch ein freigeschaltetes SELinux-Boolean:
setsebool -P nis_enabled on
Jail konfigurieren¶
In der Jail kommen Action und Filter zusammen und werden mit „bantime“ und anderen Konfigurationsparametern versehen. Hier wird die Jail „linuxfabrik-apache-dos“ definiert, womit der gleichnamige Filter zur Anwendung kommt. IP-Adressen, die 200 und mehr Requests innerhalb von zehn Sekunden gegen den Webserver feuern, werden für 15 Minuten geblockt, und es wird per Rocket.Chat benachrichtigt.
[DEFAULT]
action = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
linuxfabrik-rocket-chat[name=%(__name__)s, rockethook="%(rockethook)s"]
banaction = iptables-multiport
chain = INPUT
ignoreip = 127.0.0.1/8 10.80.32.0/24
logpath = /var/log/httpd/*access.log
port = http,https
protocol = tcp
rockethook = https://chat.linuxfabrik.io/hooks/692136e4b03b41cc98c2d1aa1fe3bb35
[linuxfabrik-apache-dos]
bantime = 15m
enabled = true
findtime = 10s
maxretry = 200
Dump der Einstellungen und gleichzeitig Test auf syntaktische Korrektheit:
# fail2ban does not need to be running for this
fail2ban-client -d
Alles aktivieren:
systemctl reload fail2ban
Ignorierte IPs ermitteln¶
fail2ban-client get $JAIL ignoreip
Gesperrte IPs ermitteln¶
Mit dem fail2ban-client:
# get list of active jails
fail2ban-client status
# get stats on specific jail and
# "Banned IP list"
fail2ban-client status $JAIL
Alternativ mit iptables (falls damit geblockt wurde):
iptables --list --numeric
Die gesperrten IP-Adressen tauchen bei Verwendung der Action „iptables“ in eigenen iptables-Chains namens „f2b-$JAIL“ auf, so dass bei bekanntem Namen auch der Aufruf
iptables --list f2b-$JAIL --numeric
genügt. Der Name ergibt sich aus f2b- und angehängtem Jail-Name aus jail.local, im Beispiel oben also f2b-linuxfabrik-apache-dos.
Zählen, wieviele Adressen geblockt wurden (vom Ergebnis noch 3 abziehen):
iptables --list f2b-$JAIL --numeric | wc --lines
IP-Adresse manuell freigeben¶
Um die durch Fail2ban geblockte IP-Adresse 10.26.6.74 zu entsperren, entfernt man sie aus der passenden Jail:
fail2ban-client set $JAIL unbanip 10.26.6.74
Liste der mitgelieferten Jails und Actions¶
Actions:
abuseipdb
apf
apprise
blocklist_de
cloudflare
cloudflare-token
dshield
dummy
firewallcmd-allports
firewallcmd-common
firewallcmd-ipset
firewallcmd-multiport
firewallcmd-new
firewallcmd-rich-logging
firewallcmd-rich-rules
helpers-common
iptables
iptables-allports
iptables-ipset
iptables-ipset-proto4
iptables-ipset-proto6
iptables-ipset-proto6-allports
iptables-multiport
iptables-multiport-log
iptables-new
iptables-xt_recent-echo
ipthreat
mail-whois-common
mynetwatchman
netscaler
nftables
nftables-allports
nftables-multiport
nginx-block-map
npf
nsupdate
route
sendmail
sendmail-buffered
sendmail-common
sendmail-geoip-lines
sendmail-whois
sendmail-whois-ipjailmatches
sendmail-whois-ipmatches
sendmail-whois-lines
sendmail-whois-matches
shorewall-ipset-proto6
sm
symbiosis-blacklist-allports
xarf-login-attack
Filter:
3proxy
apache-auth
apache-badbots
apache-botsearch
apache-common
apache-fakegooglebot
apache-modsecurity
apache-nohome
apache-noscript
apache-overflows
apache-pass
apache-shellshock
assp
asterisk
bitwarden
botsearch-common
centreon
common
counter-strike
courier-auth
courier-smtp
cyrus-imap
directadmin
domino-smtp
dovecot
dropbear
drupal-auth
ejabberd-auth
exim
exim-common
exim-spam
freeswitch
froxlor-auth
gitlab
grafana
groupoffice
gssftpd
guacamole
haproxy-http-auth
horde
ignorecom
ignorecommands/apache-fakegoog
kerio
lighttpd-auth
mongodb-auth
monit
monitorix
mssql-auth
murmur
mysqld-auth
nagios
named-refused
nginx-bad-request
nginx-botsearch
nginx-http-auth
nginx-limit-req
nsd
openhab
openwebmail
oracleims
pam-generic
perdition
php-url-fopen
phpmyadmin-syslog
portsentry
postfix
proftpd
pure-ftpd
qmail
recidive
roundcube-auth
scanlogd
screensharingd
selinux-common
selinux-ssh
sendmail-auth
sendmail-reject
sieve
slapd
softethervpn
sogo-auth
solid-pop3d
squid
squirrelmail
sshd
stunnel
suhosin
tine20
traefik-auth
uwimap-auth
vsftpd
webmin-auth
wuftpd
xinetd-fail
znc-adminlog
zoneminder
Best Practices¶
``jail.local`` und ``filter.d/*.local`` verwenden, niemals die
*.conf-Dateien direkt editieren. Bei Paket-Updates werden.conf-Dateien überschrieben,.local-Dateien bleiben stehen.Incremental Bans aktivieren für SSH-exponierte Hosts: in
jail.localunter[DEFAULT]bantime.increment = true,bantime.factor = 2,bantime.maxtime = 604800(eine Woche) setzen. Wiederholungstäter werden so progressiv länger ausgesperrt.``ignoreip`` mit Management-Netzen und dem eigenen Monitoring füttern, damit ein falscher Login durch das Rollout-Tool den Admin nicht selbst aussperrt.
Backend ``systemd`` auf allen RHEL-8+ und Debian-11+ Systemen verwenden - Fail2ban liest dann direkt aus dem Journal, ohne auf rsyslog-Aktualisierungen angewiesen zu sein.
Jail-Status regelmässig prüfen.
fail2ban-client statuszeigt alle aktiven Jails,fail2ban-client status <jail>listet aktuell gebannte IPs. Dasfail2ban-Monitoring-Plugin liefert diese Zahlen nach Icinga.DB auf nicht-Standard-Pfad umlegen, wenn
/var/aus einer tmpfs- oder schnellen SSD-Partition besteht - die SQLite-Datenbank kann unter Last IO-lastig werden.
RHEL/Debian-Unterschiede¶
- Paketquelle
RHEL 8+: Paket liegt im EPEL (
dnf --assumeyes install epel-release; dnf --assumeyes install fail2ban).Debian/Ubuntu: Paket liegt im Main-Repo (
apt-get install fail2ban).
- Default-Backend
RHEL 8+: systemd (Journal). Die
jail.confsetztbackend = systemd.Debian/Ubuntu: je nach Release auto; bei systemd-Systemen entsprechend
systemdoder polling. Bei Bedarf explizit setzen.
- Firewall-Backend
RHEL 8+: firewalld mit
ipsetals Default (banaction = firewallcmd-ipset).Debian/Ubuntu: iptables/nftables (
banaction = iptables-multiportoderbanaction = nftables-multiport). Bei Systemen mit UFW entsprechendbanaction = ufwsetzen.
- SSH-Jail per Default aktiv
RHEL 8+: ja (
[sshd]in derjail.confmitenabled = true).Debian/Ubuntu: ja.
- Logpfad für SSH
RHEL 8+: Journal (automatisch erkannt).
Debian/Ubuntu:
/var/log/auth.log.
Troubleshooting¶
- Filter enabled, IP taucht auch in der iptables-Liste als geblockt auf, aber Zugriff auf z.B. die Webseite ist immer noch möglich?
Greift ein Client beispielsweise auf
meine-ip:9999zu, wird er geblockt. Ruft er danachmeine-ip:443auf, darf er meine Webseite besuchen. Warum? Hat mich einen Tag gekostet, und wie immer sehr logisch: Fail2ban läuft hier auf einem System, welches direkt am Internet hängt und eingehenden Netzwerk NATtet, z.B. auf einen Webserver. Damit wird der Netzverkehr in der PREROUTING-Chain behandelt und an den Webserver durchgeroutet, durchläuft also nicht die Fail2ban-Chains. Ein Testzugriff aufmeine-ip:9998zeigt, dass alles ausserhalb der NAT-Regeln wirklich geblockt wird.- fail2ban-client: ERROR NOK: (‚database disk image is malformed‘)
SQLite-Datenbank in
/var/lib/fail2ban/fail2ban.sqlite3löschen und Fail2ban neu starten.- ERROR: No failure-id group in …
Fehler im Filter: im regulären Ausdruck fehlt die
<HOST>-Angabe.