Kurzvorstellung des Programms OpenSSH
Vorwort
Der Vortrag am 11. Oktober 2007 war mit dem Ziel gesetzt, sowohl interessante und kreative Anwendungen von OpenSSH als auch einen Einstieg und kleine Hilfen für Anfänger zu bieten. Dabei wurden jedoch grundlegende Kenntnisse über die Kommandozeile vorausgesetzt.
Der Anfang – Neu bei SSH
Schlüssel erzeugen
Bei der Arbeit mir SSH ist es sehr sinnvoll mit Schlüsseln zu arbeiten. Ein SSH‐Schlüssel ist wie ein PGP‐Schlüssel ein Paar, bestehend aus einem öffentlichen und einem privaten Teil. Den öffentlichen Teil hinterlegt man bei den Servern, bei denen man sich anmelden will, und der private Teil wird für die Anmeldung verwendet.
Die Verwendung eines Schlüssels hat den Vorteil, dass man sich das Passwort für den Login nicht merken bzw. nicht immer eingeben muss, was bei Tab‐Completion sonst sehr nervend ist, und ein Schlüssel wird in der Regel auch als sicherer angesehen, weil dieser bei einem Brute‐Force‐Angriff nicht so leicht erraten werden kann, wie ein Passwort – einige Server erlauben z. B. nur die Authentisierung per Schlüssel.
Für OpenSSH erzeugt man sich das Schlüsselpaar mit ssh-keygen. Dabei kann man ein Passwort zur Verschlüsselung des privaten Schlüsselteils angeben, damit dieser bei einem Diebstahl nicht zu leicht missbraucht werden kann. Sonst gibt es zur Erzeugung des Schlüssels nichts Besonderes zu sagen.
Den Schlüssel verteilen
Wenn man sich mit dem Schlüssel bei einem entfernten Rechner authentifiziern will, muss man den öffentlich Teil des Schlüsselpaars erst bei dem entfernten Rechner bekannt machen. Dies geht am einfachsten mit ssh-copy-id.
Durch den Aufruf ssh-copy-id -i Ziel wird eine Verbindung zu dem Rechner Ziel aufgebaut – man muss sich also nochmal mit dem Passwort anmelden – und der Schlüssel in die Datei ~/.ssh/authorized_keys eingetragen. Danach kann man sich einfach per ssh Ziel an dem entfernten Rechner anmelden, ohne dass man sein Passwort eingeben muss.
Alte Bekannte wiedererkennen
Indem der entfernte Rechner, bei dem man sich anmelden will, vor der Anmeldung dazu aufgefordert wird, sich selbst erst einmal zu authentisieren, sollten sogenannte Man‐In‐The‐Middle‐Angriffe ausgeschlossen werden. Dazu verwendet der Server ebenfalls ein Schlüsselpaar, bestehend aus einem öffentlichen und einem privaten Teil. Für eine sichere Authenfizierung sollte, wie bei jedem anderen Public‐Privat‐Key‐Verfahren, der öffentliche Schlüsselteil vorher auf sicherem Weg – z. B. mittels Fingerprint – geprüft werden.
Ist der öffentliche Teil eines Server‐Schlüssels noch nicht bekannt, meldet SSH dies beim ersten Anmeldeversuch und gibt den Fingerprint des entfernten Rechners aus. Wenn man diesen akzeptiert, wird der öffentliche Schlüsselteil in der Datei ~/.ssh/known_hosts vermerkt.
Um später zu erzwingen, dass es sich immer noch um den gleichen Rechner handelt, sollte man die Option StrictHostKeyChecking yes in seiner Konfiguration (~/.ssh/config) setzen, damit bei jedem erneuten Verbindungsaufbau sichergestellt wird, dass kein Fremder in der Leitung sitzt. Einen abweichenden Schlüssel würde SSH zwar auch bei no mit einer riesigen Warnung melden, aber wenn die Ausgabe, wie der Weiterleitung eines X‐Programms, gar nicht sichtbar ist, wird die Verbindung zu einem Angreifer aufgebaut. Mit StrictHostKeyChecking yes wird der Verbindungsaufbau abgebrochen und man kann entsprechend reagieren.
Neue Bekanntschaften trotz strenger Vorgaben schließen
Durch StrictHostKeyChecking yes wird jedoch auch der Verbindungsaufbau zu einem unterbekannten Rechner unterbunden. Dafür kann man die Option kurzzeitig von der Kommandozeile aus mit -o StrictHostKeyChecking=no deaktivieren oder man besorgt sich mit ssh-keyscan -t rsa -H Ziel den öffentlichen Schlüsselteil und trägt diesen per Hand in die Datei ~/.ssh/known_hosts ein.
Wen kenne ich denn? – Hashs in known_hosts
Unter Debian z. B. haben sich die Paketverwalter von OpenSSH dazu entschlossen, die Option HashKnownHosts in der ssh_config zu aktivieren. Damit werden nicht mehr die Namen der Rechner in der Datei known_hosts gespeichert, sondern nur ein Hash. Dies soll verhindern, dass ein Angreifer, der Zugriff zum lokalen System erlangt hat, über die known_hosts erfährt, auf welche weiteren Systeme er sich mit Hilfe des SSH‐Schlüssels noch ausbreiten kann.
Jedoch schränkt diese Maßnahme z. B. die Tabcompletion ein und in der known_hosts kann man nicht mehr erkennen, für welche Rechner es überhaupt alles Einträge gibt. Es ist also eine Abwägung zwischen Paranoia und Bequemlichkeit zu machen – wie immer.
Was macht man jetzt damit? – Kreativer Einsatz von SSH
Ich will hier nur ein paar (teilweise ungewöhnliche) Einsatzmöglichkeiten von SSH aufzählen, um einen Eindruck (und Ideen) zu vermitteln, was man alles mit SSH anstellen kann.
X‐Forward
Eine sehr sinnvolle Verwendung von SSH ist die Weiterleitung der Kommunikation des X‐Servers. Anstatt mit xhost + ein riesiges Sicherheitsloch aufzureißen, kann man per ssh -X Ziel Programm ein X‐Programm auf einem entfernten Rechner starten und sich die Ausgabe auf dem lokalen Bildschirm anzeigen lassen.
Dies kann beispielsweise ein einfacher XTerm oder z. B. Matlab sein – weil es vielleicht lokal nicht installiert ist. Aber man kann nicht nur einfache Programme auf diese Weise umleiten, sondern ganze X‐Sitzungen. Wenn z. B. auf Rechner1 das Angebot an Programmen schlecht ist oder das System prinzipell schlecht gepflegt ist, man aber an dem Rechner arbeiten muss, weil in dem Raum die Vorlesung stattfindet, kann man den Rechner einfach als Termin missbrauchen und startet nicht den lokalen (Desktop‐ oder) Window‐Manager, sondern per ssh -X Rechner2 x-window-manager den Window‐Manager auf dem besser gepflegten System Rechner2.
sendmail umbiegen
Wer vielleicht dazu gezwungen ist, seine E‐Mails über einen bestimmten Server zu versenden, kann sich ebenfalls SSH zu nutze mache. SSH leitet die Standardein‐ und ‐ausgabe für gestartete Programme weiter. So kann man also z. B. in mutt als sendmail‐Befehl ssh Ziel /usr/sbin/sendmail -oem -oi angeben und kann weiterhin seine E‐Mail lokal mit mutt schreiben, aber sie werden auf dem entfernten Rechner Ziel zur Auslieferung abgegeben. So könnte man z. B. eine Firewall umgehen oder einen Rechner erreichen, der sonst nicht auf normalem Wege erreichbar ist.
Das gleiche Schema kann man verwenden, wenn man am lokalen Rechner keinen Drucker angeschlosen hat und der Drucker an einem anderen Rechner nicht übers Netz verfügbar ist. Einfach das Kommando lp durch einen SSH‐Aufruf geschickt weiterleiten und schon klappts auch mit dem Drucker vom Nachbarn.
Kopieren, aber sicher
Man kann mit SSH auch komfortabel Dateien übertragen. Dazu sind die Programme scp und sftp gedacht. scp kann man wie den normalen Befehl cp verwenden, nur dass man bei einer der Datei den Rechnernamen voranstellt und durch einen Doppelpunkt trennt. Wenn man z. B. die Zsh verwendet und sich einen SSH‐Schlüssel eingerichtet hat, kann man auch wunderbar mit Tabcompletion arbeiten.
Mit scp RECHNER:/bin/ls /tmp kopiert man die Datei /bin/ls vom entfernten Rechner in das lokale Verzeichnis /tmp. Durch die Option -r kann man auch ganze Verzeichnisse übertragen; scp -r RECHNER:/bin /tmp.
Probleme mit SSH
Bei Problemen mit SSH ist es oft sehr hilfreich, die Option -vvv (oder nur -vv) zu setzen. Dann rast an einem zwar eine riesige Flut von Meldungen vorbei, aber wenn man sich langsam durcharbeitet, findet man oft die Stelle, an der es schief geht.
Programme, die ein Terminal brauchen
Manchmal will man direkt per SSH ein Programm starten und nicht erst am entfernten Prompt. Viele Programme, z. B. top, screen und ssh selbst, benötigten aber ein (Pseudo‐)Terminal für die Ausgabe.
% ssh RECHNER top TERM environment variable not set. % ssh RECHNER screen Must be connected to a terminal. % ssh RECHNER1 ssh RECHNER2 Pseudo-terminal will not be allocated because stdin is not a terminal.
Wenn SSH eine Befehl mitgeschickt wird, erzeugt es auf der Gegenseite kein (Pseudo‐)Terminal, sondern öffnet die Standardein‐ und ‐ausgabe nur als einfache Datei. Wenn SSH ein (Pseudo‐)Terminal öffnen soll, muss man dies ihm explizit mit der Option -t sagen.
% ssh -t RECHNER screen ... % ssh -t RECHNER1 ssh RECHNER2 ...
Für das Ausführen eines Befehls, der kein Terminal benötigt, auf einem zweiten Rechner ist auch kein Terminal auf dem ersten Rechner notwendig.
% ssh RECHNER1 ssh RECHNER2 pwd /home/joerg
Der Fluch von Unicode – oder doch nicht?
Im Zusammenhang mit SSH wird oft über Unicode geschimpft, weil man sich von einem Nicht‐Unicode‐System zu einem Unicode‐System verbindet oder umgekehrt und dann funktioniert die Ausgabe nicht mehr.
SSH bietet eine sehr gute Möglichkeit, dieses Problem zu beheben, indem für die Kodierung relevante Umgebungsvariablen übertragen werden können. Dann wissen die Programme auf dem Server, welche Bytes sie dem Terminal des Clients schicken müssen oder von ihm zu erwarten haben, um Zeichen außerhalb des ASCII-Zeichensatzes darstellen oder zu lesen.
Auf der einen Seite muss der Client dafür in seiner Konfiguration die Option SendEnv LANG LC_* stehen haben (und zwar innerhalb eines Host-Abschnitts), zum anderen ist dafür ein Eingriff in die Konfiguration des Servers notwendig: In der Datei sshd_config muss man die Option AcceptEnv LANG LC_* eintragen.
Auf dem Server ist zusätzlich zu beachten, die Werte der Variablen nicht durch PAM oder die Shell zu überschreiben. Sie sollten also nicht in ~/.profile, /etc/environment oder ähnlichen Dateien gesetzt werden. Unter Debian liest PAM zudem noch /etc/default/locale aus.
Unterwegs im Tunnel
SSH im Tunnel
Wenn man mit SSH keine direkte Verbindung aufbauen kann, weil z. B. eine Firewall den Verbindungsaufbau blockiert, kann man mit OpenSSH die Aufgabe des Verbindungsaufbaus einen anderen Programm überlassen.
Eine denkbare Situation wäre ein schlecht konfigurierter Proxy, der https‐Verbindungen zu jedem beliebigen Port zulässt. Da der Datenstrom einer https‐Verbindung nicht kontrolliert werden kann, werden die Daten nur durchgereicht, was die Möglichkeit eröffnet, die SSH‐Verbindung durch den Proxy zu leiten. Falls der Proxy‐Server nur Verbindungen zum Port 443 zulässt, kann man natürlich auch den SSH‐Server auf diesem Port lauschen lassen.
Ein Programm, dass den https‐Verbindungsaufbau vornimmt und dann die Standardein‐ und ‐ausgabe auf die Verbindung umleitet ist corkscrew. Dieses kann man in der ssh_config mit der Option ProxyCommand corkscrew PROXY PROXYPORT %h %p als Programm für den Verbindungsaufbau eingestellt werden. %h und %p sind Platzhalter für den Zielrechner und den Zielport. Die Regel kann also auch allgemein für viele Ziele verwendet werden.
Genauso kann auch das Problem gelöst werden, wenn man auf einen Rechner Z nur über einen Rechner M zugreifen kann, weil zwischen dem Startrechner S und dem Zielrechner Z eine Firewall den Verkehr blockiert, zwischen M und Z aber nicht.
Dafür muss auf dem Rechner in der Mitte das Programm nc oder ein ähnliches vorhanden sein. Durch die Einstellung ProxyCommand ssh M nc Z 22 in der ssh_config wird für den Verbindungsaufbau zum Rechner Z eine SSH‐Verbindung zum Rechner M aufgebaut und dort das Programm nc gestartet, welches die Ein‐ und Ausgaben von SSH an den eigentlichen Rechner Z weiterleitet.
Port‐forwarding
SSH bietet auch die Möglichkeit, Verbindungen von anderen Rechnern aus zu eröffnen. Wenn man z. B. auf bestimmte Seiten des Firmen‐Web‐Servers nur aus dem Firmennetzwerk zugreifen kann, ist es mit SSH möglich, die Verbindung zum Web‐Server von einem Rechner im Firmennetzwerk aus aufzubauen.
Mit ssh -L localhost:8000:Web-Server:80 Firmenrechner öffnet SSH am localhost den Port 8000. Alle Verbindungen, die zu diesem Port aufgebaut werden, leitet es dann an den Rechner Firmenrechner weiter, von dem aus der Rechner Web-Server auf dem Port 80 angesprochen wird. Für den Web‐Server sieht es so aus, als käme die Anfrage aus dem dortigen Netzwerk, wenn man mit dem Web‐Browser auf localhost:8080 zugreift.
Auf diese Weise kann man aber immer nur die Verbindung zu einem bestimmten Port an einem bestimmten Rechner umleiten. Will man auf das ganze Web zugreifen, kann man den Weg über den Web‐Proxy in der Firma gehen. Mit ssh -L localhost:8080:Proxy-Server:8080 Firmenrechner öffnet man den Tunnel zum Proxy‐Server. Wenn man dann dem Browser sagt, dass er unter localhost:8080 einen Proxy‐Server findet, kann man darüber auch das gesamte Web erreichen.
Socks‐Proxy
OpenSSH kennt aber auch die Möglichkeit des Socks‐Proxys. Über das SOCKS 4‐ bzw. SOCKS 5‐Protokoll kann der Browser SSH direkt mitteilen, welchen Rechner er gern sprechen möchte. Auf diese Weise ist man auf einen Web‐Proxy, wie beim Port‐forwarding, nicht angewiesen.
Mit ssh -D localhost:8000 Rechner öffnet SSH den Port 8000 am localhost. Im Browser muss man dann einstellen, dass sich dort ein SOCKS‐Proxy (das ist kein normaler Proxy!) befindet und schon liegt einem die Welt, die man von Rechner aus sehen kann, zu Füßen.
Für eine angenehmere Verbindung
[…]
Herr und Meister! Hör' mich rufen! […]
Das SSH‐Protokoll ermöglicht es, in einer TCP‐Verbindung mehrere SSH‐Verbindungen zu betreiben. Man kann es sich in etwa so vorstellen, wie ein Glasfaserkabel (= TCP‐Verbindung) mehrere Adern (= SSH‐Verbindungen) haben kann. Der Vorteil ist der, dass der TCP‐Verbindungsaufbau und die Anmeldung – Passworteingabe oder Schlüsselabgleich – nur einmal geschehen muss. Bei kleinen Vorgängen – z. B. Tabcompletion – macht sich dies auch bei sehr schnellen Verbindungen bemerkbar.
Um dieses Verbindungs‐Multiplexing zu verwenden, muss man eine SSH‐Verbindung als Hauptverbindung öffnen. Diese bildet den Kanal, in dem alle SSH‐Teilverbindungen laufen. Dieser SSH‐Prozess ist der Master für den Kanal und erzeugt einen Unix‐Socket, über den sich die Slaves bei ihm melden können, wenn sie an dem Kanal teilnehmen wollen. Die beiden Optionen in der Konfiguration dafür lauten:
Host *
ControlMaster auto
ControlPath ~/.ssh/socket_%h
Damit wird zuerst nach dem Socket ~/.ssh/socket_%h – %h wird durch den Rechnernamen ersetzt – gesucht. Existiert dieser bereits, wird darüber der Master kontaktiert, im anderen Fall übernimmt der aktuelle Prozess die Aufgabe des Masters.
Welche Verbindungen alle in einem SSH‐Kanal laufen werden, kann man sich in der Hauptverbindung mit ~# anzeigen lassen. (OpenSSH beachtet den Escape‐Character ~ nur nach einem Zeilenumbruch. Also am Besten vorher Enter drücken, sofern dies das Programm auf der anderen Seite nicht verwirrt.)
Einen Nachteil hat das Ganze aber: Man kann für eine SSH‐Teilverbindung nie mehr bekommen, als die gesamte Verbindung kann. Eine Verbindung, die über einen Master‐Prozess aufgebaut wird, kann z. B. kein X‐Forwarding verwenden, wenn es nicht bereits für die Hauptverbindung aktiviert ist, oder den Verschlüsselungsalgorithmus wechseln. Dafür muss man eine komplett neue Verbindung – mit Authentisierung und allem Drum und Dran – aufbauen. Wenn bereits eine Masterverbindung besteht kann man dies mit der Kommandooption -o ControlMaster=no erzwingen.
Chip‐Tuning für mehr Leistung
Sicherheit, sprich die Verschlüsselung, hat auch ihren Preis. Auf leistungsschwachen Systemen kann es sich daher lohnen, einen anderen Verschlüsselungsalgorithmus zu verwenden, der weniger rechenintensiv ist. Für die Protokollversion 1 war es sogar möglich, die Verschlüsselung ganz zu deaktivieren und so aus ssh ein rsh zu machen.
Durch ein bisschen Probieren habe ich herausgefunden, dass ich mit dem Verschlüsselungsalgorithmus arcfour fast doppelt so viel Daten pro Sekunde übertragen kann wie mit dem Standardalgorithmus aes128-cbc. Zur Sicherheit dieses Algorithmus' kann ich jedoch nichts sagen, aber da ich ihn nur im lokalen Netzwerk einsetze, sehe ich diese Änderung als unbedenklich an.
Aber auch mit dem als sicher geltenden Algorithmus blowfish-cbc erreiche ich einen höheren Datendurchsatz als mit dem Standardalgorithmus. Daher verwende ich ihn als Standardalgorithmus.
Auch die Komprimierung ist entscheidend. Selbst bei meinem iBook G4 800 MHz entsteht bei der Komprimierung der Daten (Compression=yes) eine merklich höhere CPU‐Belastung und auch die Datenrate geht spürbar zurück. Daher sollte man bei schnellen Datenverbindungen unbedingt die Komprimierung deaktivieren.
Host lokalerRechner
Ciphers arcfour,arcfour128,blowfish-cbc,aes128-cbc,cast128-cbc
Compression no
Host *
Ciphers blowfish-cbc,aes128-cbc,cast128-cbc,arcfour128,arcfour
In der Konfiguration unterwegs
Beliebige Namen für Konfigurationen
Immer den vollständigen Rechnernahmen einzutippen, ist lästig. Ein kürzerer Name ist da schon wesentlich handlicher.
Host svn
HostName svn.example.org
Es kann auch so ganz hilfreich sein, wenn man die Konfiguation für einen Dienst erstellt und an allen Stellen, die SSH verwenden, den Namen für den Dienst anstatt den eines konkreten Rechners verwendet.
Host Cluster
HostName K1.cluster.example.org
Wenn z. B. der Zugriff auf einen Rechner‐Cluster über die Knoten K1, K2 und K3 erfolgen kann, wobei es unerheblich ist, auf welchem Knoten man sich befindet, und der Knoten K1 ausfällt, braucht man nur die Konfiguration von SSH zu ändern und alles geht wieder seinen gewohnten Gang.
Wenn's mal wieder etwas mehr wird
Für OpenSSH ist es möglich, in der Konfigurationsdatei Shell‐Pattern zu verwenden. Wenn ein Muster passt, dann werden die Optionen verwendet, wobei die erste passende Option verwendet wird. Daher sollten die Standardwerte am Ende der Datei stehen, da das Muster * natürlich alle anderen überstimmt.
Wenn man unter einer Domain für mehrere Rechner die gleiche Konfiguration verwendet, kann man diese auch zusammenfassen:
Host *.example.org
Option1 Wert1
Option2 Wert2
Benutzernamen zentral verwalten
Den Benutzernamen für den entfernten Rechner kann man beim Aufruf mit Name@Rechner bestimmen. Solche Kleinigkeiten will man sich aber in der Regel nicht merken. Daher kann man diese Einstellung auch in der Konfigurationsdatei ~/.ssh/config angeben.
Host blubb.example.org
User MeineAndereIdentität
… und zum Schluss nochmal Alles im Überblick
# Port‐forwarding
Host Z
ProxyCommand ssh M nc Z 22
# Chip‐Tuning für mehr Leistung
Host lokalerRechner
Ciphers arcfour,arcfour128,blowfish-cbc,aes128-cbc,cast128-cbc
Compression no
# Beliebige Namen für Konfigurationen
Host Cluster
HostName K1.cluster.example.org
User NichtIch
Host svn
HostName svn.example.org
# Wenn's mal wieder etwas mehr wird
Host *.example.org
Option1 Wert1
Option2 Wert2
# Benutzernamen zentral verwalten
Host blubb.example.org
User MeineAndereIdentität
# die Standardwerte erst am Ende, da der erste Treffer verwendet wird
Host *
# Alte Bekannte wiedererkennen
StrictHostKeyChecking yes
# Herr und Meister! Hör' mich rufen!
ControlMaster auto
ControlPath ~/.ssh/socket_%h
# Chip‐Tuning für mehr Leistung
Ciphers blowfish-cbc,aes128-cbc,cast128-cbc,arcfour128,arcfour