#!/bin/blog

December 11, 2004

SSH um die Ecke(n) bringen

Filed under: Notizen, Sicherheit, UNIX/Linux/BSD — martin @ 11:41 am

Die Ausgangslage

Auf einer bestimmten Baustelle muß ich, wenn ich an meine Mails kommen will, über zwei DMZ-Gateways (eins von der Baustelle und unser eigenes) sowie unseren im Rechenzentrum stehenden Webserver gehen, um schließlich auf dem Server im Büro zu landen. Als ich noch mit dem textbasierten Mutt gearbeitet habe, war das eine ganz einfache Sache, denn ich konnte mich immer der Nase nach per SSH über ein System nach dem anderen durchhangeln und dann auf der Kommandozeile des Zielsystems mutt starten:

martin@workstation:~$ cat bin/bring-mich-office.sh
#!/bin/sh
ssh -A -t dmzbox.baustelle.invalid \
 ssh -A -t webbox.example.com \
 ssh -A -t dmzbox.example.com \
 ssh officebox.example.com
martin@workstation:~$ bin/bring-mich-office.sh
martin@officebox:~$ mutt -y

Die Frickelvariante

Seit ich unter die Mausschubser gegangen bin, gestaltet sich das ganze deutlich schwieriger, denn über diese ganze Kette müssen jetzt die Ports 143 und 25 für IMAP und SMTP getunnelt werden. Dies soll geschehen, ohne daß diese Ports auf den in der Mitte der Kette befindlichen Systemen ansprechbar sind. Wenn auf den Zwischenstationen jedermann auf die weitergeleiteten Ports zugreifen könnte, hätte ich riesige unerwünschte Löcher in Firewalls gebohrt, und das will sicherlich niemand.

Um diesen Tunnel vollautomatisch aufbauen zu können, habe ich mich dann eine ganze Weile mit einer wüsten Konstruktion herumgeschlagen, bei der zunächst über alle beteiligten Funkhäuser ein “verlegter” SSH-Port durchgetunnelt wurde. In einer zweiten SSH-Sitzung habe ich über diesen dann meine beiden Applikationsports getunnelt:

#!/bin/sh
# Erste Verbindung
ssh -A -L 10022:localhost:10022 dmzbox.baustelle.invalid \
 ssh -A -L 10022:localhost:10022 webbox.examle.com \
 ssh -A -L 10022:localhost:10022 dmzbox.example.com \
 ssh -L 10022:localhost:22 officebox.example.com sleep 20 &
# Gedenkpause
sleep 10
# Zweite Verbindung
ssh -t -C -p 10022 -L 10025:localhost:25 -L 10143:localhost:143 127.0.0.1

Ich denke, ich muß nicht näher erläutern, warum das nicht nur furchtbar aussieht, sondern auch ganz schön bescheiden funktioniert hat. Bei fünf ineinandergestöpselten Port-Weiterleitungen ist die Wahrscheinlichkeit, daß alles klappt, wirklich nicht besonders hoch.

Jetzt stellen wir uns mal ganz dumm.

Kürzlich habe ich mir dann einmal die Manpage von ssh_config vorgenommen und tatsächlich die optimale Lösung gefunden.

Man kann, soviel war vorher schon klar, in ~/.ssh/config Optionen pro Zielhost definieren. Unter anderem gibt es da auch eine Option namens ProxyCommand, mittels der man man eine zum Erreichen des genannten Zielhosts erforderliche Verbindung aufbauen kann, die dem realen SSH-Client vorgeschaltet wird. Dieser spricht dann lustigerweise nicht TCP/IP, sondern kommuniziert ausschließlich über Pipes zum ProxyCommand.

ProxyCommand im Einsatz

Wenn man einen Beispielhost über einen Zwischenhost erreichen kann, benötigt man auf dem Zwischenhost zunächst die Allzweckwaffe Netcat. Als ProxyCommand wird eine SSH-Verbindung zum Zwischenhost definiert. Dort wird dann die oben erwähnte Pipe von Netcat in eine TCP-Verbindung in Richtung Zielhost umgewandelt. Der reale SSH-Client kann dann über die Pipe und den Netcat-Aufruf letztlich den Zielhost erreichen:

# Aus der Datei ~/.ssh/config:
Host zielhost
ProxyCommand ssh zwischenhost nc -w 10 zielhost 22

