Come aggiungere l'autenticazione a due fattori a SSH con TOTP

Installa libpam-google-authenticator, esegui google-authenticator come ciascun utente, aggiungi auth required pam_google_authenticator.so a /etc/pam.d/sshd e imposta AuthenticationMethods publickey,keyboard-interactive e KbdInteractiveAuthentication yes nella configurazione del server SSH. Ogni login richiederà poi la chiave e un codice di sei cifre. Tieni aperta una sessione mentre provi, perché un errore può chiuderti fuori.

Aggiornata il . Eseguito dall'inizio alla fine con OpenSSH 10.0 e libpam-google-authenticator su Debian 13, in un container usa e getta, con login reali e codici generati da oathtool: codici corretti, sbagliati, riutilizzati e vecchi, codici di emergenza, utenti senza file del segreto e un modo del file sbagliato.

Prima di iniziare

Resta collegato al server in una finestra fino alla fine. Verifica di avere anche una console del tuo provider di hosting. Configura prima l'accesso con chiave: vedi come generare una chiave.

Passo 1: installa il modulo

sudo apt update
sudo apt install libpam-google-authenticator

Nonostante il nome, non serve nessun account Google e funziona con qualsiasi app TOTP. I codici li controlla il server stesso.

Passo 2: crea un segreto per ogni utente

Eseguilo come l'utente che accederà, non con sudo:

google-authenticator -t -d -f -r 3 -R 30 -w 3
OpzioneSignificato
-tCodici basati sul tempo
-dUn codice non può essere usato due volte. Abbiamo verificato: un secondo login con lo stesso codice è fallito.
-fScrive il file senza chiedere
-r 3 -R 30Al massimo 3 login ogni 30 secondi. Ricordalo quando provi: tentativi ripetuti in fretta falliscono anche con un codice corretto.
-w 3Accetta il codice attuale e quelli appena prima e dopo, per tollerare una piccola differenza di orologio

Scansiona il codice QR con la tua app e digita un codice per confermare. Se non riesci a scansionarlo, inserisci a mano la chiave segreta nell'app. Lo strumento stampa anche un link a una pagina con un grafico di Google e avverte che aprirlo espone il segreto a Google, quindi non aprirlo. Il comando stampa cinque codici di emergenza (scratch code). Salvali in un posto diverso da questo server e dal tuo telefono. Ognuno funziona una volta al posto di un codice.

Questo crea ~/.google_authenticator con modo 400. Lascialo così: nel nostro test, con modo 644 i login fallivano anche con un codice corretto.

Passo 3: configura PAM

Modifica /etc/pam.d/sshd. Commenta la riga che chiede la password e aggiungi due righe sotto:

# @include common-auth
auth required pam_google_authenticator.so nullok
auth required pam_permit.so
  • Perché commentare common-auth: se la lasci, nel nostro test il login chiedeva il codice e poi anche la password di sistema.
  • Cosa fa nullok: un utente senza file del segreto può accedere senza codice, così puoi attivare il sistema un utente alla volta. Toglilo quando tutti sono configurati.
  • Perché pam_permit.so: nullok fa astenere il modulo e PAM ha bisogno che almeno un modulo abbia successo. Senza questa riga, nel nostro test gli utenti senza file del segreto venivano rifiutati. Gli utenti che il file ce l'hanno hanno comunque bisogno del codice giusto.

Quando togli nullok, puoi togliere anche pam_permit.so. I sistemi Red Hat usano una prima riga diversa e il pacchetto viene da EPEL. Controlla la documentazione della tua distribuzione.

Passo 4: configura sshd

# /etc/ssh/sshd_config.d/10-2fa.conf
AuthenticationMethods publickey,keyboard-interactive
KbdInteractiveAuthentication yes
UsePAM yes

La virgola significa che servono entrambi, in quell'ordine. Usa un file in questa cartella perché vince il primo valore letto, e il sshd_config principale di Debian ha più sotto KbdInteractiveAuthentication no. I sistemi più vecchi chiamavano questa impostazione ChallengeResponseAuthentication.

Controlla il file prima di ricaricare:

sudo sshd -t
sudo sshd -T | grep -iE '^(authenticationmethods|kbdinteractiveauthentication|usepam) '
sudo systemctl reload ssh

Se KbdInteractiveAuthentication è disattivato, sshd -t te lo dice e non devi ricaricare:

Disabled method "keyboard-interactive" in AuthenticationMethods list "publickey,keyboard-interactive"
AuthenticationMethods cannot be satisfied by enabled authentication methods

Passo 5: prova da una nuova finestra

ssh user@server
(user@server) Verification code:

Cosa abbiamo ottenuto in ogni caso:

TentativoRisultato
Chiave e codice correttoAccesso riuscito. Il log dice Accepted keyboard-interactive/pam for user.
Chiave e codice sbagliato, riutilizzato o vecchio di cinque minutiPermission denied (keyboard-interactive).
Nessuna chiavePermission denied (publickey). Non viene chiesto nessun codice e nessuna password viene accettata.
Chiave e codice di emergenzaAccesso riuscito una volta. Il codice viene poi rimosso dal file e fallisce se riusato.

Se i codici corretti falliscono, controlla prima l'orologio. Server e telefono devono concordare sull'ora. Esegui timedatectl sul server e verifica se l'orologio è sincronizzato.

Tieni una via di rientro

Abbi almeno due di queste cose prima di chiudere l'ultima sessione aperta:

  • I tuoi codici di emergenza, conservati lontano dal telefono. Se perdi il telefono, entra con uno di questi ed esegui di nuovo google-authenticator per sostituire il segreto.
  • La console del provider. Non usa SSH. Da lì, elimina 10-2fa.conf e ricarica.
  • Un'eccezione per indirizzo, per una rete che solo tu puoi raggiungere, come una VPN:
# At the end of 10-2fa.conf
Match Address 10.8.0.0/24
    AuthenticationMethods publickey
  • Un account di emergenza separato, con una chiave tenuta offline. Aggiungi lo stesso blocco con Match User breakglass. Va bene anche per un job automatico, se limiti la sua chiave.

Controlla un'eccezione con -C, perché il semplice sshd -T non mostra i blocchi Match:

sudo sshd -T -C user=user,host=server,addr=10.8.0.5 | grep -i authenticationmethods

Ogni eccezione è un modo per aggirare il secondo fattore, quindi tienile poche e ristrette.

Per limitare cosa può eseguire una chiave di emergenza o di un job, vedi come limitare una chiave SSH a un solo comando.

Digitare meno codici

Con la condivisione della connessione, le nuove sessioni riusano una connessione aperta e non chiedono di nuovo un codice.

Domande

Questo influisce su scp, sftp, rsync e gli script?

Sì. Accedono tutti allo stesso modo e chiederanno un codice, quindi un job senza nessuno che lo digiti fallisce. Escludi il suo account con un blocco Match e limita ciò che la sua chiave può fare con le opzioni descritte nella guida su come restringere le chiavi.

Protegge anche sudo?

No. Questo cambia solo /etc/pam.d/sshd. sudo ha un suo file PAM e non ne è toccato.

Fonti

Altro in Mettere in sicurezza un server

Tutte le guide