Ein Host hinter einer Unternehmensfirewall oder hinter einem NAT-Router
kann kann normalerweise nicht von außen erreicht werden. Dies ist
grundsätzlich auch ein Sicherheitsmerkmal, aber in bestimmten Situationen
kann es dennoch notwendig sein, den Zugang zu gewähren. Eine elegante
Möglichkeit ist die Einrichtung eines Tunnels über Reverse-SSH.
Dies entspricht im Prinzip dem Verfahren, das auch von Anbietern
bekannter Fernwartungssoftware wie PcVisit oder TeamViewer verwendet
wird. Was man dafür braucht und wie man es einrichtet, wird im Folgenden
beschrieben.
Konzept
Der Schlüssel liegt darin, die Verbindung umzukehren. Anstatt einen Port direkt nach außen anzubieten, baut der Server eine SSH-Verbindung(1) zu einem einem externen Host auf. Dieser wird auch als Jump-Host bezeichnet, in Anlehnung an die Tatsache, dass er als Sprungbrett in ein anderes Netzwerk dient. Die SSH-Verbindung fungiert als verschlüsselter Tunnel, über den jeder Port des Server mit dem Jump-Host verbunden werden kann. Der Jump-Host selbst kann dann diese Ports wieder zur Verfügung stellen, zum Beispiel für Clients aus einem anderen Netzwerk, die Zugriff auf den Jump-Host haben(2). Alle Verbindungen, die über die entsprechenden Ports abgewickelt werden, werden vom Jump-Host an den Server(3) weitergeleitet.
.--------. .---------. .---------.
| |---+-(1)-+-->| | | |
| Server | | | |Jump Host|<----(2)--->| Client |
| |<--` (3) `---| | | |
`--------` `---------` `---------`
Implementierung
Der Server verwendet AutoSSH zur Aufrechterhaltung und Überwachung einer permanenten SSH-Sitzung mit dem Jump-Host. Die Authentifizierung basiert auf öffentlichen Schlüsseln. Der Login-Benutzername könnte vom Servernamen abgeleitet werden, um eine einfache Zuweisung der jeweiligen SSH-Konfiguration im Jump-Host zu ermöglichen, die erforderlich ist, um ein angemessenes Maß an Isolation zu gewährleisten. In der Praxis bedeutet dies, dass nur ein bestimmter Benutzername einen bestimmten Port weiterleiten darf, was eine netzseitige Isolierung von Hosts unterschiedlicher Nutzer oder Kunden ermöglicht.
Konfiguration
Jump Host
Erstellen eines “Remote-Host-Kontos” (SSH-Anmeldung):
jumphost$ doas useradd -m myserver
jumphost$ doas su - myserver
jumphost$ whoami
myserver
Setzen des initialen Passwort für die Schlüsselübertragung:
jumphost$ doas passwd myserver
Server
- Lokalen AutoSSH-Benutzer anlegen:
myserver$ doas useradd -m autossh
myserver$ doas su - autossh
myserver$ whoami
autossh
- Erstellen des private und public key:
myserver$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/autossh/.ssh/id_rsa):
Created directory '/home/autossh/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/autossh/.ssh/id_rsa.
Your public key has been saved in /home/autossh/.ssh/id_rsa.pub.
- Übertragung des public key zum Jump-Host:
myserver$ ssh-copy-id -i /home/autossh/.ssh/id_rsa.pub -p 22 myserver@jumphost
Sicherheitsvorkehrungen auf dem Jump Host
Es wird im Folgenden davon ausgegangen, dass der Server nur einen einzigen Port an den Jump-Host binden können sollte. Außerdem sollte es nicht möglich sein, Befehle auf dem Jump-Host auszuführen. SSH sollte daher nur als Transportmittel für den getunnelten Port dienen. Dies kann durch Hinzufügen eines Eintrags in der authorized_keys-Datei des Login-Benutzers myserver (im Beispiel) erreicht werden. Achten Sie darauf, dass alles in der gleichen Zeile steht wie der Host-Schlüssel und der ssh-rsa-Parameter nicht dupliziert wird.
Generisches Beispiel für listen:
permitlisten="localhost:19103",permitlisten="localhost:9999",permitlisten="localhost:2211",no-pty,no-X11-forwarding,no-agent-forwarding,command="/bin/echo
'Remote shell access has been disabled'" ssh-rsa ......
Beispiel für das Öffnen des lokalen Ports 10001 auf Anfrage des Servers:
permitopen="localhost:10001",no-pty,no-X11-forwarding,no-agent-forwarding,command="/bin/echo
'Remote shell access has been disabled'" ssh-rsa ....
Außerdem muss im obigen Fall die GatewayPorts-Funktion in SSH aktiviert werden, wenn der Port an die externe Schnittstelle des Jump-Hosts weitergeleitet werden soll (nur empfohlen, wenn sich der jump host in einer vertrauenswürdigen Umgebung befindet).
# vi /etc/sshd/sshd_config
GatewayPorts yes
Verbindungstest
Als Beispiel wird Port 9182 des Servers an den lokalen Port 10001 des Jump Hosts weitergeleitet. Dieser Port wird normalerweise vom Prometheus node_exporter verwendet und dient als praktisches Beispiel, wie z.B. wie z.B. die Überwachung eines entfernten Servers durch eine Firewall hindurch realisiert werden kann.
myserver$ ssh -p 22 -N -R 10001:localhost:9182 myserver@jumphost
Leiten Sie Port 9182 des Servers an den öffentlich zugänglichen (gatewayed) Port 10001 weiter im Jump-Host weiter:
myserver$ ssh -p 22 -N -R 0.0.0.0:10001:localhost:9182 myserver@jumphost
Der node_exporter des Servers ist jetzt über den Jump-Host zugänglich:
http://jumphost:10001
AutoSSH beim Systemstart starten
Die vorangegangenen Schritte gelten für jedes Linux / Unix / BSD-System weitgehend unverändert. Abschließend möchte ich hier noch einen Ausblick geben, wie AutoSSH am Beispiel von NetBSD in die Startsequenz des Betriebssystems integriert werden kann.
# vi /etc/rc.local
su autossh -c "/usr/pkg/bin/autossh -f -M 9999 -p 22 -N -R 0.0.0.0:10001:localhost:9182 myserver@jumphost"
Noch besser ist es natürlich, den Aufruf in ein eigenes rc-Skript zu verpacken oder mit einem Dienstmanager (Monit, Initware, Systemd) zu starten.
Fazit
Dieser Ansatz eröffnet viele interessante Anwendungsfälle in verteilten Infrastrukturen. Ich selbst nutze diese Techniken zur Vernetzung von Systemen mit dynamischen IP-Adressen, zum Beispiel um verteilte Backups mit Bareos zu realisieren und zur Überwachung von Hosts mit Prometheus. Dieser Weg könnte auch geeignet sein geeignet sein, um temporär dedizierte Dienste aus einer geschlossenen Umgebung anzubieten, wobei hier immer das Risiko abgewogen werden sollte (die meisten geschlossenen Umgebungen sind aus guten Gründen geschlossen, und die Anwendung von solcher Techniken diese Schutzmaßnahmen umkehren).
Wie bereits eingangs erwähnt, funktionieren gängige Fernwartungsprodukte ähnlich, nur dass die Einrichtung hinter benutzerfreundlichen Fassaden erfolgt. In der Tat fände ich es interessant und wünschenswert, wenn es solche client- und serverseitigen Komponenten als freie Open-Source-Software geben würde.