Proteggere SSH: accesso con chiave, blocco del login root, password disattivate

Pubblicato il 17 min di lettura

ed25519 su Linux, macOS e Windows, la trappola cloud-init in /etc/ssh/sshd_config.d, l'attivazione via socket su Ubuntu 24.04, la verifica con sudo sshd -T e la via di salvataggio dalla console.

Un server appena installato finisce nelle liste degli scanner pochi minuti dopo essere diventato raggiungibile. Quello che arriva è quasi sempre la stessa cosa: tentativi automatici di indovinare nomi utente e password sulla porta 22. Chi disattiva l'autenticazione con password e ammette soltanto le chiavi toglie ogni base a questa intera classe di attacchi. Non la indebolisce: la elimina del tutto.

I passaggi di base li conoscono quasi tutti. Quello che manca nelle guide più diffuse è la parte successiva: perché PasswordAuthentication no resta regolarmente senza effetto sulle immagini cloud, perché un systemctl reload ssh su un server con ssh.socket attivo non fa più quello che ti aspetti, e come dimostrare (invece di sperare) che la modifica sia davvero attiva. È esattamente questo il tema. Tutte le indicazioni si riferiscono a Debian 13, Debian 12, Ubuntu 24.04 e Ubuntu 22.04.

La regola che salva tutto: due sessioni

Prima di toccare qualsiasi cosa nella configurazione SSH, apri una seconda finestra di terminale e accedi al server anche da lì. Questa seconda sessione resta aperta finché non hai collaudato con successo la nuova configurazione tramite una terza connessione completamente nuova.

Il motivo è tecnico: il riavvio del servizio SSH non chiude le sessioni esistenti. Le connessioni in corso vengono servite da processi figli già separati e sopravvivono al riavvio del processo padre. Di una configurazione rotta ti accorgi quindi solo al successivo tentativo di connessione, e a quel punto la vecchia sessione è la tua unica via di ritorno. Chi la chiude per "rifare un accesso pulito da zero" se ne pente con una certa regolarità.

Verifica inoltre quale versione di OpenSSH hai davanti, perché da questo dipendono diversi dettagli:

ssh -V
SistemaOpenSSHListener predefinito
Debian 13 (trixie)10.0p2ssh.service
Debian 12 (bookworm)9.2p1ssh.service
Ubuntu 24.04 LTS9.6p1ssh.socket
Ubuntu 22.04 LTS8.9p1ssh.service

Se il servizio server manca del tutto, per esempio in un'immagine minimale, installalo:

sudo apt update
sudo apt install -y openssh-server

Generare la chiave: ed25519 su Linux, macOS e Windows

Scegli ed25519. Chiave corta, verifica veloce, ampio margine di sicurezza, e ogni versione di OpenSSH trattata qui la supporta. RSA ti serve solo per sistemi datati che non accettano altro, e in quel caso con almeno 4096 bit.

Linux e macOS

ssh-keygen -t ed25519 -a 100 -C "hani@notebook" -f ~/.ssh/id_ed25519

-a 100 alza il numero di round KDF per la passphrase e rende molto più costosi gli attacchi offline al file della chiave. -C imposta un commento che finisce poi in authorized_keys e ti dice quale chiave proviene da quale dispositivo. Assegna una passphrase. Una chiave senza passphrase è un file che chiunque può portarsi via, basta che si sieda un attimo al tuo computer.

Per non dover digitare la passphrase a ogni connessione, è l'agent a tenerla in memoria:

eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519

Su macOS metti invece la passphrase nel portachiavi. La vecchia opzione -K da macOS 12 si chiama --apple-use-keychain:

ssh-add --apple-use-keychain ~/.ssh/id_ed25519

Perché questo sopravviva a un riavvio, in ~/.ssh/config va scritto:

Host *
    UseKeychain yes
    AddKeysToAgent yes
    IdentityFile ~/.ssh/id_ed25519

