Avant de commencer
Restez connecté au serveur dans une fenêtre jusqu'à la fin. Vérifiez aussi que vous disposez d'une console chez votre hébergeur. Configurez d'abord la connexion par clé : voir comment générer une clé.
Étape 1 : installer le module
sudo apt update
sudo apt install libpam-google-authenticator
Malgré son nom, il n'exige aucun compte Google et fonctionne avec n'importe quelle app TOTP. Le serveur vérifie lui-même les codes.
Étape 2 : créer un secret pour chaque utilisateur
Lancez ceci en tant qu'utilisateur qui se connectera, pas avec sudo :
google-authenticator -t -d -f -r 3 -R 30 -w 3
| Option | Signification |
|---|---|
-t | Codes basés sur le temps |
-d | Un code ne peut pas être utilisé deux fois. Nous l'avons vérifié : une seconde connexion avec le même code a échoué. |
-f | Écrire le fichier sans demander |
-r 3 -R 30 | Au plus 3 connexions toutes les 30 secondes. Pensez-y pendant vos tests : des essais rapides répétés échouent même avec un code correct. |
-w 3 | Accepter le code actuel et ceux juste avant et après, pour tolérer un léger écart d'horloge |
Scannez le QR code avec votre app et saisissez un code pour confirmer. Si vous ne pouvez pas le scanner, saisissez la clé secrète à la main dans l'app. L'outil affiche aussi un lien vers une page de graphique de Google et avertit que l'ouvrir expose le secret à Google : ne l'ouvrez donc pas. La commande affiche cinq codes de secours. Enregistrez-les ailleurs que sur ce serveur et sur votre téléphone. Chacun fonctionne une fois à la place d'un code.
Cela crée ~/.google_authenticator avec le mode 400. Gardez-le ainsi : dans notre test, avec le mode 644, les connexions échouaient même avec un code correct.
Étape 3 : configurer PAM
Modifiez /etc/pam.d/sshd. Commentez la ligne qui demande le mot de passe, et ajoutez deux lignes dessous :
# @include common-auth
auth required pam_google_authenticator.so nullok
auth required pam_permit.so
- Pourquoi commenter
common-auth: si vous la laissez, la connexion de notre test demandait le code puis aussi le mot de passe du système. - Ce que fait
nullok: un utilisateur sans fichier de secret peut se connecter sans code, ce qui permet de déployer utilisateur par utilisateur. Retirez-le quand tout le monde est configuré. - Pourquoi
pam_permit.so:nullokfait s'abstenir le module, et PAM a besoin d'au moins un module qui réussisse. Sans cette ligne, les utilisateurs sans fichier de secret étaient refusés dans notre test. Ceux qui ont un fichier ont toujours besoin du bon code.
Une fois nullok retiré, vous pouvez retirer aussi pam_permit.so. Les systèmes Red Hat utilisent une première ligne différente, et le paquet vient d'EPEL. Consultez la documentation de votre distribution.
Étape 4 : configurer sshd
# /etc/ssh/sshd_config.d/10-2fa.conf
AuthenticationMethods publickey,keyboard-interactive
KbdInteractiveAuthentication yes
UsePAM yes
La virgule signifie que les deux sont requis, dans cet ordre. Utilisez un fichier de ce dossier, car la première valeur lue l'emporte, et le sshd_config principal de Debian contient KbdInteractiveAuthentication no plus bas. Les anciens systèmes appelaient ce réglage ChallengeResponseAuthentication.
Vérifiez le fichier avant de recharger :
sudo sshd -t
sudo sshd -T | grep -iE '^(authenticationmethods|kbdinteractiveauthentication|usepam) '
sudo systemctl reload ssh
Si KbdInteractiveAuthentication est désactivé, sshd -t vous le dit, et vous ne devez pas recharger :
Disabled method "keyboard-interactive" in AuthenticationMethods list "publickey,keyboard-interactive"
AuthenticationMethods cannot be satisfied by enabled authentication methods
Étape 5 : tester depuis une nouvelle fenêtre
ssh user@server
(user@server) Verification code:
Ce que nous avons obtenu dans chaque cas :
| Essai | Résultat |
|---|---|
| Clé et code correct | Connecté. Le journal indique Accepted keyboard-interactive/pam for user. |
| Clé et code faux, réutilisé ou vieux de cinq minutes | Permission denied (keyboard-interactive). |
| Pas de clé | Permission denied (publickey). Aucun code n'est demandé, et aucun mot de passe n'est accepté. |
| Clé et code de secours | Connecté une fois. Le code est ensuite retiré du fichier et échoue s'il est réutilisé. |
Si des codes corrects échouent, vérifiez d'abord l'horloge. Le serveur et le téléphone doivent être d'accord sur l'heure. Lancez timedatectl sur le serveur et regardez si l'horloge est synchronisée.
Gardez une porte de retour
Ayez au moins deux de ces éléments avant de fermer votre dernière session ouverte :
- Vos codes de secours, rangés ailleurs que sur le téléphone. Si le téléphone est perdu, entrez avec l'un d'eux, puis relancez
google-authenticatorpour remplacer le secret. - La console de l'hébergeur. Elle n'utilise pas SSH. Depuis elle, supprimez
10-2fa.confet rechargez. - Une exception par adresse, pour un réseau que vous seul pouvez atteindre, comme un VPN :
# At the end of 10-2fa.conf
Match Address 10.8.0.0/24
AuthenticationMethods publickey
- Un compte de secours séparé, avec une clé gardée hors ligne. Ajoutez le même bloc avec
Match User breakglass. Cela convient aussi à une tâche automatisée, si vous limitez sa clé.
Vérifiez une exception avec -C, car un simple sshd -T n'affiche pas les blocs Match :
sudo sshd -T -C user=user,host=server,addr=10.8.0.5 | grep -i authenticationmethods
Chaque exception est un contournement du second facteur : gardez-les peu nombreuses et étroites.
Pour limiter ce que peut exécuter une clé de secours ou de tâche automatique, voir restreindre une clé SSH à une seule commande.
Saisir moins de codes
Avec le partage de connexion, les nouvelles sessions réutilisent une connexion ouverte et ne redemandent pas de code.
Questions
Cela affecte-t-il scp, sftp, rsync et les scripts ?
Oui. Ils se connectent tous de la même façon et demanderont un code : une tâche sans personne pour le saisir échoue. Exemptez son compte avec un bloc Match, et limitez ce que sa clé peut faire avec les options du guide sur la restriction des clés.
Cela protège-t-il sudo ?
Non. Cela ne modifie que /etc/pam.d/sshd. sudo a son propre fichier PAM et n'est pas concerné.