Einführung

Problem

Oft ist man im Arbeitsalltag vor das Problem gestellt, dass man eine Kommunikation zwischen zwei entfernten Computern ermöglichen soll. Mögliche Szenarien hierfür sind…

  • die Fernwartung eines Servers,
  • der Zugriff auf zentral abgelegte Ressourcen oder
  • eine Peer-to-Peer-Dateiübertragung.

Desktop- und Server-Umgebungen

Für die Fernwartung eines Desktop-Computers gibt es Lösungen wie das Remote Desktop Protocol unter Windows oder TeamViewer für verschiedene Betriebssysteme.

Da Desktop-Umgebungen sehr ressourcenintensiv sind, wird auf Server-Systemen oftmals keine grafische Benutzeroberfläche installiert. Der Server, auf dem diese Webseite gehosted ist, verfügt beispielsweise über folgende (virtuelle) Hardware-Ressourcen:

  • 512 MB Arbeitsspeicher
  • 1 CPU mit 2198 MHz
  • 10 GB Festplattenspeicher

Das sind Hardware-Spezifikationen, wie sie ungefähr vor 20 Jahren bei Desktop-Computern verbreitet waren, genügen aber heutzutage noch völlig, um kleinere Web-Anwendungen mit relativ wenig Zugriffen auszuführen. Und je weniger Ressourcen verbraucht werden, desto weniger Kosten entstehen, wenn das System über einen Cloud-Anbieter bezogen wird (IaaS).

Ist keine Desktop-Umgebung verfügbar, stehen Lösungen wie Windows Remote Management (WinRM) oder die Secure Shell (SSH) zur Verfügung. In diesem Modul soll SSH im Vordergrund stehen, weil dies eine weit verbreitete, sehr erprobte, sichere und zuverlässige Lösung ist, die Clients für alle gängigen Betriebssysteme anbietet. Ausserdem ist SSH der Industriestandard für den Fernzugriff auf Linux-Systeme, die in diesem Modul zum Einsatz kommen.

Telnet

Eine ältere Lösung zum Fernzugriff auf andere Systeme ist Telnet. Damit lässt sich eine textorientierte Verbindung zu beispielsweise einem Webserver aufnehmen, indem man eine Adresse und einen Port angibt:

telnet ADDRESS PORT

Ist eine Verbindung aufgenommen, kann man interaktiv mit diesem System kommunizieren. Spricht man beispielsweise einen Webserver auf Port 80 an, kann man diesem HTTP-Anfragen schicken (sofern er noch Inhalt unter diesem Port ausliefert):

$ telnet www.website.com 80
GET /ping HTTP/1.1
Host: www.website.com

<!DOCTYPE html>
<html>
    <head>
        <title>Some Website</title>
…

Da Telnet unverschlüsselt kommuniziert, sollte es heutzutage nur noch als Port-Scanner eingesetzt werden. (Ist der angegebene Port geschlossen, wird erst gar keine Sitzung aufgebaut.)

Hintergrund und Funktionsweise

SSH ist ein Protokoll, wofür es mehrere Implementierungen gibt. Die Referenzimplementierung ist OpenSSH und wird im Rahmen des Unix-artigen Betriebssystems OpenBSD weiterentwickelt, welches sehr hohen Wert auf Sicherheit legt. OpenSSH ist im Lieferumgang der Git Bash enthalten.

SSH arbeitet mit asymmetrischer Kryptographie. Sowohl der Server als auch der Client verfügen über ein Schlüsselpaar, wobei der private Schlüssel gut zu schützen ist und der öffentliche Schlüssel auf andere Systeme verteilt werden darf. (Aus Effizienzgründen wird beim erfolgreichen Verbindungsaufbau ein symmetrischer Schlüssel generiert, womit dann der Datenverkehr für die laufende Sitzung verschlüsselt wird.)

SSH arbeitet nach dem Client-Server-Prinzip: Auf einem Server, der per SSH zugänglich ist, muss der SSH-Daemon sshd laufen. Clients verwenden das interaktive Client-Programm ssh ‒ zumindest für interaktive Sitzungen oder einzelne auf dem Server auszuführende Befehle. Es gibt weitere Client-Programme wie z.B. scp oder sftp zum sicheren Kopieren von Daten zwischen entfernten Systemen.

