💾 Archived View for pf4sh.eu › blog › ssh_vpn.gmi captured on 2022-03-01 at 14:59:58. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2021-11-30)
-=-=-=-=-=-=-
Manchmal möchte man auf einen entfernten Rechner sicher zugreifen, dafür gibt es natürlich `ssh`. Was aber tun, wenn die IP-Adresse des Rechners nicht bekannt und dieser hinter einer Firewall und/oder zusätzlich einem NAT-Gateway steckt? Dann könnte man natürlich über einen externen Anbieter oder über TOR eine Verbindung aufbauen z.B. ein VPN, aber für ein VPN muss normalerweise UDP-Trafik erlaubt sein und man muss dem Anbieter vertrauen.
Gut wäre eine Lösung, wo auf einem Remote-Rechner keine Geheimnisse hinterlegt sein müssen.
Da `ssh` ein flexibles Werkzeug ist und auch für das Weiterleiten von TCP-Ports verwendet werden kann, kann ich auch entfernte Dienste an anderen Orten verfügbar machen. Durch die sichere Authentifizierung mittels Schlüssel ist auch Fremden der Zugriff nicht möglich und diese Schlüssel können mit den eingebauten Funktionen selbst erzeugt und verteilt werden.
Dafür läuft auf dem Remote-Client ein "Service", der den für den Dienst nötigen Port an einen Server mit dem festen Namen oder IP weiterleitet. Wenn wir nun diesen Port des Servers nutzen oder selbst weiterleiten, dann haben wir Zugriff auf den Dienst des Remote-Client.
Auf den Server ist eigentlich keine weitere Einstellung nötig, außer um das System robuster zu gestalten, sollten in der Datei `/etc/ssh/sshd_config` die folgenden Parameter gesetzt werden:
ClientAliveInterval 60 ClientAliveCountMax 3
Dies bewirkt, dass erst nach 180s die Verbindung abgebaut würde, womit kurze Netzunterbrechungen toleriert werden.
Sinnvoll ist evtl. auch ein separater Nutzer, der für die Anmeldung der Remote-Clients verwendet wird. Damit kann man dann später gezielt nach der Verbindung suchen und diese z.B. abbauen, falls doch mal etwas nicht wie gewünscht funktioniert. Hierzu ein Beispiel:
Match User emrcall AllowTcpForwarding yes X11Forwarding no PermitTunnel no GatewayPorts no AllowAgentForwarding no ClientAliveInterval 60 ClientAliveCountMax 3 ForceCommand date
Dieser User benötigt noch nicht einmal ein Passwort, da ja die Anmeldung ausschließlich per ssh-key erfolgt. Je nach System ist dies aber für User ohne Passwort gesperrt. Eine Änderung im 2. Feld der Datei `/etc/shadow` von ! auf x behebt dies.
Dieser Rechner soll einen oder mehrere Dienste auf dem Server anbieten. Dafür nutzen wir `ssh` mit der Option `-R ` (Remote Port Forwarding). Das Programm sollte in einer Dienstüberwachung wie z. B. `runit` laufen, denn die Verbindung kann durch verschiedene Situationen abbrechen und damit endet auch die Programmausführung.
Zuerst erstellen wir ein neues ssh-Schüsselpaar für diese Aufgabe, wobei wir den Öffentlichen-Schüssel in die Datei `~/.ssh/authorized_keys` des für diesen Zweck verwendeten Users eintragen. Die Datei darf nur vom User beschreibbar sein (0600).
Mit dem oben angegebenen Beispiel-Setup sollte eine ssh-Verbindung mit dem gerade erzeugten Key die Uhrzeit des Servers liefern.
Um unsere Portweiterleitung als Dienst laufen zu lassen, bietet es sich an, die Parameter in ein kleines Script zu schreiben, z. B. nach `/etc/rpfs.sh`. Hier ein Beispiel:
#!/bin/sh ssh -q -o ConnectTimeout=45 -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \ -N -R 4022:localhost:22 -i /home/user/.ssh/id_rsa_ermcall \ ermcall@server_ip_or_name
Dieses Script machen wir mit `chmod +x /etc/rpfs.sh` ausführbar. Wenn wir dies nun direkt starten, können wir auf den Server über Port 4022 auf den ssh-Server des Remote-Clients zugreifen. Eine Anmeldung sollte aber nicht möglich sein, da auf dem Server nicht die notwendigen Schlüssel verfügbar sind und auch nicht sein sollten (Private Schlüssel sollten auch Privat bleiben).
Damit dies auch immer zur Verfügung steht, erstellen wir dafür einen Dienst, bei runit mit:
mkdir /etc/sv/emrcall cd /etc/sv/emrcall echo -en '#!/bin/sh\n\nexec /etc/rpfs.sh' > run chmod +x run ln -s /run/runit/supevrise-emrcall supervise cd ln -s /etc/sv/emrcall /var/service
Je nach System können die Pfade etwas anders sein, schaut einfach in die Dokumentation.
Auf dem Rechner, wo wir diesen Dienst nutzen wollen, benötigen wir das Schlüsselmaterial, um auf unseren Remote-Client zugreifen zu können. Der passende Öffentliche Schlüssel muss auf dem Remote-Client eingetragen sein. Sind diese Vorarbeiten erledigt, bietet es sich an, in der lokalen ssh Konfiguration, normalerweise unter `~/.ssh/config` dafür einen eignen Eintrag zu erstellen. Hier ein Beispiel:
Host server1 Hostname server_ip_o_name IdentityFile ~/.ssh/id_rsa_for_server_access User server_user_account Host rhost1 Hostname localhost Port 4022 IdentityFile ~/.ssh/id_rsa_for_remote_client ProxyCommand ssh -W %h:%p server1
Nun ist mit `ssh rhost1` ein Zugriff auf den entfernten Rechner möglich und wir haben nirgends auf dem Weg Geheimnisse hinterlegen müssen.
Es können über eine Verbindung natürlich auch mehre Ports freigegeben oder auch bezogen werden.
In sehr seltenen Fällen und bei einer nach jetzigen Erfahrungen sehr schlechten Netzverbindung, geht evtl. die Weiterleitung kaputt und die Client-Seite beendet nicht das Programm. Dann ist es notwendig, den passenden `sshd` Prozess serverseitig zu beenden.