Wenn der Zielhost auf diese Weise konfiguriert ist, kann man einfach mittels ssh zielhost auf ihn zugreifen. Portweiterleitungen mit -L, -R oder -D funktionieren genau wie beim direkten Zugriff. SCP und das Fish-Protokoll funktionieren natürlich ebenfalls ohne weiteres zutun. Das liegt einfach daran, daß die Verbindung tatsächlich den lokalen SSH-Client und den SSH-Daemon auf dem Zielserver als Endpunkte hat und das ProxyCommand nur für die Weiterleitung der Pipe und die abschließende Umwandlung der Pipe in eine TCP-Verbindung zum Zielhost zuständig ist.

Man kann mittels Netcat und den Platzhaltern %h und %p übrigens eine allgemeingültige Lösung für Situationen aufbauen, in denen man immer hinter der selben Firewall sitzt. Darum soll es hier aber nicht gehen.

Kompliziertes einfach

Hier nun das ganze auf meine Situation übertragen:

# Aus der Datei ~/.ssh/config:
Host officeserver-tunnel
ProxyCommand ssh -A dmzbox.baustelle.invalid ssh -A webbox.example.com ssh dmzbox.example.com nc -w 10 officebox.example.com 22
Compression yes

Wenn dieser Eintrag gemacht ist, bekomme ich mit dem folgenden Aufruf meine Portweiterleitung ganz normal ohne große Mühe frei Haus geliefert:

ssh -L 10025:localhost:25 -L 10143:localhost:143 officeserver-tunnel

Damit ist doch mal wirklich einiges gewonnen. Man kann mit dieser Lösung nicht nur sehr gut leben, sondern man kann, wo man schon dabei ist, gleich AutoSSH mit in den Mix werfen, um die Verbindung beim Abbruch (Stichwort: DSL-Zwangstrennung) automatisch wieder aufzubauen. Mal schauen, was sich da noch alles zurechtbasteln läßt… 🙂

Vertrauen Sie mir, ich weiß, was ich tue!

Obwohl hier nur legale SSH-Funktionalität zum Einsatz kommt, kann sowas je nach Standpunkt des Betrachters recht schnell in die Kategorie “Firewall-Piercing” fallen. Jeder muß selbst wissen, wie er mit sowas zurechtkommt.

Update, 15.12.: Michael Lohmann merkt an, daß die Netcat-Prozesse nie beendet werden und praktisch unendlich auf dem Gateway weiterlaufen. Ich möchte das noch ergänzen dadurch, daß auch davorgehängte SSH-Proxy-Clients so lange laufen, wie der Netcat-Prozeß noch da ist. Man kann das vermutlich in den Griff bekommen, indem man Netcat mit der Option “-w 10” aufruft, damit es sich nach 10 Sekunden ohne Datentransfer beendet. Offene Sessions wurden mir dadurch bisher nicht abgebrochen, aber da ich nicht sicher bin, was da wirklich über die Leitung geht, weiß ich nicht, ob das allgemeingültig ist. Um auf Nummer sicher zu gehen, könnte man den Timeout auch auf einen halben oder ganzen Tag erhöhen. Ich werde das mal einige Tage beobachten.

Advertisements

3 Comments

  1. Esoterisches mit SSH

    Der #!/bin/blog beschreibt, auf welche “krummen” Gedanken man bei der Benutzung von ssh kommen kann. Also mal ehrlich: SSH-Tunnel über zwei DMZ-Gateways, das hat einen ganz hohen Nerd-Faktor 🙂 Lesetipp!

    Trackback by public void blog() — December 11, 2004 @ 11:11 pm

  2. Ports mit SSH tunneln

    Wenn man nicht gleich ein ganzes VPN aufsetzen möchte, nur um einen Port durch eine oder mehrere Firewalls zu tunneln, bietet sich ssh dazu an. In #!/bin/blog wird beschrieben wie ein SSH-Tunnel manuell oder über die Konfigurationsdatei aufgebaut wer…

    Trackback by Jan's Technik Blog — December 13, 2004 @ 11:10 pm

  3. SSH um die Ecke

    Beispiel für den Einsatz von ProxyCommand bei ssh

    Trackback by Michael Lohmann — December 15, 2004 @ 2:22 pm


RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Create a free website or blog at WordPress.com.

%d bloggers like this: