schlittermann

SSH ohne Passwort -- Kurze Anleitung zur Nutzung

Auf einfachen Wunsch ... eine unvollständige Anleitung, wie immer hilft das Manual (man ssh) weiter.

Die SSH ist Ersatz für rsh, rlogin, rcp, ... und bietet

ssh/slogin/scp kann als Ersatz für rsh/rlogin/rcp genutzt werden. Bei vorhandener .rhosts auf dem Zielrechner kann sie sich wie die r* commands verhalten. Sollten dann doch Passwörter übertragen werden, sind diese verschlüsselt. Bei der Nutzung von .rhosts ist die Authentisierung nicht sonderlich sicher, das Paar aus `host' und `user' ist doch ziemlich leicht durch Fremde zu nachzuempfinden. Sie beruhen ausschliesslich auf Vertrauen gegenüber dem DNS und dem fremden Host. Die ssh nutzt host- und userspezifische Keys zur Authentisierung. Spoofing wird damit schwerer.

Für die Nutzung der ssh als Ersatz für telnet und rlogin sind folgende Dinge zu tun:

	$ ssh-keygen -t rsa1	  # für Protokol 1 (!! nicht mehr verwenden !!)
        $ ssh-keygen -t rsa	  # für Protokol 2
        $ ssh-keygen -t dsa	  # für Protokol 2

Damit werden eigene Schlüsselpaare erzeugt. (Für Protokol 2 gibt es RSA und DSA Keys, eigentlich reicht normalerweise einer von beiden.) Die Passphrase sollte nicht zu lang sein, denn sie wird doch das eine oder andere Mal abgefragt. Zeitweise wurden DSA-Keys für unsicher gehalten, da wohl der Algorithmus schlecht implementiert war.

Es entstehen Dateien mit den Schlüsselpaaren: Für Protokoll 1 (RSA1) ~/.ssh/identity und ~/.ssh/identity.pub, für Protokoll 2 (RSA, DSA) ~/.ssh/id_{rsa,dsa} und ~/.ssh/id_{rsa,dsa}.pub.

Die *.pub-Dateien können nun auf den Zielhost kopiert werden und dort an ~/.ssh/authorized_keys angehängt werden:

        $ ssh-copy-id user@remote-system
        $ ssh-copy-id -i ~/.ssh/id_rsa.pub user@remote-system
        $ ssh-copy-id -i ~/.ssh/id_dsa.pub user@remote-system
