+39 3662317539/+34 620899163
info@simonecosci.com

fail2ban su un VPS: ban automatici senza restare chiusi fuori

Sviluppo Siti Web a Tenerife

fail2ban su un VPS: ban automatici senza restare chiusi fuori

Un VPS con la porta 22 esposta riceve tentativi di login continuamente. Non è un attacco mirato: sono scanner automatici che provano root, admin, test su interi blocchi di indirizzi. Non entrano, se l’autenticazione è a chiave, ma riempiono i log e rendono illeggibile tutto il resto.

fail2ban serve a questo. Non è un firewall e non è un antivirus: è un programma che legge i log, conta i fallimenti e scrive una regola nel firewall quando un indirizzo supera la soglia. Il file che lo governa, jail.conf, è descritto nel manuale come la “configuration for the fail2ban server” che definisce “combinations of Filters with Actions”: un filtro che riconosce la riga di log, un’azione che la trasforma in un ban.

Quello che segue è verificato sul pacchetto Debian 1.1.0-8, quello di trixie. È importante perché su Debian tre cose funzionano diversamente da come le racconta quasi tutta la documentazione in giro.

Su Debian il jail sshd è già attivo

Il jail.conf che arriva da upstream disattiva tutto. Nella sezione [DEFAULT] c’è enabled = false, e la sezione dell’SSH non ha nessuna riga enabled:

[sshd]
#mode   = normal
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s

Letto così, fail2ban appena installato non fa niente. Ed è esattamente il punto in cui le guide ti dicono di creare un jail.local con [sshd] e enabled = true. Su Debian non serve, perché il pacchetto installa un file suo in /etc/fail2ban/jail.d/defaults-debian.conf, che contiene per intero questo:

[DEFAULT]
banaction = nftables
banaction_allports = nftables[type=allports]

[sshd]
backend = systemd
journalmatch = _SYSTEMD_UNIT=ssh.service + _COMM=sshd
enabled = true

Il README.Debian del pacchetto lo dice in una riga: “Only handling of ssh files is enabled by default”. Da qui scendono tre conseguenze, e sono i tre punti su cui si perde tempo.

Il jail non legge /var/log/auth.log. Legge il journal di systemd, perché Debian imposta backend = systemd con il journalmatch che vedi sopra. Il file paths-debian.conf spiega la scelta: “these services will log to the journal via syslog, so use the journal by default”. Quindi ogni consiglio del tipo “metti logpath = /var/log/auth.log” qui è sbagliato, e il pacchetto dipende da python3-systemd proprio perché quel backend funzioni senza installare nulla.

Il ban non è una regola iptables. Upstream il default è banaction = iptables-multiport; Debian lo sovrascrive con nftables. Se cerchi il ban con iptables -L non trovi niente e concludi che fail2ban non funziona, mentre invece sta funzionando. Il pacchetto dichiara nftables | iptables fra i Recommends, in quest’ordine.

Non devi abilitare niente per l’SSH. Devi solo decidere i numeri.

Dove si mette la configurazione

L’intestazione di jail.conf è esplicita: “YOU SHOULD NOT MODIFY THIS FILE. It will probably be overwritten or improved in a distribution update”, e indica la strada giusta — “Provide customizations in a jail.local file or a jail.d/customisation.local”.

