Hardening SSH: chiavi Ed25519, accessi, firewall e Fail2Ban

Hardening SSH moderno su Linux: chiavi Ed25519, disabilitazione password/root, AllowGroups, verifica sshd, firewall di gestione, Fail2Ban e troubleshooting senza rischiare di chiudersi fuori.

SSH è uno dei servizi più delicati di un server perché, quando funziona come previsto, consegna proprio ciò che un attaccante vorrebbe ottenere: una shell autenticata sul sistema. La differenza tra un servizio SSH sicuro e uno pericoloso non è quindi “avere o non avere SSH”, ma chi può raggiungerlo, come può autenticarsi e quali privilegi ottiene dopo l’accesso.

Per anni molte guide hanno trattato il cambio della porta 22 come una misura di sicurezza fondamentale. Spostare il servizio su una porta non standard riduce effettivamente il rumore dei bot più banali, ma non cambia il modello di sicurezza: una scansione completa trova comunque il servizio. È utile come misura operativa, non come sostituto dell’autenticazione forte o delle ACL.

Password e chiavi non sono semplicemente due password diverse

Con l’autenticazione a password il server riceve un segreto che deve verificare. Con una chiave pubblica il segreto privato non lascia mai il client: il server possiede soltanto la chiave pubblica e verifica una firma. Questo cambia drasticamente la resistenza a brute force e credential stuffing, a patto naturalmente che la chiave privata sia protetta e gestita correttamente.

La passphrase della chiave privata protegge invece il file sul client. Se il notebook viene rubato, una chiave cifrata con passphrase non è immediatamente utilizzabile. È quindi possibile avere sia la comodità delle chiavi sia una seconda barriera locale.

La rete è parte dell’hardening

Un server amministrato soltanto dalla VLAN Gestione o attraverso una VPN non ha motivo di esporre SSH a Internet. Questo è spesso il controllo più efficace in assoluto: riduciamo il numero di soggetti che possono persino iniziare una sessione TCP verso sshd. Fail2Ban e le policy di autenticazione lavorano dopo; il firewall lavora prima.

Hardening senza chiudersi fuori

SSH ha una caratteristica antipatica: una configurazione errata può togliere l’accesso proprio alla persona che dovrebbe correggerla. Per questo la procedura è parte integrante della sicurezza. Manteniamo una sessione aperta, validiamo con sshd -t, controlliamo la configurazione risultante con sshd -T, facciamo un reload e proviamo una seconda sessione prima di chiudere la prima.

A questo punto possiamo passare alle impostazioni concrete.

Prima regola: mantenere aperta una sessione

Durante l’hardening non chiudiamo la sessione amministrativa già funzionante. Apriremo una seconda connessione solo dopo aver validato la configurazione. È una precauzione banale che evita di trasformare un errore di battitura in una visita al datacenter.

Creare un amministratore dedicato

adduser adminops
usermod -aG sudo adminops

id adminops

Generare una chiave Ed25519

Le vecchie guide usavano DSA. Non va più fatto. Per un nuovo accesso interattivo usiamo normalmente Ed25519, proteggendo la chiave privata con passphrase.

ssh-keygen -t ed25519 -a 100 -C "adminops@workstation"

ssh-copy-id adminops@server.example.net

ssh adminops@server.example.net

Per hardware token compatibili possiamo valutare anche chiavi FIDO, per esempio ed25519-sk.

Configurazione separata in sshd_config.d

Sulle distribuzioni moderne è più pulito aggiungere un file dedicato invece di trasformare /etc/ssh/sshd_config in una stratificazione di modifiche storiche.

# /etc/ssh/sshd_config.d/90-hardening.conf

PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitEmptyPasswords no

MaxAuthTries 3
LoginGraceTime 30

AllowGroups ssh-admins

X11Forwarding no

Prima creiamo il gruppo e aggiungiamo l’utente:

groupadd -f ssh-admins
usermod -aG ssh-admins adminops

Port forwarding: disabilitarlo solo se non serve

AllowTcpForwarding no e AllowAgentForwarding no riducono la superficie, ma possono rompere tunnel, bastion host, deploy e automazioni. Non vanno copiati alla cieca. Se il server non usa queste funzioni possiamo aggiungerli; altrimenti limitiamoli con blocchi Match.

Validare prima del reload

sshd -t

# Configurazione effettiva risultante
sshd -T | less

systemctl reload ssh
# su alcune distribuzioni:
systemctl reload sshd

Solo adesso apriamo un nuovo terminale e proviamo l’accesso con adminops. La vecchia sessione root/amministrativa rimane aperta finché il test non è concluso.

Limitare SSH a una rete di gestione

La protezione migliore è non rendere SSH raggiungibile da dove non serve. Se disponiamo di una VLAN Gestione, VPN o bastion, la porta 22 dovrebbe essere consentita soltanto da lì.

# esempio UFW
ufw allow from 10.0.20.0/24 to any port 22 proto tcp

# verifica
ss -lntp | grep ':22'

Su nftables/OpenWrt la stessa regola va espressa nel firewall centrale. Spostare SSH su 2222 può ridurre il rumore nei log, ma non sostituisce una ACL.

Fail2Ban

apt install fail2ban

cat > /etc/fail2ban/jail.d/sshd.local <<'EOF'
[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1h
EOF

systemctl enable --now fail2ban
fail2ban-client status sshd

Fail2Ban è una seconda linea: se SSH è raggiungibile solo dalla VPN o dalla rete Gestione, il numero di tentativi ostili si riduce prima ancora che Fail2Ban debba intervenire.

Log e diagnostica

journalctl -u ssh -f
journalctl -u sshd -f

ssh -vvv adminops@server.example.net

# Algoritmi supportati dal client
ssh -Q key
ssh -Q PubkeyAcceptedAlgorithms

Non congelare gli algoritmi senza motivo

Una vecchia abitudine è copiare liste rigide di cipher, MAC e KEX da una guida e lasciarle lì per anni. Con OpenSSH aggiornato, i default evolvono insieme al software. Restringere gli algoritmi ha senso per requisiti precisi o compliance, ma una lista manuale dimenticata può diventare più vecchia dei default che voleva “rafforzare”.

Checklist finale

sshd -t
sshd -T | egrep 'permitrootlogin|passwordauthentication|pubkeyauthentication|maxauthtries'

fail2ban-client status sshd
ss -lntp | grep ':22'

# Test da una seconda sessione
ssh adminops@server.example.net

Riferimento

La fonte da consultare per la versione installata resta sshd_config(5).