Oder, wenn ssh-copy-id nicht vorhanden ist:
        $ cat ~/.ssh/*.pub | ssh user@remote-system 'umask 077; cat >>.ssh/authorized_keys'

Sonst ist das andere Theater witzlos.

Nutzt man nun slogin, ssh, oder scp, will der Server auf der anderen Seite den Beweis, daß man zu einem der dort in der authorized_keys liegenden öffentlichen Schlüssel den privaten Teil hat.

Der lokale Client verlangt also nach der Passphrase, um den (lokal in id_{dsa,rsa}) gespeicherten privaten Schlüssel zu "aktivieren".

Passen beide Schlüssel zusammen, ist der Server davon überzeugt, daß wir einer derjenigen sind, die Zugang erhalten sollen.

Um das beständige Nachfragen nach der Passphrase zu unterdrücken, ist es möglich, einen ssh-agent beim Login zu starten. Dieser Agent bekommt die Passphrase übergeben, kann den privaten Schlüssel aktivieren und in Zukunft alle Fragen nach diesem Schlüssel stellvertretend beantworten.

Für normale Konsolen-Logins geht das etwa so: (in der .profile oder wie immer die heißt) -- meine Login-Shell ist eine Bash.

      test "$SSH_AUTH_SOCK" || exec ssh-agent $SHELL -c "ssh-add; exec $SHELL -login"

Für X11-Nutzer: in meiner .xsession findet sich z.B. folgendes:

	test "$SSH_AUTH_SOCK" || exec ssh-agent $SHELL -c "ssh-add </dev/null; exec fvwm2"
	exec fvwm2

(Achtung, SuSE: Offenbar wird bei SuSE (9.2) nach dem Anmelden am KDM schon irgendwo eine login-Shell gestartet, oder wenigstens wird die ~/.profile (oder ~/.bash_profile oder ~/.bash_login) abgearbeitet, mit dem Effekt, dass der Key erfragt wird und anschließend der ganze xinit-Prozess durcheinander kommt. Dort habe ich ein if test -z "$DISPLAY"; then ... um diese Zeilen, damit sie eben nur aktiv send, wenn es nicht als Teil der X11-Initialisierung getan wird.

Natürlich gibt's noch die "classic-Variante" mit eval `ssh-agent` und einem anschließenden ssh-add. Aber es bleiben dann Probleme beim Killen der nach Sessionende übrigbleibenden Agents.

Immer noch Probleme?

Nun kann es sein, daß es trotzdem noch nicht paßwortfrei funktionert, was könnte alles geprüft werden?

Erzwingen der Verwendung von Schlüsseln

Wenn das jetzt alles so schön funktioniert, wollen wir ja auch die Anmeldung mit den Schlüsseln erzwingen. Wenn es nur den Root-Account betrifft, ist das relativ einfach:
    # /etc/ssh/sshd_config
    ...
    PermitRootLogin without-password
    ...
Wenn auch andere Nutzer von der Schlüsselnutzung überzeugt werden sollen, dann sieht es etwas komplexer aus:
    # /etc/ssh/sshd_config
    ...
    PasswordAuthentication no
    ChallengeResponseAuthentication no
    UsePAM yes
    ...
Wenn eine schlüsselfreie Anmeldung erkannt wird, versucht die SSH zuerst, PAM zu nutzen (UsePAM und ChallengeResponseAuthentication), zu erkennen am Passwort-Prompt Password:. Wenn das nicht funktioniert, versucht die SSH anschließend noch mal selbst, das Passwort zu prüfen (PasswordAuthentication), der Passwort-Prompt ändert sich zu user@host's password:. PAM auszuschalten wäre auch möglicht, ist aber nicht nützlich, weil dann z.B. Session-Management über PAM nicht mehr funktioniert, einige Umgebungsvariablen nicht gesetzt werden usw. usf. Waren die oben angegebenen Manipulationen erfolgreich, so darf keinesfalls nach einem Passwort, sondern nur nach einer Passphrase (das ist dann die für den privaten Schlüssel) gefragt werden. Natürlich muss für derlei Versuche der SSH-Agent ausgeschaltet, oder wenigstens "gelähmt" sein (ssh-add -x).

Ist das alles?

Nein, natürlich nicht. Wenn nun mehrere Leute auf den den selben Account (z.B. root) einer Maschine zugreifen müssen und es sollen noch personenspezifische Dinge (History, Begrüßung, ... ) in z.B. der .bash_profile veranstaltet werden, dann gibt es eine ziemlich clevere Lösung:

An den Anfang der dem Nutzer entsprechenden Zeile in .ssh/authorized_keys wird eine Option eingetragen. Diese Zeile sieht dann etwa so aus:

enviroment="REMOTE_USER=heinz" 1024 37 1452609839509....
Diese Umgebungsvariable läßt sich dann prima auswerten und alles andere muß vielleicht nicht mehr erklärt werden ;-) (Übrigens: in der Manualseite zum sshd steht das alles beschrieben.)

Achtung: Bei neueren SSH (was ist neu? Neuer als 3.4) muß in der Konfiguration extra erlaubt werden, daß Environment-Variablen gesetzt werden dürfen. Sosnt werden die betroffenen Zeilen der authorized_keys einfach ignoriert. Die entsprechende Option heißt PermitUserEnvironment.

Vielen Dank an: Arthur Vollmer, Marcel Lauber und Axel Freund für Ergänzungen bzw. Korrekturen.