Windows

Windows 10 dalla versione 1809, Windows 11 e Windows Server dal 2019 includono il client OpenSSH. In PowerShell:

ssh -V
ssh-keygen -t ed25519 -a 100 -C "hani@windows"

La chiave finisce in C:\Users\TuoNome\.ssh\. Se il client manca, installalo come funzionalità di Windows:

Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0

Su Windows l'agent è un servizio di sistema e alla consegna è disattivato:

Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519

Portare la chiave pubblica sul server

Sul server va esclusivamente il file con estensione .pub. Il file senza estensione è la chiave privata e non lascia mai il tuo computer.

La via comoda su Linux

ssh-copy-id -i ~/.ssh/id_ed25519.pub root@203.0.113.10

ssh-copy-id crea ~/.ssh, imposta i permessi corretti, aggiunge la chiave ad authorized_keys e nel farlo controlla se sia già presente. Su macOS lo strumento non è incluso in tutte le versioni. Verifica al volo con command -v ssh-copy-id e, se manca, passa alla via manuale.

La via Windows senza ssh-copy-id

Il client OpenSSH di Microsoft non contiene ssh-copy-id. L'originale è uno script di shell e non è mai stato portato. Lo stesso risultato si ottiene con una pipe:

type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh root@203.0.113.10 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"

Qui si nasconde un dettaglio che costa parecchie ore: quando passa i dati a un programma esterno, PowerShell aggiunge i fine riga in formato Windows. In authorized_keys resta così un carattere di ritorno a capo invisibile alla fine della riga. Finché hai commentato la chiave con -C, quel carattere finisce nel campo commento e non dà fastidio. Senza commento resta attaccato al blocco Base64 e l'accesso fallisce senza un messaggio utile. Quindi: imposta sempre un commento e, nel dubbio, fai una pulizia sul server.

sed -i 's/\r$//' ~/.ssh/authorized_keys

La via manuale, che funziona ovunque

mkdir -p ~/.ssh && chmod 700 ~/.ssh && touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys

Poi aggiungi il contenuto del file .pub come una riga sola. Se il file si trova già sul server, per esempio perché lo hai caricato, si fa direttamente così:

cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys

Controlla subito dopo che cosa è finito davvero nel file:

ssh-keygen -lf ~/.ssh/authorized_keys

L'output elenca fingerprint e commento di ogni voce valida. Quello che qui non compare è andato a capo oppure è danneggiato. Confronta il fingerprint con quello della tua chiave locale:

ssh-keygen -l -f ~/.ssh/id_ed25519.pub

Se i due coincidono, il trasferimento è andato a buon fine. Adesso, prima di disattivare qualsiasi cosa, verifica che l'accesso con chiave funzioni davvero. Solo quando una nuova connessione passa senza richiesta di password si va avanti.

La trappola: /etc/ssh/sshd_config.d e cloud-init

Qui è il punto in cui la maggior parte delle guide si ferma, ed è anche il motivo più frequente della frase "l'ho disattivato, eppure funziona ancora".

Da Debian 11 e Ubuntu 22.04, in cima a /etc/ssh/sshd_config c'è una riga che legge un'intera directory. Guarda tu stesso in quale posizione:

grep -n Include /etc/ssh/sshd_config

Su tutti e quattro i sistemi trattati qui la riga Include sta all'inizio, non alla fine. E adesso arriva la particolarità di OpenSSH, che quasi nessun altro linguaggio di configurazione conosce: vince il primo valore trovato, non l'ultimo. Quello che sta in un file sotto /etc/ssh/sshd_config.d/ viene quindi letto prima del file principale e batte qualunque riga successiva in sshd_config.

Cloud-init usa esattamente questa directory. Al primo avvio scrive /etc/ssh/sshd_config.d/50-cloud-init.conf e, a seconda del provisioning, lì dentro c'è PasswordAuthentication yes. Puoi poi inserire PasswordAuthentication no in sshd_config quante volte vuoi: l'autenticazione con password resta aperta. Fatti prima un quadro della situazione:

ls -la /etc/ssh/sshd_config.d/
sudo grep -riE 'passwordauthentication|permitrootlogin|kbdinteractive' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/

Da qui nasce il consiglio vero e proprio: non toccare affatto sshd_config. Crea invece un file tuo, il cui nome si ordini alfabeticamente prima di tutto ciò che l'automazione deposita in quella directory. I file vengono letti in ordine alfabetico, 01- viene prima di 50-, e siccome vince il primo valore, cloud-init può riscrivere il suo file quante volte vuole senza scardinare il tuo hardening. È questa la differenza rispetto al consiglio molto diffuso di creare un 99-hardening.conf: quello perde contro cloud-init, e per giunta in silenzio. La stessa meccanica però può anche rivoltarsi contro di te: un file con numero più basso, per esempio 00-cloud.conf, vince contro il tuo 01-, perché OpenSSH prende il valore letto per primo. Vale quindi la pena dare un'occhiata alla directory anche dopo l'hardening.

Scrivere l'hardening, con un timer di sicurezza come via di ritorno

Costruisci prima la rete di sicurezza. Il comando seguente rimuove automaticamente il tuo nuovo file dopo dieci minuti e riavvia SSH, se nel frattempo non lo hai annullato:

sudo systemd-run --on-active=10min --unit=ssh-rollback /bin/sh -c 'rm -f /etc/ssh/sshd_config.d/01-hardening.conf; systemctl try-restart ssh.socket ssh.service'

Adesso la configurazione vera e propria:

sudo tee /etc/ssh/sshd_config.d/01-hardening.conf >/dev/null <<'EOF'
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
PermitEmptyPasswords no
MaxAuthTries 3
EOF
sudo chmod 644 /etc/ssh/sshd_config.d/01-hardening.conf

Due righe meritano una spiegazione. KbdInteractiveAuthentication no non è un accessorio: se resta su yes, PAM può continuare a proporre la richiesta di password passando dalla scorciatoia della tastiera interattiva, anche se PasswordAuthentication è su no. È esattamente per questo che esistono server che chiedono ancora una password nonostante l'autenticazione con password sia disattivata.

E PermitRootLogin prohibit-password invece di no: così l'accesso come root con chiave resta possibile, mentre le password per root sono escluse. Quando hai creato un utente tuo con sudo e ne hai collaudato in modo dimostrabile l'accesso con chiave, imposta invece PermitRootLogin no. Prima no.

Quello che non dovresti riprendere, anche se compare nelle guide più vecchie: ChallengeResponseAuthentication. Dalla versione 8.7 di OpenSSH l'opzione è soltanto un vecchio alias di KbdInteractiveAuthentication e nelle versioni attuali genera un avviso di deprecazione nel log. Lasciala perdere.

Controllo della sintassi prima di attivare, senza eccezioni:

sudo sshd -t

Nessun output significa: il file è corretto dal punto di vista sintattico. Non significa che nel merito faccia quello che vuoi tu. Di questo si occupa fra poco sudo sshd -T.

Se invece il test segnala Missing privilege separation directory: /run/sshd, vuol dire che sshd non è ancora partito nemmeno una volta da quando il sistema è acceso, perché quella directory nasce solo con ssh.service. Riguarda soprattutto Ubuntu 24.04 con attivazione via socket e si risolve con sudo mkdir -p /run/sshd oppure sudo systemctl start ssh.service; su un server a cui sei collegato proprio via SSH non si presenta comunque.

Attivare: ssh.service, ssh.socket e le differenze fra le distribuzioni

Qui i quattro sistemi divergono, e la vecchia abitudine systemctl reload ssh è la risposta sbagliata ovunque sia ssh.socket a tenere la porta.

