A cosa serve
Un client SSH deve sapere di parlare con il server vero prima di inviare una password o eseguire un comando. Alla prima connessione mostra l'impronta del server e chiede. Se accetti, la chiave pubblica finisce in known_hosts. Nelle connessioni successive il controllo è automatico, e una chiave diversa produce l'errore REMOTE HOST IDENTIFICATION HAS CHANGED.
Il file contiene solo chiavi pubbliche. Non ha segreti, ma rivela quali server usi.
Il formato
203.0.113.10 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGYt...
[server]:2222 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMJi...
server,203.0.113.10 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAB...
Ogni riga ha i nomi host, il tipo di chiave e la chiave. Una porta diversa dalla 22 si scrive tra parentesi quadre, come [server]:2222. I nomi possono essere un elenco separato da virgole e possono includere caratteri jolly. Due marcatori facoltativi possono comparire per primi: @cert-authority per la chiave di una CA e @revoked per una chiave che non deve mai essere accettata. Con i certificati host SSH, una sola riga della CA può sostituire una riga per ogni server.
Il client legge anche un file valido per tutto il sistema, /etc/ssh/ssh_known_hosts, che un amministratore può riempire per tutti.
Voci con hash
|1|eoQ3SZFlQ/5gRWuuw3MoS+AtytA=|BlzFc5MrVrt8iIEm7rloTmKPRBo= ssh-ed25519 AAAAC3Nz...
Una riga che inizia con |1| ha il nome host in forma di hash, così chi ruba il file non ottiene un elenco pronto dei tuoi server. ssh la trova comunque. Dipende da HashKnownHosts. Il default di OpenSSH è no, ma Debian lo attiva in /etc/ssh/ssh_config, quindi vedrai entrambe le forme.
Per applicare l'hash a un file esistente:
ssh-keygen -H
Il file originale resta come known_hosts.old, in chiaro. Cancella quella copia se lo hai fatto per riservatezza.
Comandi di tutti i giorni
Funzionano anche sui file con hash. Aggiungi -f file per usare un file diverso da quello predefinito.
| Obiettivo | Comando |
|---|---|
| Trovare la voce di un host | ssh-keygen -F server |
| Trovarne una su un'altra porta | ssh-keygen -F '[server]:2222' |
| Mostrare l'impronta di quell'host | ssh-keygen -lF server |
| Elencare tutte le impronte | ssh-keygen -lf ~/.ssh/known_hosts |
| Rimuovere un host | ssh-keygen -R server |
Con -F, il codice di uscita è 1 se l'host non viene trovato, utile negli script. -R esce con 0 in entrambi i casi.
Come verificare un'impronta
Alla prima connessione vedi questo:
The authenticity of host 'server (203.0.113.10)' can't be established.
ED25519 key fingerprint is: SHA256:iU7+QOFWSHJeCFBdzU31dTOoJRNhncp+Wzw3UJMzasU
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
Scrivere yes senza controllare significa fidarsi di qualunque cosa abbia risposto. Per controllare davvero, ottieni il valore da un posto che non passa per questa connessione, come la console del tuo provider, oppure dalla persona che gestisce il server. Sul server:
sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
Confronta i valori, oppure incolla l'impronta corretta al prompt al posto di yes, e ssh fa il confronto per te. Nel nostro test il valore giusto è stato accettato, e uno sbagliato ha ricevuto Please type 'yes', 'no' or the fingerprint:.
ssh-keyscan e il suo problema di fiducia
ssh-keyscan -t ed25519 server >> ~/.ssh/known_hosts
Recupera la chiave pubblica di un server e si vede spesso negli script di configurazione e nei job di CI. Il problema è che non verifica nulla. Registra qualunque cosa risponda, quindi un attaccante sul percorso fa registrare la sua chiave, e da quel momento l'attacco è invisibile.
Va bene se verifichi il risultato dopo:
ssh-keyscan -t ed25519 server | ssh-keygen -lf -
Per la CI è meglio salvare nella pipeline la riga known_hosts attesa come valore e scrivere quella nel file.
Valori di StrictHostKeyChecking
| Valore | Host nuovo | Chiave cambiata |
|---|---|---|
ask (predefinito) | Te lo chiede | Rifiuta |
yes | Rifiuta | Rifiuta |
accept-new | Lo aggiunge | Rifiuta |
no o off | Lo aggiunge | Si connette, con restrizioni |
accept-new è la scelta sensata per l'automazione: si fida al primo uso e rileva i cambiamenti successivi. yes è il più severo e va bene per flotte in cui distribuisci tu known_hosts. Con questo, un host sconosciuto dà:
No ED25519 host key is known for server and you have requested strict checking.
Host key verification failed.
Evita no. Si connette a un host la cui chiave è cambiata, che è proprio il caso che questo file serve a intercettare.
UpdateHostKeys
Un server può comunicare a un client tutte le sue chiavi host dopo il login. Con UpdateHostKeys, il client le aggiunge a known_hosts, e questo permette a un amministratore di aggiungere una nuova chiave, aspettare che i client la imparino e poi rimuovere la vecchia senza avvisi. Abbiamo provato UpdateHostKeys=yes: partendo con la sola voce ED25519, un login ha aggiunto le righe RSA ed ECDSA.
Il manuale dice che è attivo per impostazione predefinita se non hai cambiato UserKnownHostsFile e non hai abilitato VerifyHostKeyDNS. Accetta solo chiavi da un host già considerato fidato tramite il tuo file, non un file globale, e non si applica quando l'host si è autenticato con un certificato.
SSHFP: impronte nel DNS
Le impronte delle chiavi host possono anche essere pubblicate nel DNS come record SSHFP. Questo stampa i record da aggiungere per un server, da eseguire su quel server:
ssh-keygen -r example.com
I client li usano con VerifyHostKeyDNS yes. Ci si fida automaticamente solo quando la risposta DNS è sicura, il che in pratica significa zone firmate e un resolver che le valida. Altrimenti si comporta come ask: ti mostra la corrispondenza e devi comunque confermare. Il default è no.
Domande
Dove si trova il file known_hosts?
In ~/.ssh/known_hosts nella tua cartella home, su qualsiasi sistema con OpenSSH. Può esistere anche un file per tutto il sistema in /etc/ssh/ssh_known_hosts.
Si può cancellare known_hosts?
Contiene solo chiavi pubbliche, quindi non perdi nulla di segreto. Però ssh ti chiederà di nuovo conferma per ogni server, e perdi il controllo che rileva una chiave cambiata. Meglio togliere un solo host con ssh-keygen -R.
Come tolgo un host da known_hosts?
Esegui ssh-keygen -R server, scritto come '[server]:2222' se la porta non è la 22. Funziona anche con i file hashati.
Fonti
- sshd(8), formato del file SSH_KNOWN_HOSTS
- ssh_config(5), manuale OpenBSD
- ssh-keygen(1), manuale OpenBSD
- ssh-keyscan(1), manuale OpenBSD