L’ordine di lettura, dal manuale, è questo:

  1. jail.conf
  2. jail.d/*.conf, in ordine alfabetico
  3. jail.local
  4. jail.d/*.local, in ordine alfabetico

con la regola che conta: “Settings in the file parsed later take precedence over identical entries in previously parsed files”. Nota dove cade jail.local: dopo jail.d/*.conf, quindi dopo defaults-debian.conf. Le tue impostazioni in jail.local vincono su quelle del pacchetto, e non devi toccare nessuno dei due file che l’aggiornamento riscriverà.

I tre numeri che contano

Nel [DEFAULT] del file installato ci sono tre righe:

bantime  = 10m
findtime  = 10m
maxretry = 5

Il manuale le definisce così: bantime è la “effective ban duration (in seconds or time abbreviation format)”, findtime il “time interval (in seconds or time abbreviation format) before the current time where failures will count towards a ban”, maxretry il “number of failures that have to occur in the last findtime seconds to ban the IP”.

Tradotto: cinque fallimenti in dieci minuti, e l’indirizzo resta fuori per dieci minuti. È una soglia prudente, pensata per non fare danni.

Attenzione al formato del tempo, che è una trappola vera: nel formato abbreviato m e mm indicano i minuti, i mesi si scrivono mo o mon. Un bantime = 1m non è un mese di ban, è un minuto. Se hai un dubbio, il client lo calcola per te: fail2ban-client --str2sec 1d12h.

Nel file installato esistono anche le righe del ban progressivo, ma sono commentate — cioè non attive:

#bantime.increment = true
#bantime.multipliers = 1 2 4 8 16 32 64

Vale la pena saperlo prima di dare per scontato che il ban si allunghi da solo a ogni recidiva: di default non lo fa.

Non bannare te stesso

Questa è la parte da sistemare per prima, perché l’errore si paga subito. Nel file installato la riga degli indirizzi esentati è commentata:

#ignoreip = 127.0.0.1/8 ::1

Quello che è attivo è un altro meccanismo, ignoreself, che il manuale descrive come “boolean value (default true) indicates the banning of own IP addresses should be prevented”. Leggi bene: own IP addresses, gli indirizzi del server. Protegge la macchina dal bannare se stessa, non protegge te. Il tuo indirizzo di casa o dell’ufficio non c’entra niente con ignoreself.

Se vuoi un’esenzione, va scritta, in jail.local:

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 198.51.100.7

ignoreip è la “list of IPs not to ban. They can include a DNS resp. CIDR mask too”. Con un’avvertenza da tenere presente: se la tua connessione ha un IP dinamico, quell’esenzione scade senza preavviso il giorno in cui il provider te lo cambia. Non è una rete di sicurezza. La rete di sicurezza vera è la console di emergenza del pannello del tuo provider, che passa fuori dalla rete e quindi fuori dal firewall: verifica che funzioni prima di toccare le regole, non dopo.

Il comando di unban, da imparare adesso

Questo è il motivo per cui conviene leggere questo paragrafo oggi e non quando ti serve. fail2ban-client è il programma per “configure and control the server”, e i comandi che contano sono quattro.

Per vedere cosa sta facendo:

fail2ban-client status
fail2ban-client status sshd

Il primo “gets the current status of the server”, il secondo “gets the current status of , with optional flavor or extended info”. Esiste anche status --all [FLAVOR], che fa la stessa cosa su tutti i jail.

Per liberare un indirizzo:

fail2ban-client unban 198.51.100.7
fail2ban-client set sshd unbanip 198.51.100.7

Il primo “unbans (in all jails and database)” — in tutti i jail e nel database, che è quasi sempre quello che vuoi. Il secondo agisce su un jail solo. E se hai fatto un disastro completo c’è unban --all, che “unbans all IP addresses (in all jails and database)”.

Per rileggere la configurazione senza fermare il servizio c’è reload, documentato con la sua opzione più brusca: “reloads the configuration without restarting of the server, the option ‘–restart’ activates completely restarting of affected jails, thereby can unban IP addresses (if option ‘–unban’ specified)”.

Cosa fail2ban non è

Non è un’alternativa all’autenticazione a chiave, e presentarlo così è il modo più rapido per prendere una decisione sbagliata. La soglia di maxretry vale per indirizzo: una botnet con diecimila IP diversi ha diecimila volte cinque tentativi, e ogni singolo indirizzo resta sotto la soglia senza sforzo. Contro quello non ti difende il conteggio dei fallimenti, ti difende il fatto che non ci sia una password da indovinare — PasswordAuthentication no nella configurazione di SSH.

Quello che fail2ban fa davvero, e che vale comunque la fatica di configurarlo, è ridurre il rumore: meno righe nei log, meno banda consumata, meno carico sul demone SSH, e soprattutto log in cui un tentativo anomalo si vede ancora perché non è sepolto sotto diecimila tentativi banali. È un filtro, non una porta blindata. La porta blindata è la chiave.


Se gestisci un VPS e non sei sicuro di come sia configurato — quali porte sono aperte, se gli aggiornamenti di sicurezza entrano da soli, se esiste un modo di rientrare quando qualcosa va storto — possiamo guardarlo insieme. Scrivici.