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
| Opzione | Significato |
|---|---|
-t | Codici basati sul tempo |
-d | Un codice non può essere usato due volte. Abbiamo verificato: un secondo login con lo stesso codice è fallito. |
-f | Scrive il file senza chiedere |
-r 3 -R 30 | Al massimo 3 login ogni 30 secondi. Ricordalo quando provi: tentativi ripetuti in fretta falliscono anche con un codice corretto. |
-w 3 | Accetta 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:nullokfa 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:
| Tentativo | Risultato |
|---|---|
| Chiave e codice corretto | Accesso riuscito. Il log dice Accepted keyboard-interactive/pam for user. |
| Chiave e codice sbagliato, riutilizzato o vecchio di cinque minuti | Permission denied (keyboard-interactive). |
| Nessuna chiave | Permission denied (publickey). Non viene chiesto nessun codice e nessuna password viene accettata. |
| Chiave e codice di emergenza | Accesso 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-authenticatorper sostituire il segreto. - La console del provider. Non usa SSH. Da lì, elimina
10-2fa.confe 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.