Fail2Ban - Un cane da guardia per NGINX
Fail2Ban è un software che utilizza iptables per bloccare automaticamente i client che continuano a fallire i tentativi di accesso, che provano a sfruttare vulnerabilità dei servizi web, e molto altro. Vediamo insieme come implementarlo sulla nostra infrastruttura.
Introduzione
Nelle guide precedenti abbiamo visto come implementare NGINX per svolgere varie funzioni, come:
Ma nell'articolo di introduzione ad NGINX, ho specificato che un software di questo tipo ci permette anche di aumentare notevolmente la sicurezza dell'infrastruttura.
Come può farlo, di preciso?
Innanzitutto, facendo passare tutto il traffico da NGINX è possibile approfittare di questo accentramento per concentrare sui nodi NGINX tutte le configurazioni di sicurezza a livello di firewall e regole di ispezione del traffico.
In questa guida, vedremo come implementare una soluzione open source che utilizza il firewall iptables e criteri di lettura dei log per rilevare e bloccare i tentativi di intrusione: Fail2Ban
Installazione
(testato su Ubuntu Server 24.04)
Fail2Ban si installa con pochi e semplici comandi, vediamoli insieme.
Installate fail2ban ed iptables
sudo apt install fail2ban iptablesControllate lo stato del servizio di fail2ban
fail2ban-client statusCreate il file jail.local partendo dal file di template jail.conf
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.localCon questo si conclude lo step di installazione.
Andiamo ora a vedere come configurare Fail2Ban per abilitare le regole che ci servono e personalizzarne il comportamento.
Configurazione
Come funziona la configurazione
- Il file di configurazione che abbiamo appena creato (jail.local) contiene una lista di regole che Fail2Ban applicherà leggendo i file di log che andremo ad indicare al suo interno.
- Ogni regola che andremo a creare diverrà una jail (dall'inglese, prigione). Un client che soddisfa i requisiti indicati nella jail (ad esempio, 3 tentativi di accesso non riusciti) verrà messo nella jail corrispondente a quella regola.
- Dentro ad ogni regola è anche specificata una lista di azioni da intraprendere. Dal più banale "blocca questo client sul firewall" ad "invia una notifica telegram", è possibile indicare varie azioni da far compiere a Fail2Ban
- Un client che viene spedito in prigione, verrà bloccato esclusivamente utilizzando le regole specificate in quella jail (ad esempio, se ho una regola per SSH ed una per un server web, ed un client sbaglia l'autenticazione SSH, potrà comunque utilizzare il server web)
Creare delle eccezioni
Prima di andare avanti con la configurazione, è il caso di censire alcune eccezioni su Fail2Ban per evitare di bloccarci da soli durante i nostri test.
Modificate il file jail.local
nano /etc/fail2ban/jail.local Andate alla riga del parametro ignoreip ed aggiungete le subnet e/o gli indirizzi che Fail2Ban non deve mai bannare
Per esempio, per ignorare 192.168.120.1 e tutta la rete 192.168.0.0:
ignoreip = 192.168.0.0/24,192.168.120.1Creare una regola per l'autenticazione SSH
In questo esempio diremo a Fail2Ban di bloccare per 4 ore tutti i client che sbagliano 3 volte la password di SSH nell'arco di 30 secondi.
Modifichiamo il file jail.local
nano /etc/fail2ban/jail.local Impostiamo la sezione [sshd] relativa ad SSH come segue:
[sshd]
enabled = true
filter = sshd
maxretry = 3
port = ssh
backend = systemd
findtime = 30
bantime = 4h- enabled → indica se la jail è attiva o meno
- filter → fa riferimento al filtro presente in /etc/fail2ban/filter.d/ relativo ad sshd. Questo file contiene informazioni relative a come interpretare i file di log di sshd
- maxretry → il numero massimo di tentativi errati, in questo caso relativi all'autenticazione tramite SSH
- port → la porta da usare per la regola di firewall, che viene creata nel caso in cui un client debba essere bloccato. Indicando ssh come in questo esempio, verrà usata la porta di default di SSH (22)
- backend → indica che per leggere i log di sshd, Fail2Ban dovrà utilizzare systemd (perchè sshd è un servizio di systemd)
- findtime → il tempo massimo (in questo caso, essendo senza unità di misura è in secondi) che deve passare tra i tentativi massimi (in questo caso 3) affinchè la regola sia soddisfatta
- bantime → dopo quante ore cancellare il blocco sul firewall per ciascun client che viene bannato
Come avrete notato, in questo esempio non è specificata alcuna azione da intraprendere alla soddisfazione della regola. Quando non specificata, l'azione che viene intrapresa è quella indicata al parametro action_ nel file jail.local, sotto alla sezione [DEFAULT]
Di default, questa azione crea una regola su iptables che rifiuta le connessioni del client da bloccare, sulla porta indicata nella regola.
Ora che abbiamo configurato la nostra prima regola, riavviamo il servizio di fail2ban per testarne il funzionamento
sudo systemctl restart fail2ban.service
systemctl status fail2ban.serviceProvate, da un client che non sia stato configurato nel parametro ignoreip, ad autenticarvi tramite SSH alla macchina sbagliando la password più volte. Dopo tre tentativi, dovreste perdere la connessione.
Potete monitorare il funzionamento in due modi:
- Leggendo in diretta il log di Fail2Ban
tail -f /var/log/fail2ban.log- Controllando lo status della Jail sshd
fail2ban-client status sshd
Dato che si tratta di un test, potete ora sbannare manualmente il vostro client
sudo fail2ban-client set %nomejail% unbanip %indirizzoIP%Creare una regola per NGINX
Se state usando NGINX come reverse Proxy, può esservi molto utile configurare alcune jail relative ad NGINX. In questo esempio ne configureremo due:
- nginx-http-auth che monitora i vostri webserver in reverse proxy che espongono autenticazione http, e ci permetterà di bannare i client che falliscono l'autenticazione troppe volte
- nginx-bad-clients (che andremo ad importare in quanto regola personalizzata) che blocca gran parte dei bot che cercano di rilevare le vulnerabilità dei vostri servizi web
Prima di tutto, modifichiamo il file jail.local
nano /etc/fail2ban/jail.local Impostiamo la regola [nginx-http-auth]
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.logPoi creiamo la regola [nginx-bad-clients] (vi consiglio di farlo vicino alle altre regole relative ad NGINX, per comodità)
[nginx-bad-clients]
port = http,https
filter = nginx-bad-clients
logpath = /var/log/nginx/*access.log
maxretry = 3
findtime = 30s
bantime = 4h
enabled = trueNotate come il valore di logpath sia diverso per le due regole. Questo perchè:
- nginx-http-auth controlla esclusivamente i tentativi di accesso falliti, che vengono loggati in error.log
- nginx-bad-clients controlla invece i comportamenti dei client che accedono (anche se con successo) a vari path dei vostri servizi web usando dei pattern sospetti
nginx-bad-clients quini agisce anche quando il client non sta facendo di per sé qualcosa di sbagliato, ma sta palesemente curiosando in giro
Come ho specificato poco fa, il filtro nginx-bad-clients in realtà non esiste di default su Fail2Ban, perché si tratta di un filtro custom. Andiamo a crearlo
Create il filtro nginx-bad-clients
nano /etc/fail2ban/filter.d/nginx-bad-clients.localIncollate il seguente contenuto
# Fail2Ban filter to match web requests for misbehaving clients
#
[INCLUDES]
# Load regexes for filtering
before = botsearch-common.conf
[Definition]
failregex = ^<HOST> - \S+ \[\] "[^"]*" 429 .+$
^<HOST> - \S+ \[\] "[^"]*" 404 .+$
ignoreregex =
datepattern = {^LN-BEG}%%ExY(?P<_sep>[-/.])%%m(?P=_sep)%%d[T ]%%H:%%M:%%S(?:[.,]%%f)?(?:\s*%%z)?
^[^\[]*\[({DATE})
{^LN-BEG}
# DEV Notes:
# Based on nginx-botsearch filter
#
# Author: Dan LangilleUna volta salvato, riavviate fail2ban e controllate che non abbia segnalato errori
sudo systemctl restart fail2ban.service
systemctl status fail2ban.serviceCome indicato per sshd, potete controllare lo stato di fail2ban e delle nostre nuove jail tramite i seguenti comandi:
- Leggendo in diretta il log di Fail2Ban
tail -f /var/log/fail2ban.log- Controllando lo status della Jail nginx-bad-clients e nginx-http-auth
fail2ban-client status nginx-bad-clients
fail2ban-client status nginx-http-authCome inviare notifiche Telegram
Nell'introduzione alla configurazione, ho menzionato la possibilità di inviare notifiche Telegram quando Fail2Ban banna (o sbanna) un client.
Integrazioni come questa, e molte altre, sono possibili grazie al grado di personalizzazione che Fail2Ban ci offre.
In questo esempio, vediamo come configurare l'invio notifiche tramite Telegram.
Prima di tutto, creiamo la cartella /etc/failban/scripts dove tenere questo ed i nostri altri script personalizzati
sudo mkdir /etc/fail2ban/scriptsCreare il file /etc/fail2ban/scripts/fail2ban-telegram.sh col seguente contenuto (modificando il bot token ed i chat id):
sudo nano /etc/fail2ban/scripts/fail2ban-telegram.sh#!/bin/bash
# Sends text messages using Telegram
# to alert webmaster of banning.
# Require one argument, one of the following
# start
# stop
# ban
# unban
# Optional second argument: Ip for ban/unband
# Display usage information
function show_usage {
echo "Usage: $0 action <ip>"
echo "Where action start, stop, ban, unban"
echo "and IP is optional passed to ban, unban"
exit
}
# Send notification
function send_msg {
apiToken=<bottoken>
chatId=<chatid>
url="https://api.telegram.org/bot$apiToken/sendMessage"
curl -s -X POST $url -d chat_id=$chatId -d text="$1"
exit
}
# Check for script arguments
if [ $# -lt 1 ]
then
show_usage
fi
# Take action depending on argument
if [ "$1" = 'start' ]
then
msg='Fail2ban+just+started.'
send_msg $msg
elif [ "$1" = 'stop' ]
then
msg='Fail2ban+just+stopped.'
send_msg $msg
elif [ "$1" = 'ban' ]
then
msg=$([ "$2" != '' ] && echo "Fail2ban+just+banned+$2+on+service+$3." || echo 'Fail2ban+just+banned+an+ip+on+service+$3.' )
send_msg $msg
elif [ "$1" = 'unban' ]
then
msg=$([ "$2" != '' ] && echo "Fail2ban+just+unbanned+$2+on+service+$3." || echo "Fail2ban+just+unbanned+an+ip+on+service+$3." )
send_msg $msg
else
show_usage
fiCreare il file /etc/fail2ban/action.d/telegram.conf col seguente contenuto:
sudo nano /etc/fail2ban/action.d/telegram.conf# Fail2Ban configuration file
#
# Author: MushaGH
#
#
[Definition]
# Option: actionstart
# Notes.: command executed once at the start of Fail2Ban.
# Values: CMD
#
actionstart = /etc/fail2ban/scripts/fail2ban-telegram.sh start
# Option: actionstop
# Notes.: command executed once at the end of Fail2Ban
# Values: CMD
#
actionstop = /etc/fail2ban/scripts/fail2ban-telegram.sh stop
# Option: actioncheck
# Notes.: command executed once before each actionban command
# Values: CMD
#
actioncheck =
# Option: actionban
# Notes.: command executed when banning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: See jail.conf(5) man page
# Values: CMD
#
actionban = /etc/fail2ban/scripts/fail2ban-telegram.sh ban <ip> <name>
# Option: actionunban
# Notes.: command executed when unbanning an IP. Take care that the
# command is executed with Fail2Ban user rights.
# Tags: See jail.conf(5) man page
# Values: CMD
#
actionunban = /etc/fail2ban/scripts/fail2ban-telegram.sh unban <ip> <name>
[Init]
init = 123Riavviare Fail2Ban e controllare che non dia errore relativo al modulo telegram
sudo systemctl restart fail2ban.service
systemctl status fail2ban.serviceSe non viene segnalato alcun errore, possiamo implementare l'azione "telegram" sulle nostre jail
Modifichiamo il file jail.local
sudo nano /etc/fail2ban/jail.localEd aggiungiamo a tutte le jail dove vogliamo abilitare le notifiche telegram il parametro action
action = iptables[name=SSH,port=22,protocol=tcp]
telegramIn questo esempio, la action è relativa alla jail sshd. Dobbiamo specificare una azione per riga:
- iptables[name,port,protocol] crea una regola firewall su iptables che blocca tutte le comunicazioni sulla porta 22 TCP per l'IP del client da bannare
- telegram invece invia una notifica telegram usando i parametri impostati in precedenza
Ripetete questa configurazione su tutte le jail dove abilitare le notifiche Telegram, modificando name, port e protocol a seconda del servizio in questione
Riavviate infine Fail2Ban e controllate che non ci siano errori segnalati
sudo systemctl restart fail2ban.service
systemctl status fail2ban.serviceAdesso quando un client viene bannato, riceverete anche una notifica su Telegram!
