Dieses HOWTO beschreibt, wie man einen ssh-Tunnel über einen Gateway zum Zielrechner aufbaut um zum Beispiel svn darüber laufen zu lassen. Das Verfahren wird manchmal auch „port forwarding“ genannt.
Angenommen ein subversion-Repository war früher im Internet via https erreichbar, doch der Betreiber entschied sich dazu nur noch anfragen aus dem (entfernten) Netzwerk zuzulassen. Wenn man sich nicht bereits in diesem Netz befindet würde man sich üblicherweise per VPN ins entfernte Netz einfwählen und wie gewohnt weiterarbeiten. Möchte man allerdings nicht extra für einen Dienst ein VPN betreten, kann man diesen Dienst auch über ssh tunneln.
Der Befehl
# ssh -L lokalerport:zielrechner:zielport gatewaylogin@gateway
erzeugt nach erfolgreichem login auf dem Gateway einen Tunnel. Alle anfragen an port „lokalerport“ auf dem lokalen Rechner, werden nun über den Gateway zum Zielrechner an den Zielport geleitet.
Am konkreten Beispiel leiten wir alle lokalen Anfragen an den Port 7777 über das Gateway (der zu dem wir SSH-Zugang haben und der sich im selben Netz wie der svnserver befindet) an den https-Port des svnservers weiter:
# ssh -L 7777:svnserver:443 user@gateway
Nun ist man auf dem Tunnel eingeloggt und der Tunnel besteht solange bis man sich wieder ausloggt.
Da der svnserver jetzt nicht mehr über „https://svnserver/“, sondern über „https://localhost:7777/“ erreichbar ist, müssen bereits vorhandene Arbeitskopien natürlich angepasst werden. Dazu wechselt man ins Verzeichnis der Arbeitskopie und „schaltet“ von der alten URL zur neuen um:
# svn switch --relocate https://svnserver/pfad/zu/repo https://localhost:7777/pfad/zu/repo
Ein anschließendes
# svn up
Sollte nach ein paar eventuellen Fragen über den „neuen“ Host die Arbeitskopie aktualisieren.
Wenn ich auf hamster
# ssh -g -L 4321:www.ibm.com:80 gate
aufrufe, baut ssh eine Verbindung zu gate auf, lauscht währenddessen auf hamster:4321 und reicht alle dort ankommenden TCP-Verbindungen an den sshd an gate weiter, der sie an Port 80 von „www.ibm.com“ weiterleitet. Der Rückweg funktioniert entsprechend.
Im Browser würde „http://hamster:4321“ also genauso aussehen wie die Webseite von IBM.
Man muss auf hamster Rootrechte haben, wenn man einen lokalen Port kleiner als 1024 öffnen möchte.
Wenn man den -g Parameter weglässt, können Clients den Port nur über die IP-Adresse 127.0.0.1 oder entsprechende Aliase (z.B. localhost) erreichen, müssen also auf dem selben Rechner wie der ssh-Client laufen, oder aus einem anderen Tunnel dort umsteigen.
Sollen die Benutzer auf dem sshd-Rechner keinen Shellzugriff, sondern nur Portforwarding können, kann man zunächst in der /etc/ssh/sshd_config die Option PasswordAuthentication=no setzen und dann für jeden betreffenden Publickey in der ~/.ssh/authorized_keys am Zeilenanfang einen Aufruf wie command=“/bin/cat“ oder command=„sleep 2000d“ einfügen.
Wer zusätzlich einen keepalive einbauen möchte, damit die Natting-Tabelle der Firewall im Leerlauf die Tunnels nicht kappt, schreibt an den Beginn der Publickeyzeilen jeweils:
command="while :;do date;sleep 10;done"
Um die möglichen Portforwoarding-Ziele zu beschränken, kann man eine Liste von permitopen-Optionen vor den jeweiligen Publickeys einfügen, z.B.:
permitopen="192.168.42.5:80",permitopen="127.0.0.1:8080"
Wenn ich auf hamster ssh -R 9030:intranet:80 gate eingebe, nimmt der sshd auf gate die Verbindung entgegen, lauscht auf Port 9030 und reicht alle dort ankommenden Verbindungen an den ssh-Client auf hamster weiter, der sie auf den Port 80 von intranet weiterleitet. Der Rückweg funktioniert entsprechend. Ich habe einen Tunnel von gate:9030 nach intranet:80 gelegt.
Wer im Browser http://gate:9030 aufruft, landet auf dem Intranetserver.
Man muss auf gate Rootrechte haben, wenn man remote Port <1024 öffnen möchte. Wer den Rootzugriff per ssh nicht erlauben möchte, kann den ssh-Tunnel auf einen hohen Port (z.B. 9030) legen und mit xinetd, netcat oder Firewallregeln auf Port 80 umleiten.
Dies leisten folgende:
# vi /etc/inetd.conf 80 stream tcp nowait nobody /bin/nc /bin/nc -w 3 localhost 9030
oder
# vi /etc/xinetd.d/intranet
service intranet
{
type = UNLISTED
flags = REUSE
socket_type = stream
protocol = tcp
user = root
wait = no
instances = UNLIMITED
port = 80
redirect = localhost 9030
disable = no
}
oder ein Firewallscript:
# echo 1 > /proc/sys/net/ipv4/ip_forward # turns on forwarding iptables -F -t nat # Flush existing translation tables iptables -t nat -A PREROUTING -p tcp --dport 9030 -j DNAT --to localhost:80 iptables -t nat -A POSTROUTING -j MASQUERADE
Der sshd bindet die remote Tunnels in seiner Standardkonfiguration an das loopback-Interface; er nimmt also nur Verbindungen von localhost entgegen. Wer möchte, dass seine Tunnels auf allen Netzinterfaces erreichbar sind, trage in der /etc/ssh/sshd_config auf gate die Zeile GatewayPorts yes ein oder leite den Port wie oben beschrieben mit ssh oder xinetd um.