Introduzione
SSH è il metodo predefinito per connettersi a un server cloud. È affidabile e estensibile: nuovi standard di crittografia possono essere utilizzati per generare nuove chiavi SSH, garantendo che il protocollo principale rimanga sicuro. Tuttavia, nessun protocollo o stack software è totalmente infallibile, e il fatto che SSH sia così ampiamente diffuso su Internet significa che rappresenta una superficie di attacco molto prevedibile o un vettore di attacco attraverso cui le persone possono cercare di ottenere accesso.
Ogni servizio esposto alla rete è un potenziale obiettivo in questo modo. Se si controllano i log del proprio servizio SSH in esecuzione su un server molto frequentato, si vedranno spesso tentativi di accesso ripetuti e sistematici che rappresentano attacchi di forza bruta da parte di utenti e bot. Anche se è possibile apportare alcune ottimizzazioni al proprio servizio SSH per ridurre al minimo la possibilità che questi attacchi abbiano successo, come disabilitare l’autenticazione tramite password a favore delle chiavi SSH, possono comunque rappresentare una piccola responsabilità continua.
Le distribuzioni di produzione su larga scala per le quali questa responsabilità è completamente inaccettabile di solito implementeranno una VPN come WireGuard di fronte al loro servizio SSH, in modo che sia impossibile connettersi direttamente alla porta SSH predefinita 22 dall’esterno senza un’astrazione software aggiuntiva o gateway. Queste soluzioni VPN sono ampiamente affidabili, ma aggiungeranno complessità e potrebbero interrompere alcune automazioni o altri piccoli hook software.
Prima di impegnarti in una configurazione VPN completa o in aggiunta ad essa, puoi implementare uno strumento chiamato Fail2ban. Fail2ban può mitigare significativamente gli attacchi brute force creando regole che modificano automaticamente la configurazione del firewall per bandire specifici indirizzi IP dopo un certo numero di tentativi di accesso non riusciti. Ciò permetterà al tuo server di proteggersi da questi tentativi di accesso senza interventi da parte tua.
In un altro tutorial, abbiamo discusso Come proteggere SSH con Fail2ban. In questa guida, approfondiremo come funziona effettivamente Fail2ban e come puoi utilizzare questa conoscenza per modificare o estendere il comportamento di questo servizio.
I Fondamenti di Fail2ban
Lo scopo di Fail2ban è monitorare i log dei servizi comuni per individuare pattern nelle autenticazioni fallite.
Quando fail2ban è configurato per monitorare i log di un servizio, guarda a un filtro che è stato configurato specificamente per quel servizio. Il filtro è progettato per identificare i fallimenti dell’autenticazione per quel servizio specifico attraverso l’uso di espressioni regolari complesse. Le espressioni regolari sono un linguaggio di templating comune usato per il riconoscimento dei pattern. Esso definisce questi modelli di espressioni regolari in una variabile interna chiamata failregex
.
Di default, Fail2ban include file di filtro per servizi comuni. Quando un log di qualsiasi servizio, come un server web, corrisponde al failregex
nel suo filtro, viene eseguita un’azione predefinita per quel servizio. L’azione
è una variabile che può essere configurata per fare molte cose diverse, a seconda delle preferenze dell’amministratore.
L’azione predefinita è quella di bloccare l’host/indirizzo IP offensivo modificando le regole del firewall locale. È possibile estendere questa azione, ad esempio, per inviare un’email all’amministratore di sistema.
Di default, l’azione verrà intrapresa quando saranno stati rilevati tre fallimenti di autenticazione in 10 minuti, e il tempo di blocco predefinito è di 10 minuti. Questo è configurabile.
Quando si utilizza il firewall iptables
predefinito, fail2ban
crea un nuovo set di regole del firewall, chiamato anche catena, quando il servizio viene avviato. Aggiunge una nuova regola alla catena INPUT che invia tutto il traffico TCP diretto alla porta 22 alla nuova catena. Nella nuova catena, inserisce una singola regola che torna alla catena INPUT. La catena e le regole associate vengono rimosse se il servizio Fail2ban viene interrotto.
Esplorare le impostazioni del servizio Fail2ban
Fail2ban è configurato attraverso diversi file situati in una gerarchia sotto la directory /etc/fail2ban/
.
Il file fail2ban.conf
configura alcune impostazioni operative come il modo in cui il demone registra le informazioni e il file socket e PID che utilizzerà. La configurazione principale, tuttavia, è specificata nei file che definiscono i “jails” per singole applicazioni.
Per impostazione predefinita, fail2ban viene fornito con un file jail.conf
. Tuttavia, questo può essere sovrascritto negli aggiornamenti, quindi è consigliabile copiare questo file in un file jail.local
e apportare le modifiche necessarie.
Se si dispone già di un file jail.local
, aprirlo utilizzando nano
o il proprio editor di testo preferito:
Se non si dispone già di un file jail.local
, o se il file aperto era vuoto, copiare il file jail.conf
e quindi aprire il nuovo file:
Esamineremo le opzioni disponibili qui e vedremo come questo file interagisce con altri file di configurazione nel sistema.
La Sezione Predefinita
La prima parte del file definirà le impostazioni predefinite per la politica di fail2ban. Queste opzioni possono essere sovrascritte nella sezione di configurazione di ciascun servizio individuale.
Con i commenti rimossi, l’intera sezione predefinita appare così:
[DEFAULT]
ignoreip = 127.0.0.1/8
bantime = 10m
findtime = 10m
maxretry = 3
backend = auto
usedns = warn
destemail = root@localhost
sendername = Fail2Ban
banaction = iptables-multiport
mta = sendmail
protocol = tcp
chain = INPUT
action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s", sendername="%(sendername)s"]
action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
%(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s", sendername="%(sendername)s"]
action = %(action_)s
Esaminiamo cosa significa alcune di queste opzioni:
- ignoreip: Questo parametro identifica gli indirizzi IP che devono essere ignorati dal sistema di ban. Per impostazione predefinita, è impostato solo per ignorare il traffico proveniente dalla stessa macchina, in modo da non riempire i propri log o bloccarsi.
- bantime: Questo parametro imposta la durata di un ban, in secondi. Il valore predefinito è di 10 minuti.
- findtime: Questo parametro imposta la finestra che Fail2ban prenderà in considerazione quando cerca tentativi di autenticazione falliti ripetuti. Il valore predefinito è impostato su 10 minuti, il che significa che il software conterà il numero di tentativi falliti negli ultimi 10 minuti.
- maxretry: Questo imposta il numero di tentativi falliti che saranno tollerati all’interno della finestra
findtime
prima che venga istituito un ban. - backend: Questa voce specifica come Fail2ban monitorerà i file di log. L’impostazione di
auto
significa che fail2ban cercheràpyinotify
, quindigamin
, e quindi un algoritmo di polling basato su ciò che è disponibile.inotify
è una funzione integrata nel kernel Linux per il tracciamento dell’accesso ai file, epyinotify
è un’interfaccia Python perinotify
, utilizzata da Fail2ban. - usedns: Questo definisce se viene utilizzato il reverse DNS per aiutare a implementare i blocchi. Impostando questo su “no” verranno bloccati gli IP stessi invece dei loro nomi host di dominio. L’impostazione
warn
cercherà di cercare un nome host e di bloccarlo in questo modo, ma registrerà l’attività per la revisione. - destemail: Questo è l’indirizzo a cui verrà inviata la mail di notifica se si configura l’azione per inviare avvisi via mail.
- sendername: Questo sarà utilizzato nel campo email come mittente per le email di notifica generate.
- banaction: Questo imposta l’azione che verrà utilizzata quando viene raggiunto il limite. In realtà si tratta di un percorso verso un file situato in
/etc/fail2ban/action.d/
chiamatoiptables-multiport.conf
. Questo gestisce effettivamente la manipolazione del firewalliptables
per bloccare un indirizzo IP. Ne parleremo più avanti. - mta: Questo è l’agente di trasferimento di posta che verrà utilizzato per inviare le email di notifica.
- protocollo: Questo è il tipo di traffico che verrà bloccato quando viene implementato un blocco IP. Questo è anche il tipo di traffico inviato alla nuova catena iptables.
- chain: Questa è la catena che verrà configurata con una regola di salto per inviare il traffico al imbuto fail2ban.
Il resto dei parametri definisce azioni diverse che possono essere specificate. Passano alcuni dei parametri che abbiamo definito sopra utilizzando la sostituzione di variabili all’interno di stringhe di testo come questo:
%(nome_variabile)s
La riga sopra sarebbe sostituita con il contenuto di var_name
. Utilizzando questo, possiamo dire che la variabile action
è impostata per impostazione predefinita alla definizione action_
(solo ban, nessun avviso via email).
Questo, a sua volta, è configurato chiamando l’azione iptables-multiport
con un elenco di parametri (nome del servizio, porta, protocollo e catena) che è necessario per eseguire il ban. Il __name__
è sostituito con il nome del servizio specificato dalle intestazioni di sezione di seguito.
Sezioni Specifiche del Servizio
Sotto la sezione predefinita, ci sono sezioni per servizi specifici che possono essere utilizzate per sovrascrivere le impostazioni predefinite. Questo segue una convenzione di modificare solo i parametri che differiscono dai valori normali (convenzione su configurazione).
Ogni intestazione di sezione è specificata in questo modo:
[nome_servizio]
Qualsiasi sezione che abbia la riga enabled = true
verrà letta e abilitata.
All’interno di ciascuna sezione, i parametri vengono configurati, incluso il file di filtro che dovrebbe essere utilizzato per analizzare i log (senza l’estensione del file) e la posizione dei file di log stessi.
Tenendo presente ciò, la sezione che specifica le azioni per il servizio SSH appare così:
[SSH]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 6
Questo abilita questa sezione e imposta la porta al porto predefinito “ssh” (porta 22). Dice a Fail2ban di guardare il registro situato in /var/log/auth.log
per questa sezione e di analizzare il registro utilizzando i meccanismi di filtraggio definiti nella directory /etc/fail2ban/filters.d
in un file chiamato sshd.conf
.
Tutte le altre informazioni di cui ha bisogno sono prese dai parametri definiti nella sezione [DEFAULT]
. Ad esempio, l’azione sarà impostata su action_
che bloccherà l’indirizzo IP offensivo utilizzando l’azione di blocco iptables-multiport
, che fa riferimento a un file chiamato iptables-multiport.conf
trovato in /etc/fail2ban/action.d
.
Come puoi vedere, le azioni nella sezione [DEFAULT]
dovrebbero essere generali e flessibili. Utilizzando la sostituzione dei parametri insieme a parametri che forniscono valori predefiniti sensati, sarà possibile sovrascrivere le definizioni quando necessario.
Esaminare il File di Filtro
Per capire cosa sta succedendo nella nostra configurazione, è necessario comprendere i file di filtro e azione, che fanno la maggior parte del lavoro.
Il file di filtro determinerà le righe che fail2ban cercherà nei file di registro per identificare le caratteristiche offensive. Il file di azione implementa tutte le azioni richieste, dalla costruzione di una struttura del firewall quando il servizio si avvia, all’aggiunta e alla rimozione delle regole e alla demolizione della struttura del firewall quando il servizio si ferma.
Esaminiamo il file di filtro richiesto dal nostro servizio SSH nella configurazione sopra:
[INCLUDES]
before = common.conf
[Definition]
_daemon = sshd
failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error) for .* from <HOST>( via \S+)?\s*$
^%(__prefix_line)s(?:error: PAM: )?User not known to the underlying authentication module for .* from <HOST>\s*$
^%(__prefix_line)sFailed \S+ for .*? from <HOST>(?: port \d*)?(?: ssh\d*)?(: (ruser .*|(\S+ ID \S+ \(serial \d+\) CA )?\S+ %(__md5hex)s(, client user ".*", client host ".*")?))?\s*$
^%(__prefix_line)sROOT LOGIN REFUSED.* FROM <HOST>\s*$
^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from <HOST>\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because not listed in AllowUsers\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because listed in DenyUsers\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because not in any group\s*$
^%(__prefix_line)srefused connect from \S+ \(<HOST>\)\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because a group is listed in DenyGroups\s*$
^%(__prefix_line)sUser .+ from <HOST> not allowed because none of user's groups are listed in AllowGroups\s*$
ignoreregex =
La sezione intestazione [INCLUDES]
specifica altri file di filtro che vengono letti prima o dopo questo file. Nel nostro esempio, il file common.conf
viene letto e inserito prima delle altre righe in questo file. Questo imposta alcuni parametri che utilizzeremo nella nostra configurazione.
Successivamente, abbiamo una sezione [Definition]
che definisce le regole effettive per i match del nostro filtro. Prima, impostiamo il nome del demone che stiamo monitorando utilizzando il parametro _daemon
.
Dopo di ciò, passiamo alla definizione effettiva di failregex
, che imposta i pattern che verranno attivati quando viene trovata una riga corrispondente nel file di registro. Queste sono espressioni regolari che corrispondono in base ai diversi errori e fallimenti che possono essere generati quando un utente non si autentica correttamente.
Parti della riga come %(__prefix_line)s
verranno sostituite con il valore di un parametro impostato nel file common.conf
che abbiamo incluso. Questo viene utilizzato per corrispondere alle diverse informazioni iniziali che i sistemi operativi scrivono nei file di registro quando utilizzano metodi standard. Ad esempio, alcune righe da /var/log/auth.log
potrebbero apparire così:
May 6 18:18:52 localhost sshd[3534]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=101.79.130.213
May 6 18:18:54 localhost sshd[3534]: Failed password for invalid user phil from 101.79.130.213 port 38354 ssh2
May 6 18:18:54 localhost sshd[3534]: Received disconnect from 101.79.130.213: 11: Bye Bye [preauth]
La parte evidenziata è uno schema standard che il sistema operativo inserisce per fornire ulteriori dettagli. Dopo di ciò, ci sono diversi modi in cui il servizio firewall iptables scrive i tentativi di fallimento nel registro.
Vediamo due fallimenti separati nelle prime due righe sopra (un errore di autenticazione PAM e un errore di password). Le espressioni regolari definite nel filtro sono progettate per corrispondere a qualsiasi delle possibili righe di fallimento. Non dovresti modificare nessuna di queste righe, ma dovresti essere consapevole della necessità di catturare tutte le voci del registro che indicano un errore di utilizzo non autorizzato per l’applicazione che stai cercando di proteggere se mai dovessi creare un file di filtro tu stesso.
In fondo, puoi vedere un parametro ignoreregex
, attualmente vuoto. Questo può essere usato per escludere pattern più specifici che corrisponderebbero tipicamente a una condizione di fallimento nel caso tu voglia negare il trigger di fallimento per fail2ban per determinati scenari. Non lo modificheremo.
Salva e chiudi il file quando hai finito di esaminarlo.
Esaminare il File di Azione
Ora, diamo un’occhiata al file di azione. Questo file è responsabile per impostare il firewall con una struttura che consente modifiche per bannare host malintenzionati e per aggiungere e rimuovere quegli host secondo necessità.
L’azione che il nostro servizio SSH richiama si chiama iptables-multiport
. Apri il file associato ora:
Con i commenti rimossi, questo file assomiglia a qualcosa del genere:
[INCLUDES]
before = iptables-blocktype.conf
[Definition]
actionstart = iptables -N fail2ban-<name>
iptables -A fail2ban-<name> -j RETURN
iptables -I <chain> -p <protocol> -m multiport --dports <port> -j fail2ban-<name>
actionstop = iptables -D <chain> -p <protocol> -m multiport --dports <port> -j fail2ban-<name>
actioncheck = iptables -n -L <chain> | grep -a 'fail2ban-<name>[ \t]'
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j <blocktype>
actionunban = iptables -D fail2ban-<name> -s <ip> -j <blocktype>
[Init]
name = default
port = ssh
protocol = tcp
chain = INPUT
Il file inizia importando un altro file di azione chiamato iptables-blocktype.conf
che definisce il parametro blocktype
, il quale configura la restrizione che verrà impostata quando un client viene bandito. Per default, il blocktype
è impostato per rifiutare i pacchetti e rispondere ai ping inviati dai client banditi con un messaggio di rifiuto che la porta è irraggiungibile. Utilizzeremo questo nelle nostre regole di bandiera di seguito.
Successivamente, arriviamo alle definizioni delle regole stesse. L’azione actionstart
configura il firewall iptables quando il servizio fail2ban viene avviato. Crea una nuova catena, aggiunge una regola a tale catena per tornare alla catena chiamante e quindi inserisce una regola all’inizio della catena INPUT che passa il traffico corrispondente ai protocolli e alle destinazioni delle porte corrette alla nuova catena.
Lo fa utilizzando i valori che abbiamo passato con l’azione che abbiamo definito nel nostro file jail.local
. Il name
è preso dall’intestazione di sezione per ciascun servizio. La chain
, il protocol
e la port
sono presi dalla linea di action
stessa in quel file.
Qui, tutti i parametri impostati dall’altro file vengono referenziati includendo il nome del parametro tra parentesi angolari:
<nome_parametro>
Quando scendiamo alla definizione di actionstop
correlata, possiamo vedere che i comandi del firewall stanno implementando un’inversione dei comandi di actionstart
. Quando il servizio Fail2ban si interrompe, rimuove pulitamente tutte le regole del firewall che ha aggiunto.
Un’altra azione chiamata actioncheck
si assicura che la catena corretta sia stata creata prima di tentare di aggiungere regole di blocco.
Successivamente, passiamo alla regola effettiva di blocco, chiamata actionban
. Questa regola funziona aggiungendo una nuova regola alla catena che abbiamo creato. La regola corrisponde all’indirizzo IP sorgente del client offensivo – questo parametro viene letto dai log di autorizzazione quando il limite maxretry
viene raggiunto. Questo istituisce il blocco definito dal parametro blocktype
che abbiamo ottenuto nella sezione [INCLUDE]
in cima al file.
La regola actionunban
rimuove questa regola. Questo viene fatto automaticamente da fail2ban quando il tempo di blocco è scaduto.
Infine, arriviamo alla sezione [Init]
. Questo fornisce solo alcuni valori predefiniti nel caso in cui il file di azione venga chiamato senza passare tutti i valori appropriati.
Come il Servizio Fail2ban Elabora i File di Configurazione per Implementare i Blocchi
Ora che abbiamo visto i dettagli, passiamo al processo che avviene quando fail2ban viene avviato.
Caricamento dei file di configurazione iniziali
Prima, viene letto il file principale fail2ban.conf
per determinare le condizioni in cui il processo principale dovrebbe operare. Crea il socket, i file pid e di log se necessario e inizia a utilizzarli.
Successivamente, fail2ban legge il file jail.conf
per i dettagli di configurazione. Prosegue leggendo, in ordine alfabetico, eventuali file trovati nella directory jail.d
che terminano con .conf
. Aggiunge le impostazioni trovate in questi file alla sua configurazione interna, dando la preferenza ai nuovi valori rispetto ai valori descritti nel file jail.conf
.
Quindi cerca un file jail.local
e ripete questo processo, adattando i nuovi valori. Infine, ricerca nuovamente nella directory jail.d
, leggendo in ordine alfabetico i file che terminano con .local
.
Nel nostro caso, abbiamo solo un file jail.conf
e un file jail.local
. Nel nostro file jail.local
, dobbiamo solo definire i valori che differiscono dal file jail.conf
. Il processo fail2ban ha ora un insieme di direttive caricate in memoria che rappresentano una combinazione di tutti i file che ha trovato.
Esamina ogni sezione e cerca una direttiva enabled = true
. Se ne trova una, utilizza i parametri definiti in quella sezione per creare una policy e decidere quali azioni sono necessarie. Qualsiasi parametro non trovato nella sezione del servizio utilizza i parametri definiti nella sezione [DEFAULT]
.
Parsing dei file di azione per determinare le azioni di avvio
Fail2ban cerca una direttiva action
per capire quale script di azione chiamare per implementare le politiche di ban/unban. Se non ne trova uno, ricorre all’azione predefinita determinata in precedenza.
La direttiva action consiste nel nome del/i file di azione che verranno letti, oltre a un dizionario chiave-valore che passa i parametri necessari a quei file. I valori di questi spesso assumono la forma di sostituzioni di parametri facendo riferimento alle impostazioni configurate nella sezione del servizio. La chiave “nome” di solito riceve il valore della variabile speciale __name__
che sarà impostata sul valore dell’intestazione della sezione.
Fail2ban quindi utilizza queste informazioni per trovare i file associati nella directory action.d
. Prima cerca il file di azione associato che termina in .conf
e poi modifica le informazioni trovate lì con eventuali impostazioni contenute in un file .local
accompagnatorio trovato anch’esso nella directory action.d
.
Analizza quei file per determinare le azioni che deve compiere. Legge il valore actionstart
per vedere le azioni che dovrebbe intraprendere per configurare l’ambiente. Questo include spesso la creazione di una struttura del firewall per ospitare regole di blocco in futuro.
Le azioni definite in questo file utilizzano i parametri passati ad esse dalla direttiva action
. Utilizzerà questi valori per creare dinamicamente le regole appropriate. Se una determinata variabile non è stata impostata, può guardare ai valori predefiniti impostati nel file di azione per riempire gli spazi vuoti.
Analisi dei File di Filtro per Determinare le Regole di Filtraggio
I parametri per il servizio nei file jail.*
includono anche la posizione del file di log e il meccanismo di polling che dovrebbe essere utilizzato per controllare il file (ciò è definito dal parametro backend
). Include anche un filtro che dovrebbe essere utilizzato per determinare se una riga nel log rappresenta un fallimento.
Fail2ban cerca nella directory filter.d
il file di filtro corrispondente che termina con .conf
. Legge questo file per definire i pattern che possono essere utilizzati per corrispondere alle linee offensive. Cerca quindi un file di filtro corrispondente che termina con .local
per vedere se alcuni dei parametri predefiniti sono stati sovrascritti.
Utilizza le espressioni regolari definite in questi file mentre legge il file di registro del servizio. Prova ogni riga failregex
definita nei file filter.d
contro ogni nuova riga scritta nel file di registro del servizio.
Se l’espressione regolare restituisce una corrispondenza, controlla la riga contro le espressioni regolari definite dal ignoreregex
. Se anche questa corrisponde, fail2ban la ignora. Se la riga corrisponde a un’espressione nel failregex
ma non corrisponde a un’espressione nel ignoreregex
, viene incrementato un contatore interno per il client che ha causato la riga e viene creato un timestamp associato all’evento.
Quando viene raggiunto il periodo di tempo stabilito dal parametro findtime
nei file jail.*
(come determinato dal timestamp dell’evento), il contatore interno viene nuovamente decrementato e l’evento non è più considerato rilevante per la politica di divieto.
Se nel corso del tempo vengono registrati ulteriori tentativi di autenticazione falliti, ogni tentativo incrementa il contatore. Se il contatore raggiunge il valore stabilito dal parametro maxretry
entro la finestra temporale configurata, fail2ban istituisce un divieto chiamando l’azione actioncheck
per il servizio come definito nei file action.d/
per il servizio. Ciò serve per determinare se l’azione actionstart
ha impostato la struttura necessaria. Viene quindi chiamata l’azione actionban
per vietare il client offensivo. Viene impostato anche un timestamp per questo evento.
Quando è trascorso il tempo specificato dal parametro bantime
, fail2ban rimuove il divieto dal client chiamando l’azione actionunban
.
Conclusione
Ormai hai una comprensione piuttosto approfondita di come funziona fail2ban. Quando ti discosti dalla configurazione standard, è utile sapere come fail2ban funziona per manipolare il suo comportamento in modo prevedibile.
Per saperne di più su come proteggere altri servizi con fail2ban, puoi leggere Come proteggere un server Nginx con Fail2Ban su Ubuntu 22.04.