Bedienung

Ein SSH-Schlüsselpaar kann mit dem Programm ssh-keygen erstellt werden:

ssh-keygen -t ed25519 -C vorname_nachname@sluz.ch

Eine interaktive Sitzung mit einem Server kann folgendermassen gestartet werden:

ssh user@server

Haben der lokale Benutzer und derjenige auf dem Server den gleichen Namen, kann der Benutzername auch weggelassen werden:

ssh server

Beim Verbindungsaufbau muss man das Passwort vom Benutzer eingeben. Dem kann man Abhilfe schaffen, indem man seinen öffentlichen SSH-Schlüssel auf das entfernte System kopiert:

ssh-copy-id user@server

Es ist auch möglich, keine interaktive Sitzung zu eröffnen, sondern nur einen einzigen Befehl auf dem entfernten System auszuführen:

ssh server 'sudo apt install htop'

Mit diesem Befehl wird auf einem Debian-artigen Linux-Server das Programm htop installiert.

Weiter können Daten mit scp verschlüsselt übertragen werden:

scp ~/script.py server:bin/
scp server:/backup/db.sql ~/backup.sql

Der erste Befehl kopiert die Datei script.py aus dem lokalen Home-Verzeichnis ins bin-Unterverzeichnis vom Home-Verzeichnis des Benutzers auf dem Server.

Der zweite Befehl kopiert die Datei /backup/db.sql vom Server ins lokale Home-Verzeichnis unter den Namen backup.sql.

SSH-Tunnel

Oftmals steht man vor dem Problem, dass man von ausserhalb eines Servers auf eine bestimmte Anwendung auf diesem Server zugreifen muss, der entsprechende Port aber nicht offen ist (von der Firewall blockiert).

Beispielszenario I: Eine Anwendung läuft auf einem Server und greift auf eine Datenbank zu. Die Datenbank läuft auf Port 5432 (PostgreSQL). Die Datenbank lauscht auf 0.0.0.0:5432, d.h. nimmt grundsätzlich Verbindungen von überall her entgegen, doch nur auf Port 5432, der geschlossen ist.

Ein anderes ‒ wenn auch selteneres ‒ Problem ist, dass zwar der Zugriff von einem Client auf einen Server möglich ist, man aber keine Möglichkeit hat, vom Server her auf einen Client zuzugreifen. Einerseits verfügt der Client nicht über eine öffentliche IP-Adresse oder eine vergleichbare öffentlich erreichbare Adressierung (z.B. DynDNS). Andererseits dürfte der Client hinter einer Firewall sein, welche Zugriff von aussen (ingress) her nicht erlaubt. (Ausgehende Verbindungen, egress, werden im geringeren Ausmass blockiert.)

Beispielszenario II: Eine Anwendung läuft auf einem Server und funktioniert nicht wie gewünscht. Ein Benutzer schildert das Verhalten, doch der Entwickler der Anwendung kann dieses auf seiner lokalen Entwicklungsumgebung aber nicht nachvollziehen. Schön wäre es, wenn der Benutzer den Anwendungsfall auf dem Computer des Entwicklers durchspielen könnte. Der Benutzer und der Entwickler sind aber nicht am gleichen Ort. Der Rechner des Entwicklers ist wiederum nicht vom Internet her zugreifbar.

In diesen beiden Szenarien schafft SSH Abhilfe, indem es einen sicheren Kanal zwischen zwei Systemen erzeugt, über den ein Port, der geschlossen ist, “getunnelt” werden kann. Dieses Verfahren bezeichnet man entsprechend als “SSH Tunneling”.

Local Forwarding

Beim Local Forwarding wird das Problem aus Beispielszenario I gelöst. Hierbei möchte man Zugriff auf eine Anwendung erhalten, deren Port nicht freigegeben ist.