Ubuntu punta sull'attivazione via socket dalla 22.10 e Ubuntu 24.04 la consegna come impostazione predefinita: lì ssh.socket è abilitato e ssh.service disabilitato. Debian di fabbrica fa esattamente il contrario. Debian 13 e Debian 12 arrivano con ssh.service abilitato e ssh.socket disabilitato, contro la convinzione diffusa che Debian 13 passi al socket in una nuova installazione. Con l'attivazione via socket è systemd stesso ad ascoltare sulla porta 22 e ad avviare un sshd nuovo solo quando arriva una connessione. Questo ha un effetto collaterale piacevole: le modifiche a sshd_config valgono comunque alla connessione successiva, perché ogni processo di connessione rilegge la configurazione. Un ricaricamento ti serve solo per le impostazioni che riguardano il listener stesso, cioè Port e ListenAddress.

Non tirare a indovinare, quindi: chiedi al sistema quale unità gestisce da te il servizio:

systemctl is-enabled ssh.socket ssh.service
Sistemassh.socketssh.serviceParticolarità
Ubuntu 24.04 LTSenableddisabledAttivazione via socket predefinita, ListenStream su 0.0.0.0:22 e [::]:22
Debian 13 (trixie)disabledenabledAccept=no
Debian 12 (bookworm)disabledenabledAccept=no
Ubuntu 22.04 LTS (e allo stesso modo Debian 11)disabledenabledAccept=yes, quindi un processo dedicato per ogni connessione tramite ssh@.service

E poi un comando che è corretto su tutti e quattro i sistemi:

sudo sshd -t && sudo systemctl try-restart ssh.socket ssh.service

try-restart riavvia un'unità solo se è effettivamente attiva e lascia intatta l'altra. Così non devi indovinare. Entrambe le parti richiedono root: sshd si trova in /usr/sbin e su Debian non compare nel PATH di un utente normale, e try-restart passa comunque da systemd. Senza sudo la chiamata finisce, a seconda del sistema, con sshd: command not found oppure con sshd: no hostkeys available, perché le chiavi host sotto /etc/ssh sono leggibili solo da root.

Altrettanto consapevolmente niente systemctl restart ssh.socket da solo, anche se questo comando compare in molte guide. Su Debian 13 e Debian 12 si interrompe con Job failed. See journalctl -xe for details. e nel journal si legge ssh.socket: Socket service ssh.service already active, refusing. La nuova configurazione non diventa attiva e la controprova continua a segnalare Permission denied (publickey,password). Su Ubuntu 22.04 e Debian 11 il comando passa senza messaggi di errore, ma ferma ssh.service e commuta l'host sull'attivazione via socket. Siccome lì ssh.socket resta disabilitato, al riavvio successivo riparte di nuovo ssh.service: la modalità operativa cambia quindi avanti e indietro senza che te ne accorga. try-restart su entrambe le unità evita tutti e due i casi.

Consapevolmente niente reload: su un sistema in cui è ssh.socket a tenere la porta, un systemctl reload ssh risponde con

fatal: Cannot bind any address.

Dopodiché il servizio resta in stato di errore e ha lasciato andare la sua porta. Un riavvio non ha questo problema e, allo stesso modo, non chiude le sessioni esistenti.

Se vuoi spostare la porta, arriva la differenza successiva fra le distribuzioni. Ubuntu 24.04 genera la configurazione del socket da sshd_config tramite un generatore systemd, e lì dopo il cambio di porta basta:

sudo systemctl daemon-reload
sudo systemctl try-restart ssh.socket ssh.service

Se invece su Debian sei passato consapevolmente a ssh.socket, la porta sta nell'unità stessa e una modifica in sshd_config resta senza effetto. La imposti tramite un file di override con sudo systemctl edit ssh.socket, con un ListenStream= vuoto per azzerare e una seconda riga con il nuovo valore. Poi controlla il risultato sulla realtà, non sulla configurazione:

