Introduzione
Su un server di produzione, SSH non deve essere solo “attivo”. Deve essere prevedibile, ristretto e facile da verificare dopo ogni cambio.
In questo articolo partiamo da un caso reale: una VPS Ubuntu 24.04 esposta a Internet, con accesso amministrativo via SSH, deploy automatici e qualche account operativo. L’obiettivo è ridurre la superficie d’attacco senza tagliare fuori il team.
Il punto non è blindare tutto a caso. Il punto è applicare least privilege, tenere sotto controllo i segreti, correggere i permessi dei file sensibili e lasciare un percorso di accesso sicuro per emergenze.
Warning: se stai lavorando in remoto, apri sempre una seconda sessione prima di modificare sshd_config. Un errore banale può chiuderti fuori.
Prerequisiti
- Ubuntu 24.04 o Debian 12 con accesso root o sudo.
- Un utente amministrativo già funzionante via chiave SSH.
- Accesso alla console del provider, o almeno a una recovery console.
- Pacchetti:
openssh-server,fail2ban,unattended-upgrades.
Note: i comandi sono pensati per una macchina standard. Se usi un pannello, un firewall cloud o un access gateway, verifica che non ci siano regole duplicate.
Step 1: inventario dell’accesso attuale
Prima di cambiare la configurazione, fotografa lo stato reale del demone SSH. Serve per capire quali opzioni sono già attive e per evitare sorprese dopo il reload.
sudo sshd -T | egrep 'permitrootlogin|passwordauthentication|pubkeyauthentication|kbdinteractiveauthentication|permitemptypasswords|maxauthtries|allowusers|allowgroups|x11forwarding'# Output:
permitrootlogin prohibit-password
passwordauthentication yes
pubkeyauthentication yes
kbdinteractiveauthentication yes
maxauthtries 6
x11forwarding noSe vedi passwordauthentication yes e non hai un motivo preciso per tenerlo, hai già trovato il primo punto da correggere. Se permitrootlogin è ancora yes, il rischio è alto.
Step 2: rendi SSH accessibile solo con chiave e utenti espliciti
La regola base in produzione è semplice: niente login root diretto, niente password, niente utenti casuali. Concedi l’accesso solo a chi serve, e solo con chiave.
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)
sudo nano /etc/ssh/sshd_configInserisci o allinea queste righe:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
PermitEmptyPasswords no
AllowUsers deploy opsadmin
X11Forwarding no
MaxAuthTries 3
LoginGraceTime 20# Output:
AllowUsers deploy opsadmin
PasswordAuthentication no
PermitRootLogin noNote: AllowUsers è utile quando hai pochi account. Se hai molti operatori, puoi usare AllowGroups e gestire l’accesso via gruppo dedicato.
Prima di ricaricare il servizio, verifica la sintassi:
sudo sshd -t# Output:
(nessun output)Se il comando non stampa nulla, la configurazione passa il controllo sintattico.
Step 3: applica il principio del privilegio minimo agli account
Molti server falliscono qui. Gli utenti hanno più privilegi del necessario, e le chiavi SSH finiscono in account condivisi. In produzione questo crea problemi di audit e di revoca.
La scelta più pulita è avere un account per operatore, con sudo limitato al necessario. Evita account generici come admin o root2.
sudo useradd -m -s /bin/bash opsadmin
sudo usermod -aG sudo opsadmin
sudo passwd -l opsadmin# Output:
passwd: password expiry information changed.
passwd: password changed.Il blocco della password riduce il rischio di accesso interattivo via password, ma lascia valida la chiave SSH.
Se vuoi essere più severo, crea un gruppo dedicato e limita i comandi sudo. Esempio minimale:
sudo visudo -f /etc/sudoers.d/opsadminopsadmin ALL=(ALL) /bin/systemctl restart app.service, /bin/journalctl -u app.service# Output:
File saved successfullyWarning: concedere ALL=(ALL) NOPASSWD: ALL a un utente operativo non è least privilege. È solo comodità temporanea.
Step 4: sistema permessi e proprietà delle chiavi SSH
Il problema più comune non è la chiave mancante. È la chiave presente, ma leggibile da altri utenti o con permessi errati. SSH rifiuta configurazioni insicure per una buona ragione.
sudo chown -R opsadmin:opsadmin /home/opsadmin/.ssh
sudo chmod 700 /home/opsadmin/.ssh
sudo chmod 600 /home/opsadmin/.ssh/authorized_keys
sudo chmod go-rwx /home/opsadmin/.ssh# Output:
(nessun output)Se gestisci più server, applica la stessa disciplina anche lato client. Una chiave privata con permessi troppo aperti è un incidente in attesa di accadere.
chmod 600 ~/.ssh/id_ed25519
chmod 700 ~/.ssh# Output:
(nessun output)Note: se usi agent forwarding, non farlo verso host non fidati. È comodo, ma aumenta il raggio d’azione della tua sessione.
Step 5: prepara fail2ban per SSH senza falsi positivi
Fail2ban non sostituisce una buona configurazione SSH. La completa. Blocca gli attacchi a password, i tentativi rumorosi e i bot che scandiscono porta 22 tutto il giorno.
Su un server di produzione conviene usare una jail dedicata con tempi ragionevoli. Non serve bannare per una settimana al primo errore. Serve reagire bene e senza impattare gli amministratori legittimi.
sudo apt update
sudo apt install -y fail2ban# Output:
Setting up fail2ban...Crea una jail locale:
sudo nano /etc/fail2ban/jail.d/sshd.local[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
findtime = 10m
bantime = 1h
backend = systemd# Output:
(file salvato)Riavvia e controlla lo stato:
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd# Output:
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| `- Total failed: 12
`- Actions
|- Currently banned: 0Note: su sistemi recenti, il backend systemd riduce problemi di parsing rispetto ai log file tradizionali. Se non funziona, verifica il formato dei log e il path effettivo.
Step 6: aggiorna in automatico, ma con controllo
Le patch di sicurezza non devono aspettare il lunedì. Su una macchina esposta, gli aggiornamenti automatici per i pacchetti di sicurezza sono una scelta prudente.
sudo apt install -y unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades# Output:
Unattended upgrades enabledVerifica la politica attiva:
cat /etc/apt/apt.conf.d/50unattended-upgrades | sed -n '1,120p'Se vuoi un comportamento più prevedibile, limita l’auto-update ai soli repository di sicurezza. In ambienti mission-critical è meglio una finestra di manutenzione chiara che un upgrade casuale su tutto il sistema.
Warning: non lasciare kernel e OpenSSH fermi per mesi. Gli exploit pubblici puntano spesso proprio su componenti noti e vecchi.
Step 7: proteggi i segreti e riduci l’esposizione dei file
SSH è solo una parte del problema. In produzione spesso trovi chiavi API, file .env, token CI e backup lasciati in directory sbagliate. La regola è trattare i segreti come materiale sensibile, non come configurazione qualsiasi.
Per i file applicativi, imposta permessi stretti e ownership coerente. Esempio su una web app con credenziali in .env:
sudo chown root:appteam /srv/app/.env
sudo chmod 640 /srv/app/.env
sudo chmod 750 /srv/app# Output:
(nessun output)Se il processo applicativo deve leggere il file, usa un gruppo dedicato. Non usare chmod 777. Non risolve nulla, e apre tutto.
Per i segreti in shell e cron, evita di scriverli direttamente nella linea di comando. Meglio file protetti, variabili passate dal systemd unit, oppure un secret manager esterno.
Se un segreto compare in ps, nella history della shell o in un log, non è più un segreto. È un incidente.Step 8: verifica il risultato senza perdere l’accesso
Prima di chiudere la sessione corrente, apri una nuova connessione e prova esattamente il percorso che userai in produzione. Questo è il test più importante.
ssh -i ~/.ssh/id_ed25519 opsadmin@server.example.com# Output:
Welcome to Ubuntu 24.04 LTSControlla anche il comportamento del demone e di fail2ban:
sudo sshd -T | egrep 'permitrootlogin|passwordauthentication|maxauthtries'
sudo fail2ban-client status sshd
sudo journalctl -u ssh -n 30 --no-pager# Output:
permitrootlogin no
passwordauthentication no
maxauthtries 3Se usi firewall host-based, verifica che la porta sia davvero quella prevista e che non ci siano regole duplicate tra UFW, nftables e security group cloud.
Verifica finale
La configurazione è credibile solo se soddisfa questi punti:
- root non accede direttamente via SSH.
- le password SSH sono disattivate.
- solo gli utenti previsti possono entrare.
- le chiavi hanno permessi stretti.
- fail2ban blocca i tentativi ripetuti.
- gli aggiornamenti di sicurezza sono automatici.
- i segreti non sono leggibili da account non autorizzati.
Un controllo rapido utile è questo:
sudo sshd -T | grep -E 'permitrootlogin|passwordauthentication|kbdinteractiveauthentication'
sudo stat -c '%a %U %G %n' /home/opsadmin/.ssh /home/opsadmin/.ssh/authorized_keys
sudo fail2ban-client status sshd# Output:
permitrootlogin no
passwordauthentication no
kbdinteractiveauthentication no
700 opsadmin opsadmin /home/opsadmin/.ssh
600 opsadmin opsadmin /home/opsadmin/.ssh/authorized_keysTroubleshooting
1) sshd: no matching key exchange method found
Causa: il client è troppo vecchio o il server ha algoritmi troppo restrittivi per quella macchina.
Fix: verifica gli algoritmi supportati e, se serve, aggiorna il client invece di abbassare la sicurezza del server.
ssh -Q kex
ssh -Q cipher# Output:
sntrup761x25519-sha512
curve25519-sha2562) Authentication refused: bad ownership or modes for directory /home/opsadmin/.ssh
Causa: la directory o i file SSH hanno permessi troppo aperti o proprietà errata.
Fix: ripristina ownership e mode, poi riprova l’accesso.
sudo chown -R opsadmin:opsadmin /home/opsadmin/.ssh
sudo chmod 700 /home/opsadmin/.ssh
sudo chmod 600 /home/opsadmin/.ssh/authorized_keys# Output:
(nessun output)3) fatal: bad configuration option: KbdInteractiveAuthentication
Causa: stai usando una versione di OpenSSH che non riconosce quella direttiva, oppure c’è un refuso nel file.
Fix: controlla la versione e sostituisci l’opzione con quella supportata dal tuo daemon.
sshd -V 2>&1
sudo sshd -t# Output:
OpenSSH_9.6p1 Ubuntu-3ubuntu13.5Conclusione
Una configurazione SSH da produzione non è solo “più sicura”. È più leggibile, più verificabile e più facile da mantenere nel tempo.
Se hai già applicato i passi sopra, il prossimo passo concreto è mettere questa checklist in una pipeline di post-deploy o in un timer systemd. Così ogni cambio di server verifica subito permessi, accesso e blocchi di fail2ban.
Commenti (0)
Nessun commento ancora.
Segnala contenuto
Elimina commento
Eliminare definitivamente questo commento?
L'azione non si può annullare.