Die Lösung ist ein SSH-Tunnel, wobei ein lokaler Port auf dem Client auf einen entfernten Port auf dem Server umgeleitet wird. Der betreffende Port muss dabei nicht offen sein, denn die Kommunikation findet über den SSH-Port 22 statt. (Dieser muss natürlich offen sein. Doch SSH-Zugriff ist in der Regel erlaubt.)

SSH Local Forwarding SSH Local Forwarding

Möchte man vom Client her eine Weiterleitung vom lokalen Port 1234 auf den entfernten Port 5432 erstellen, verwendet man den folgenden Befehl:

ssh -L localhost:1234:server:5432 user@server

Erklärung:

  • Das Flag -L steht für Local Forwarding.
  • Die Angabe localhost:1234 ist der Port, den man lokal ansteuern möchte (Weiterleitung von).
  • Die Angabe server:5432 ist der Port, den man auf dem Server verwenden möchte (Weiterleitung zu).
  • Mit user@server wird die SSH-Verbindung mit dem jeweiligen Benutzer auf das entfernte System aufgenommen.

Ist diese SSH-Sitzung offen, kann der Benutzer via localhost:1234 auf die Datenbank zugreifen. Die Kommunikation erfolgt verschlüsselt und wird auf server:5432 weitergeleitet. Wird die Verbindung geschlossen, ist auch kein Zugriff auf die Datenbank von aussen mehr möglich.

Remote Forwarding

Beim Remote Forwarding wird das Problem aus Beispielszenario II gelöst. Hierbei soll der Zugriff vom Server aus auf den Client umgeleitet werden.

Konkret möchte der Entwickler aus dem Beispielszenario die Anwendung lokal bei sich laufen lassen, und die Anfragen, die vom Benutzer auf dem Server eingehen, auf seinen Computer weiterleiten.

Die Lösung ist ein SSH-Tunnel, wobei ein entfernter Port auf dem Server auf einen lokalen Port auf dem Client umgeleitet wird. Hierzu ist es nicht nötig, dass der Client vom Internet aus zugreifbar ist, solange der SSH-Port 22 offen ist.

Wichtig: Auch hier wird die Verbindung vom Client auf den Server erstellt. Die Weiterleitung des Ports erfolgt aber in entgegengesetzter Richtung!

SSH Remote Forwarding SSH Remote Forwarding

Möchte man vom Server her eine Weiterleitung vom Port 8080, worauf die Anwendung läuft, auf den lokalen Port 1234, worauf die Anwendung auf dem Entwickler-Computer läuft, einrichten, verwendet man den folgenden Befehl:

ssh -R server:8080:localhost:1234 user@server

Erklärung:

  • Das Flag -R steht für Remote Forwarding.
  • Die Angabe server:8080 ist der Port, von auf den die Anfragen auf dem Server eingehen.
  • Die Angabe localhost:1234 ist der Port, auf den die Anfragen weitergeleitet werden sollen.
  • Mit user@server wird die SSH-Verbindung mit dem jeweiligen Benutzer auf das entfernte System aufgenommen.

Bevor diese SSH-Sitzung mit Remote Forwarding eröffnet werden kann, muss die Serveranwendung auf Port 8080 geschlossen werden, damit der Port frei wird. Solange die SSH-Sitzung offen ist, werden die Anfragen, die auf dem Server unter Port 8080 eingehen, auf den Computer des Entwicklers umgeleitet.

Warnung

Remote Forwarding ist eine sehr mächtige ‒ und darum auch eine sehr gefährliche Technik! Schliesslich merkt der entfernte Benutzer nicht, dass seine Anfragen nicht mehr vom Server sondern von einem Entwickler-Computer behandelt werden. Dies bietet dem Entwickler die Möglichkeit, den Benutzern eine angepasste Version seiner Anwendung ausführen zu lassen, die möglicherweise bösartige Anpassungen enthält. (Man denke an eine eBanking-Anwendung, welche Beträge oder das Zielkonto manipuliert.)

Aus diesem Grund ist SSH Remote Forwarding oftmals deaktiviert. Auch wenn es aktiv ist, sollte es nur nach Abspache mit dem Systemadministrator verwendet werden.