sudo ss -tlnp

La prova: sshd -T e la controprova

Un comando che passa senza errori non è una prova. La prova è la configurazione complessiva risolta, in cui tutti i file inclusi sono già conteggiati:

sudo sshd -T | grep -E '^(passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|permitrootlogin|usepam|port|authorizedkeysfile)'

Ci si aspetta un output di questo tipo:

port 22
permitrootlogin prohibit-password
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
usepam yes
authorizedkeysfile .ssh/authorized_keys .ssh/authorized_keys2

Se lì, nonostante il tuo file, compare passwordauthentication yes, nella directory c'è un file che si ordina alfabeticamente prima del tuo. Torna al paragrafo sull'ordine di lettura.

Per una singola verifica basta lo stesso comando con un filtro più stretto:

sudo sshd -T | grep -i passwordauthentication

Ci sono due motivi per il sudo davanti. Primo, sshd -T legge le chiavi host, che sotto /etc/ssh sono leggibili solo da root. Secondo, sshd stesso si trova in /usr/sbin, e su Debian questa directory non fa parte del PATH di un utente normale, per cui senza sudo la chiamata finisce con sshd: command not found. Chi vuole evitare la strada del sudo scrive il percorso completo /usr/sbin/sshd.

Dalla versione 9.3 di OpenSSH, quindi su Ubuntu 24.04 (9.6p1) e Debian 13 (10.0p2), esiste in più sshd -G. L'opzione valuta la stessa configurazione, ma non richiede chiavi host leggibili né una /run/sshd già presente, il che la rende utile per i controlli in automazione e nei container. Su Debian 12 (9.2p1), Ubuntu 22.04 (8.9p1) e Debian 11 (8.4p1) l'opzione non esiste ancora e sshd la rifiuta come opzione sconosciuta. Per una guida valida ovunque resta quindi giusto sudo sshd -T.

Adesso la controprova, e precisamente da un nuovo terminale, mentre la vecchia sessione resta aperta. Forza un'autenticazione con password e disattiva le chiavi per questo tentativo:

ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password,keyboard-interactive root@203.0.113.10

È corretto se vieni respinto subito e senza alcuna richiesta di password:

root@203.0.113.10: Permission denied (publickey).

Decisivo è il contenuto della parentesi. Se lì c'è (publickey,password) oppure compare una richiesta di password, l'autenticazione con password è ancora aperta. Solo quando la controprova fallisce in modo pulito e una normale connessione con chiave continua a riuscire, chiudi la vecchia sessione e fermi il timer di sicurezza:

sudo systemctl stop ssh-rollback.timer

I messaggi di errore alla lettera

Permission denied (publickey). Il server accetta solo chiavi e la tua non va bene. Lancia ssh -v e guarda quale file sia stato davvero offerto. Cause più frequenti: nome utente sbagliato, chiave nell'authorized_keys dell'utente sbagliato, oppure hai bloccato root e continui ad accedere come root.

Authentication refused: bad ownership or modes for directory /home/hani/.ssh Questa riga non compare sul tuo schermo, ma nel log del server, visibile con sudo journalctl -u ssh -n 50 --no-pager. Non filtrare però con -t sshd: dalla versione 9.8 di OpenSSH, quindi su Debian 13 già alla consegna, le sessioni girano nel processo separato sshd-session, e sotto il tag sshd restano solo i messaggi del listener, senza un solo tentativo di accesso. Chi vuole filtrare per tag usa sudo journalctl -t sshd -t sshd-session -n 50 --no-pager. OpenSSH rifiuta le chiavi se la home, .ssh oppure authorized_keys sono scrivibili dal gruppo o da altri. La correzione:

chmod go-w ~ && chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys

WARNING: UNPROTECTED PRIVATE KEY FILE! ovvero Load key "/home/hani/.ssh/id_ed25519": bad permissions. Lo stesso problema sul lato client. chmod 600 ~/.ssh/id_ed25519 lo risolve.

