ssh, das sichere Tool zur Herstellung einer Verbindung zu einem (Unix-/Linux-) Server, kennt jeder, der einen Server administieren muss. Aber die wirklichen Möglichkeiten dieses Allround Werkzeugs zeigen sich erst, wenn man sich damit eingehend beschäftigt. Hier mal die Erkenntnisse, die ich bisher gesammelt habe.
ssh -p 921 -L 1234:server2:80 -L 3210:server3:3128 -D 3129 username@server1.example.com
Dieser kryptische Befehl fließt nicht jedem flüssig aus der Feder. Ein besseres Verständnis hat man, wenn man in der Datei .ssh/config die entsprechenden Einträge macht. Sehen wir uns das Ganze mal aus der Nähe an:
Host server1 HostName server1.example.com Port 921 User username DynamicForward 3129 LocalForward 1234 server2:80 LocalForward 3210 server:3128
So sieht es lesbarer aus und der Befehl
ssh server1
reicht nun aus um denselben Effekt zu erzielen. Wir wollen jetzt noch nicht versuchen, das Ganze im Detail zu verstehen, bekommen aber einen Eindruck davon, warum die Pflege einer Konfigurationsdatei für ssh Aufrufe sinnvoll ist. Alle weiteren Tipps zu ssh werde ich als Command und als Eintrag in der .ssh/config beschreiben.
PuTTY wird oft als das Tool der Wahl genannt, sobald von einem ssh client unter Windows die Rede ist. Dummerweise sind die meisten Tricks mit PuTTY ebenfalls möglich, man kann sie aber nicht im Internet finden. Viel besser sieht da die Recherche nach ssh Möglichkeiten aus, die man dann mühsam auf PuTTY übertragen muss. PuTTY ist ein ssh Client mit Terminal Emulation, openssh-client ist nur ein ssh client ohne eine Terminalemulation.
Unter Windows verwende ich ausschliesslich (Uups, eine Ausnahme gibt es) Cygwin um ssh Verbindungen zu nutzen. Über openssh hinaus ermöglicht mir Cygwin unter Windows die Benutzung der ach so hilfreichen Unix Tools. Natürlich liefert Cygwin die Terminalemulation frei Haus. Da openssh unter Cygwin wesentlich besser gepflegt wird, stehen mir neue Funktionalitäten schneller zu Verfügung.
Ergebnis: Ich benutze openssh (das Original) und nicht PuTTY.
ssh -l user server.example.com # oder anders ssh user@server.example.com
Beide Befehle sind identisch, openssh ermöglicht einen Login des Benutzers „user“ auf dem Server „server.example.com“. Der entsprechende Eintrag in der .ssh/config lautet.
Host server.example.com User user
Nach der Eingabe von
ssh server.example.com
wird man freundlich nach dem Passwort gefragt.
Natürlich muss der Benutzer sich ausweisen, dafür ist aber nicht unbedingt ein Passwort erforderlich. Ein SSH Key (eine Art Ausweis) reicht auch aus, muss aber erstmal angelegt werden. Ich empfehle DRINGEND den Schlüssel mit einem Passwort („passphrase“) geschützt wird. Eine Benutzung des SSH Keys ist dann nur möglich, wenn man das Passwort eingegeben hat. Die Generierung eines solchen SSH Keys geschieht mit dem Befehl:
ssh-keygen -t rsa -b 2048 -f <dateiname>
Lässt man „-f <dateiname>“ weg, wird eine Datei Namens „id_rsa“ angelegt.
ssh-keygen -t rsa -b 2048 -f /tmp/rsakey Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /tmp/rsakey. Your public key has been saved in /tmp/rsakey.pub. The key fingerprint is: SHA256:QNdA4hMYyLtz+Z5PZdgxxa2lRZSmygYf1xZQLz8SX1I beckhart@DESKTOP-JMK2FGP The key's randomart image is: +---[RSA 2048]----+ | . ..o+.+o .o*+.E| | o .o + ... Bo | | . + o Xo.o| | . o.o.o= =+.| | . . S+++ o o.| | o o o= . .| | o . .. | | .o | | .o.. | +----[SHA256]-----+
Zur Sicherheit besteht der Schlüssel aus zwie Teilen, einem öffentlichen, der zur Verschlüsselung dient, und einem privaten Teil, der der Entschlüsselung dient. Der obige Befehl hat zwei Dateien angelegt, „/tmp/rsakey“ (der private Teil) und /tmp/rsakey.pub (der öffentliche Teil). Die beiden Teile werden Public Key und Private Key genannt.
Um sich zu authentifizieren muss auf dem Server der Public Key und auf dem Client der Private Key „eingetragen“ sein. Auf dem Client gehört die Datei nach ~/.ssh/id_rsa. Die Datei darf nur für den Benutzer lesbar sein, genau wie das ~/.ssh Verzeichnis auch. Der Public Key darf von jedermann (daher öffentlich) gelesen werden.
mv /tmp/rsakey* ~/.ssh ls -ld / /home/ /home/user/ /home/user/.ssh /home/user/.ssh/rsa* drwxr-xr-x 32 root system 4096 Jul 17 15:49 / drwxr-xr-x 261 bin bin 16384 Sep 11 00:55 /home drwxr-xr-x 14 user gruppe 4096 Sep 18 14:23 /home/user drwx------ 3 user gruppe 4096 Sep 08 12:23 /home/user/.ssh -rw------- 1 user gruppe 1679 Aug 30 2016 /home/user/.ssh/rsakey -rw-r--r-- 1 user gruppe 1679 Aug 30 2016 /home/user/.ssh/rsakey.pub
Damit haben wir auf der Client Seite erstmal alles erledigt und können nun der Public Key auf den Server packen. Die einfachste Methde ist der folgende (siehe unsere .ssh/config) Befehl
ssh-copy-id -i /home/user/.ssh/rsakey.pub server.example.com
Dabei wird, letztmalig, das Passwort des Benutzers „user“ auf dem Server abgefragt. Jetzt passen wir noch die .ssh/config an, weil unsere Datei nicht „id_rsa“ (einer der Default Werte) heißt.
Host server1 HostName server1.example.com Port 921 User username DynamicForward 3129 LocalForward 1234 server2:80 LocalForward 3210 server:3128 IdentityFile ~/.ssh/rsakey
Damit haben wir die Passwort Abrage des Servers deaktiviert und müssen nun die Passphrase des SSH Keys eingeben. Damit haben wir aber leider nur die eine Passwortabfrage durch eine andere ersetzt.
Die openssh Entwickler sind anscheinend ziemlich faule Gesellen. Im Paket openssh befindet sich auch ein Agent, der die Aufgabe hat sich die SSH Keys im RAM zu merken und bei Bedarf zur Verfügung zu stellen. Die Ablage im RAM erfolgt natürlich nach allen Regeln der Sicherheit. Unter Linux (auch Cygwin) wird der Agent folgendermaßen benutzt:
ssh-agent SSH_AUTH_SOCK=/tmp/ssh-YYMhp1JPZkWu/agent.25166028; export SSH_AUTH_SOCK; SSH_AGENT_PID=10682402; export SSH_AGENT_PID; echo Agent pid 10682402;
Damit ist der Agent gestartet und die Befehle, die eine Benutzung ermöglichen, werden ausgegeben. Der Agent bleibt bis zum nächsten Reboot aktiv, also können wir die Befehle in eine Datei schreiben und dann in der aktuellen Shell ausführen. Nennen wir die Datei ~/ssh-agent-vars.sh und füllen sie mit Inhalt. Anschliessend führen wir sie in der aktuellen Shell aus.
SSH_AUTH_SOCK=/tmp/ssh-YYMhp1JPZkWu/agent.25166028; export SSH_AUTH_SOCK; SSH_AGENT_PID=10682402; export SSH_AGENT_PID; echo Agent pid 10682402;
Und nun die Ausführung, der Punkt am Anfang signalisiert, das das Script in der aktuellen Shell ausgeführt wird:
. ~/ssh-agent-vars.sh
Nachdem der Agent gestartet wurde und die Benutzung eingerichtet ist, müssen wir nun dem Agenten den Private Key zur Verfügung stellen
ssh-add ~/.ssh/rsakey
Der Agent fordert uns auf die Passphrase einzugeben und kann nun die Aufgabe, den Private Key bei Bedarf zur Verfügung zu stellen, übernehmen. Die Anmeldung kann nun ohne jede Passwort Abfrage gemacht werden.
ssh server.example.com
Geschafft. die Passworteingabe ist ab nun nicht mehr erforderlich. Wir müssen nur nach einen Reboot daran denken den Agenten erneut zu starten und die ausgegebenen Befehle in die Datei ~/ssh-agent-vars.sh zu schreiben. Auch der Private Key muss einmalig wieder geladen werden.
Wenn wir eine neue Shell starten muss natürlich auch hier die ~/ssh-agent-vars.sh in der aktuellen Shell ausgeführt werden. Man kann dies in der ~/.bashrc hinterlegen.
Hinweis: wer PuTTY und openssh unter Cygwin parallel benutzt sollte sich die Benutzung von PAGEANT (PuTTY) und die Zusammenarbeit mit ssh-pageant (openssh unter Cygwin) anschauen. Hier ein Link zum Einstieg
Oft findet man eine ganze Serverlandschaft, auf der man sich anmelden kann. Wenn man erst einmal den öffentlichen Teil des SSH Keys auf allen Servern hinterlegt hat, kann man sich vom Client aus auf jedem Server ohne weiteres Passwort anmelden. Wenn man nun aber von einem zum anderen Server springen will, wird man wieder nach dem Passwort gefragt, denn der Agent läuft ja nur auf unserem Client. Eine unverzeihliche Sünde ist es nun den Private Key auf die Server in der Domain example.com zu kopieren.
Ein Private Key darf den Client NIEMALS verlassen.
Natürlich hat openssh hier eine Lösung parat, denn der ssh-agent kann noch mehr. Der Private Key kann in einer ganze Kette aufeinander folgende SSH Sessions benutzt werden. Der Schalter „-A“ sorgt dafür, das der Private Key durch alle ssh Instanzen weiter gereicht wird:
client: ssh -A server.example.com server.example.com: ssh server2.example.com
Auch der auf „server.example.com“ abgesetzte ssh Befehl erforder kein Passwort, der ssh-agent befriedigt die Anfrage des Private Keys problemlos, sofern mittels „ssh-copy-id“ der öffentliche Schlüssel auf server2.example.com bereitgestellt wurde. Die Entsprechung in der .ssh/config lautet
host * ForwardAgent yes
Und wieder etwas gelernt, man kann für die Definitionen in der .ssh/config Wildcards („*“ und „?“) verwenden. Aber Achtung: Es werden alle Definitionen in allen Gruppen angewendet, auf die die Wildcards zutreffen.
Was ist damit gemeint? Auf server.example.com läuft ein WebServer, der aus dem Internet nicht erreichbar ist, den wir aber auf unserem Client ansprechen wollen. Ein WebServer wird auf Port 80 (unverschlüsselt) oder 443 (verschlüsselt) angesprochen. Dieser Port wird aber von einer Firewall geblockt. Die Lösung lautet: Port Forwarding, was mit openssh kein Problem ist.
ssh -L 1234:localhost:443 server.example.com
Was will uns der Dichter damit sagen? Die SSH Session wird überredet, auf dem Client den Port 1234 zu öffnen und jeglichen Traffic auf diesem Port an den Port 443 auf server.example.com („localhost“, aus dessen Sicht) weiterzuleiten. Im Browser reicht nun die Eingabe von
https://localhost:1234
um den Webserver zu erreichen.
Der Eintrag in der .ssh/config lautet
LocalForward 1234 localhost:443
Verwirrend? Das liegt an der Doppelnutzung von „localhost“. Dieser Rechnername „localhost“ bezieht sich immer auf den Rechner, auf dem er interpretiert wird. In dem SSH Command wird „localhost“ aus Sicht von „server.example.com“ interpretiert, im Browser, der ja auf dem Client läuft, wird es natürlich als „Client“ interpretiert.
Aber in der Serverlandschaft hinter server.example.com laufen mehrere WebServer, für jeden einzelnen ein Port Forwarding einzurichten ist wohl ein wenig aufwendig. Aber natürlich hat openssh alles zur Hand. Wir richten uns einfach einen Socks Proxy ein, den wir im Browser eintragen und schon stehen alle WebServer mit einem einzigen Eintrag im SSH Command zur Verfügung.
ssh -D 3128 server.example.com
Wie immer was es das schon. Nur noch im Browse die Proxy Einstellungen einstellen und die alle Webserver, die server.example.com erreichen kann, stehen zur Verfügung. Unschön ist das Verhalten, wenn man Namen statt IP-Adressen benutzt. Normalerweise sprechen wir Webseiten nach dem Schema <hostname>.<domain> (z.B. www.google.de) an. Der DNS nimmt uns die Arbeit ab, die Namen in IP Adressen zu übersetzen. Da das DNS Protokoll auf UDP basiert, ssh aber nur TCP zur Verfügung stellt, müssen die Namen entweder im öffentlichen DNS auflösbar sein oder in der lokalen Hosts Datei gepflegt sein.
Ach ja, wie sieht denn der Eintrag in der .ssh/config aus?
DynamicForward 3128
# Ersteinmal die Einstellungen, die für alle Rechner gelten sollen Host * # ssh-agent soll die private Keys zur Verfügung stellen ForwardAgent yes # Bei Ungereimtheiten mit Host Keys wollen wir gefragt werden StrictHostKeyChecking ask # den Wert mancher Variablen wollen wir mitschleppen, hier diejenigen, # die sich auf die Sprachumgebung beziehen SendEnv LANG LC_* # Wo steht nochmal unser Private Key? IdentityFile ~/.ssh/rsakey # Nun zu Server.example.com # Da die für alle Hosts geltenden Einstellungen hier ebenfalls gültig sind, brauchen wir nur # anzugeben, was sich ändert oder was hinzukommt Host Server.example.com # wie lautet unser Benutzename User user # unser netter Socks 5 Proxy DynamicForward 3128 # Der lokale Forward um den Webserver auf server.example.com zu erreichen # ist ja eigentlich unnötig, denn wir haben ja einen Dynamic Forward LocalForward 1234 localhost:443 # Hier mal ein Beispiel für mehrere Server Host *.example.com User user
Die Grundlagen sind gelegt und die meisten Fragen beantwortet. Weitergehende HowTo's zu SSH folgen….