Bevor Sie anfangen
Bleiben Sie bis zum Ende in einem Fenster am Server angemeldet. Prüfen Sie, ob Sie zusätzlich eine Konsole Ihres Hosting-Anbieters haben. Richten Sie zuerst die Anmeldung per Schlüssel ein: siehe SSH-Schlüssel erzeugen.
Schritt 1: Modul installieren
sudo apt update
sudo apt install libpam-google-authenticator
Trotz des Namens braucht es kein Google-Konto und funktioniert mit jeder TOTP-App. Der Server prüft die Codes selbst.
Schritt 2: Secret für jeden Benutzer erzeugen
Führen Sie das als der Benutzer aus, der sich anmelden wird, nicht mit sudo:
google-authenticator -t -d -f -r 3 -R 30 -w 3
| Option | Bedeutung |
|---|---|
-t | Zeitbasierte Codes |
-d | Ein Code kann nicht zweimal verwendet werden. Wir haben es geprüft: Eine zweite Anmeldung mit demselben Code scheiterte. |
-f | Die Datei ohne Nachfrage schreiben |
-r 3 -R 30 | Höchstens 3 Anmeldungen alle 30 Sekunden. Denken Sie beim Testen daran: Schnelle wiederholte Versuche scheitern auch mit richtigem Code. |
-w 3 | Den aktuellen Code und die unmittelbar davor und danach akzeptieren, um einen kleinen Zeitunterschied auszugleichen |
Scannen Sie den QR-Code mit Ihrer App und tippen Sie zur Bestätigung einen Code ein. Wenn Sie nicht scannen können, geben Sie den geheimen Schlüssel von Hand in die App ein. Das Werkzeug gibt außerdem einen Link zu einer Google-Chart-Seite aus und warnt, dass das Öffnen das Secret an Google preisgibt, öffnen Sie ihn also nicht. Der Befehl gibt fünf Scratch-Codes für den Notfall aus. Speichern Sie sie woanders als auf diesem Server und Ihrem Handy. Jeder funktioniert einmal anstelle eines Codes.
Das legt ~/.google_authenticator mit dem Modus 400 an. Lassen Sie es dabei: In unserem Test scheiterten Anmeldungen mit dem Modus 644 auch bei richtigem Code.
Schritt 3: PAM konfigurieren
Bearbeiten Sie /etc/pam.d/sshd. Kommentieren Sie die Zeile aus, die nach dem Passwort fragt, und fügen Sie darunter zwei Zeilen hinzu:
# @include common-auth
auth required pam_google_authenticator.so nullok
auth required pam_permit.so
- Warum
common-authauskommentiert wird: Lassen Sie es stehen, fragte die Anmeldung in unserem Test nach dem Code und danach auch noch nach dem Systempasswort. - Was
nulloktut: Ein Benutzer ohne Secret-Datei kann sich ohne Code anmelden, sodass Sie das Verfahren Benutzer für Benutzer einführen können. Entfernen Sie es, wenn alle eingerichtet sind. - Warum
pam_permit.so:nulloklässt das Modul sich enthalten, und PAM braucht mindestens ein Modul mit Erfolg. Ohne diese Zeile wurden Benutzer ohne Secret-Datei in unserem Test abgewiesen. Benutzer, die eine Datei haben, brauchen weiterhin den richtigen Code.
Sobald Sie nullok entfernen, können Sie auch pam_permit.so entfernen. Red-Hat-Systeme verwenden eine andere erste Zeile, und das Paket kommt aus EPEL. Lesen Sie dazu die Dokumentation Ihrer Distribution.
Schritt 4: sshd konfigurieren
# /etc/ssh/sshd_config.d/10-2fa.conf
AuthenticationMethods publickey,keyboard-interactive
KbdInteractiveAuthentication yes
UsePAM yes
Das Komma bedeutet, dass beides nötig ist, in dieser Reihenfolge. Nehmen Sie eine Datei in diesem Ordner, weil der zuerst gelesene Wert gilt und die Haupt-sshd_config von Debian weiter unten KbdInteractiveAuthentication no enthält. Ältere Systeme nannten diese Einstellung ChallengeResponseAuthentication.
Prüfen Sie die Datei, bevor Sie neu laden:
sudo sshd -t
sudo sshd -T | grep -iE '^(authenticationmethods|kbdinteractiveauthentication|usepam) '
sudo systemctl reload ssh
Ist KbdInteractiveAuthentication aus, meldet sshd -t das, und Sie sollten nicht neu laden:
Disabled method "keyboard-interactive" in AuthenticationMethods list "publickey,keyboard-interactive"
AuthenticationMethods cannot be satisfied by enabled authentication methods
Schritt 5: aus einem neuen Fenster testen
ssh user@server
(user@server) Verification code:
Das haben wir in den einzelnen Fällen erhalten:
| Versuch | Ergebnis |
|---|---|
| Schlüssel und richtiger Code | Angemeldet. Das Log zeigt Accepted keyboard-interactive/pam for user. |
| Schlüssel und falscher, wiederverwendeter oder fünf Minuten alter Code | Permission denied (keyboard-interactive). |
| Kein Schlüssel | Permission denied (publickey). Es wird kein Code verlangt, und kein Passwort wird akzeptiert. |
| Schlüssel und Scratch-Code | Einmal angemeldet. Der Code wird danach aus der Datei entfernt und scheitert bei erneuter Verwendung. |
Scheitern richtige Codes, prüfen Sie zuerst die Uhr. Server und Handy müssen sich über die Uhrzeit einig sein. Führen Sie timedatectl auf dem Server aus und prüfen Sie, ob die Uhr synchronisiert ist.
Einen Weg zurück offenhalten
Haben Sie mindestens zwei davon, bevor Sie Ihre letzte offene Sitzung schließen:
- Ihre Scratch-Codes, getrennt vom Handy aufbewahrt. Geht das Handy verloren, melden Sie sich mit einem davon an und führen
google-authenticatorerneut aus, um das Secret zu ersetzen. - Die Konsole des Anbieters. Sie nutzt kein SSH. Löschen Sie dort
10-2fa.confund laden Sie neu. - Eine Ausnahme nach Adresse, für ein Netz, das nur Sie erreichen können, etwa ein VPN:
# At the end of 10-2fa.conf
Match Address 10.8.0.0/24
AuthenticationMethods publickey
- Ein getrenntes Notfallkonto mit einem Schlüssel, der offline aufbewahrt wird. Fügen Sie denselben Block mit
Match User breakglasshinzu. Das passt auch zu einem automatisierten Auftrag, wenn Sie seinen Schlüssel einschränken.
Prüfen Sie eine Ausnahme mit -C, weil ein einfaches sshd -T Match-Blöcke nicht zeigt:
sudo sshd -T -C user=user,host=server,addr=10.8.0.5 | grep -i authenticationmethods
Jede Ausnahme ist ein Weg um den zweiten Faktor herum, halten Sie sie also wenige und eng gefasst.
Wie Sie einschränken, was ein Notfall- oder Job-Schlüssel ausführen darf, zeigt einen SSH-Schlüssel auf einen Befehl beschränken.
Weniger Codes tippen
Mit geteilten Verbindungen nutzen neue Sitzungen eine offene Verbindung mit und fragen nicht erneut nach einem Code.
Fragen
Betrifft das scp, sftp, rsync und Skripte?
Ja. Sie melden sich alle auf dieselbe Weise an und fragen nach einem Code, sodass ein Auftrag, bei dem niemand tippt, scheitert. Nehmen Sie sein Konto mit einem Match-Block aus und beschränken Sie mit den Optionen aus der Anleitung zum Einschränken von Schlüsseln, was sein Schlüssel darf.
Schützt das auch sudo?
Nein. Das ändert nur /etc/pam.d/sshd. sudo hat eine eigene PAM-Datei und ist nicht betroffen.