Too many authentication failures Il tuo agent propone a rotazione tutte le chiavi caricate e supera così MaxAuthTries. Limita la connessione a una sola chiave: ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 hani@203.0.113.10.

sign_and_send_pubkey: no mutual signature supported Una vecchia chiave RSA con firma SHA-1 incontra un server che non la accetta più. Genera una chiave ed25519 invece di mettere mano a PubkeyAcceptedAlgorithms.

Bad owner or permissions on C:\Users\hani\.ssh\config Il client Windows controlla i permessi del proprio file di configurazione. Nelle proprietà del file, sotto Sicurezza, rimuovi l'ereditarietà e tutte le voci tranne il tuo account utente e SYSTEM.

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! La chiave host del server è diversa rispetto all'ultima volta. Dopo una reinstallazione è prevedibile, altrimenti no. Rimuovi la vecchia voce in modo mirato con ssh-keygen -R 203.0.113.10, e solo se conosci il motivo.

Chiuso fuori: la via della console nell'area clienti

Se entrambe le sessioni sono sparite e nessuna connessione va più a buon fine, non si tratta di una perdita di dati ma di una deviazione. Ogni server root KVM e ogni server dedicato di KernelHost dispone nell'area clienti di una console che si aggancia all'output video del sistema ed è indipendente dallo stack di rete del server. Entri quindi anche quando SSH non è più in ascolto.

  1. Accedi all'area clienti, apri il server interessato e avvia la console.
  2. Al prompt di accesso entra come root con la password assegnata al momento del provisioning. L'accesso da console non passa da SSH e non è toccato da PermitRootLogin.
  3. Annulla la modifica: sudo rm /etc/ssh/sshd_config.d/01-hardening.conf
  4. Controlla e riavvia: sudo sshd -t && sudo systemctl try-restart ssh.socket ssh.service
  5. Se SSH non parte proprio, aiutano sudo systemctl status ssh.socket ssh.service e un'occhiata a sudo journalctl -u ssh -n 50 --no-pager. Il valore di ritorno 3 di status significa soltanto che una delle due unità è inattiva: su Debian, con ssh.socket disabilitato, è la normalità.

Due precauzioni ti risparmiano questa strada quasi sempre. Annota la password di root prima di disattivare l'autenticazione con password, perché alla console serve. E controlla un eventuale firewall attivo prima di spostare la porta SSH. Un cambio di porta senza la relativa regola di apertura chiude fuori con la stessa affidabilità di una sshd_config rotta, ma si presenta diversamente: al posto di Permission denied ricevi Connection timed out.

In breve

  • Lascia aperta una seconda sessione finché una terza connessione, nuova, non funziona in modo dimostrabile.
  • ed25519 con -a 100 e passphrase, chiave pubblica tramite ssh-copy-id, su Windows tramite pipe.
  • Collauda l'accesso con chiave prima di far cadere l'autenticazione con password.
  • Hardening in /etc/ssh/sshd_config.d/01-hardening.conf, non in sshd_config. Vince il primo valore trovato, da qui il numero basso.
  • Non dimenticare KbdInteractiveAuthentication no, altrimenti resta aperta la scorciatoia via PAM.
  • Attiva con sudo sshd -t && sudo systemctl try-restart ssh.socket ssh.service, né con reload né con un singolo restart ssh.socket.
  • Chiarisci prima con systemctl is-enabled ssh.socket ssh.service quale unità sia davvero attiva. Ubuntu 24.04 usa il socket, Debian 13 e Debian 12 il servizio.
  • La prova arriva da sudo sshd -T e da un tentativo forzato con password da una nuova sessione.
  • La via d'emergenza è la console nell'area clienti, per la quale serve avere pronta la password di root.

I livelli successivi più immediati li descrivono i nostri articoli su fail2ban e sul firewall UFW. Più importante di entrambi è quello che hai appena portato a termine.

Domande frequenti

Perché l'autenticazione con password resta attiva nonostante PasswordAuthentication no?
Quasi sempre per colpa di un file in /etc/ssh/sshd_config.d/, di solito 50-cloud-init.conf. Su Debian e Ubuntu la riga Include sta all'inizio di sshd_config, e OpenSSH prende il primo valore trovato, non l'ultimo. Quello che si trova nella directory vince quindi contro il file principale. Verifica con sudo sshd -T che cosa vale davvero e crea il tuo file come 01-hardening.conf, così viene letto prima di tutti i file generati in automatico.
Dopo una modifica a sshd_config devo riavviare il servizio?
Su Debian 13, Debian 12 e Ubuntu 22.04 sì, perché lì di fabbrica ssh.service è abilitato e ssh.socket disabilitato. Su Ubuntu 24.04 è systemd ad ascoltare, in modo predefinito tramite ssh.socket, e avvia un nuovo sshd per ogni connessione, che rilegge comunque la configurazione. Solo Port e ListenAddress riguardano il listener stesso. Quale unità sia attiva da te lo mostra systemctl is-enabled ssh.socket ssh.service. Il comando sudo sshd -t && sudo systemctl try-restart ssh.socket ssh.service è corretto su tutti e quattro i sistemi, mentre un singolo systemctl restart ssh.socket non lo è: su Debian 13 e Debian 12 fallisce e la nuova configurazione non diventa attiva, su Ubuntu 22.04 commuta l'host sull'attivazione via socket senza che te ne accorga.
Perché dovrei evitare reload?
Sui sistemi con ssh.socket attivo, quindi in modo predefinito su Ubuntu 24.04, systemctl reload ssh si interrompe con il messaggio fatal: Cannot bind any address, il servizio va in stato di errore e libera la sua porta. Un riavvio non ha questo problema e allo stesso modo non chiude le sessioni esistenti, perché le connessioni in corso sono servite da processi figli propri.
Come porto la mia chiave sul server da Windows, se lì ssh-copy-id non esiste?
Con una pipe: type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh utente@server "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys". Fai attenzione ad aver commentato la chiave con -C, altrimenti un carattere di ritorno a capo aggiunto da PowerShell può danneggiare il blocco Base64. Sul server la pulizia si fa con sed -i 's/\r$//' ~/.ssh/authorized_keys.
Come dimostro che l'autenticazione con password sia davvero chiusa?
In due passaggi. Primo, sudo sshd -T, che stampa la configurazione complessiva risolta e deve mostrare passwordauthentication no e kbdinteractiveauthentication no. Secondo, una controprova da una nuova sessione: ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password,keyboard-interactive utente@server deve essere respinto subito con Permission denied (publickey). Se nella parentesi compare publickey,password, l'accesso è ancora aperto.
Che cosa faccio se mi sono chiuso fuori?
Accedi all'area clienti, apri il server e avvia la console. È agganciata all'output video del sistema ed è indipendente da SSH. Lì entra come root, rimuovi il tuo file con sudo rm /etc/ssh/sshd_config.d/01-hardening.conf, controlla con sudo sshd -t e riavvia con sudo systemctl try-restart ssh.socket ssh.service. Tieni pronta la password di root prima di disattivare l'autenticazione con password.
È meglio PermitRootLogin no oppure prohibit-password?
prohibit-password continua a permettere root con chiave ed esclude soltanto le password, mantenendo l'accesso anche in caso di configurazioni errate. no è più severo, ma presuppone che esista un secondo utente con sudo e che il suo accesso con chiave funzioni già in modo dimostrabile. Passa a no solo dopo aver superato questo test.

SSH Sicurezza dei server Linux Debian Ubuntu OpenSSH ed25519 systemd cloud-init Tutorial