On-Demand-SSH-Socks-Proxy über systemd-Benutzereinheiten mit Socket-Aktivierung startet nicht wie gewünscht neu

14

Um ein isoliertes Netzwerk zu erreichen, benutze ich einen -D .

Um zu vermeiden, dass ich die Details jedes Mal eingeben muss, wenn ich sie hinzufüge ~/.ssh/config:

$ awk '/Host socks-proxy/' RS= ~/.ssh/config
Host socks-proxy
  Hostname pcit
  BatchMode yes
  RequestTTY no
  Compression yes
  DynamicForward localhost:9118

Dann habe ich eine Service Unit Definitionsdatei erstellt:

$ cat ~/.config/systemd/user/SocksProxy.service 
[Unit]
Description=SocksProxy Over Bridge Host

[Service]
ExecStart=/usr/bin/ssh -Nk socks-proxy

[Install]
WantedBy=default.target

Ich habe den Dämon die neuen Dienstdefinitionen neu laden lassen, den neuen Dienst aktiviert, gestartet, seinen Status überprüft und überprüft, ob er empfangsbereit ist:

$ systemctl --user daemon-reload
$ systemctl --user list-unit-files | grep SocksP
SocksProxy.service   disabled

$ systemctl --user enable SocksProxy.service
Created symlink from ~/.config/systemd/user/default.target.wants/SocksProxy.service to ~/.config/systemd/user/SocksProxy.service.

$ systemctl --user start SocksProxy.service 
$ systemctl --user status SocksProxy.service 
● SocksProxy.service - SocksProxy Over Bridge Host
   Loaded: loaded (/home/alex/.config/systemd/user/SocksProxy.service; enabled)
   Active: active (running) since Thu 2017-08-03 10:45:29 CEST; 2s ago
 Main PID: 26490 (ssh)
   CGroup: /user.slice/user-1000.slice/[email protected]/SocksProxy.service
           └─26490 /usr/bin/ssh -Nk socks-proxy

$ netstat -tnlp | grep 118
tcp     0    0 127.0.0.1:9118        0.0.0.0:*             LISTEN     
tcp6    0    0 ::1:9118              :::*                  LISTEN

Das funktioniert wie vorgesehen. Dann wollte ich vermeiden, dass der Dienst manuell gestartet oder permanent mit , indem die für das (erneute) nach Bedarf verwende. Das hat nicht funktioniert, ich glaube (meine Version von) sshkann keine Socket-Dateideskriptoren empfangen.

Ich fand die Dokumentation ( 1 , 2 ) und ein Beispiel für die Verwendung des systemd-socket-proxydTools zum Erstellen von 2 "Wrapper" -Diensten, einem "Dienst" und einem "Socket":

$ cat ~/.config/systemd/user/SocksProxyHelper.socket 
[Unit]
Description=On Demand Socks proxy into Work

[Socket]
ListenStream=8118
#BindToDevice=lo
#Accept=yes

[Install]
WantedBy=sockets.target

$ cat ~/.config/systemd/user/SocksProxyHelper.service 
[Unit]
Description=On demand Work Socks tunnel
After=network.target SocksProxyHelper.socket
Requires=SocksProxyHelper.socket SocksProxy.service
After=SocksProxy.service

[Service]
#Type=simple
#Accept=false
ExecStart=/lib/systemd/systemd-socket-proxyd 127.0.0.1:9118
TimeoutStopSec=5

[Install]
WantedBy=multi-user.target

$ systemctl --user daemon-reload

Dies scheint zu funktionieren, bis es sshstirbt oder getötet wird. Dann wird es beim nächsten Verbindungsversuch nicht erneut erzeugt, wenn es sollte.

Fragen:

  1. Kann / usr / bin / ssh wirklich keine vom System übergebenen Sockets akzeptieren? Oder nur neuere Versionen? Meins ist das von up2date Debian 8.9 .
  2. Können nur Root-Einheiten die BindTodeviceOption verwenden?
  3. Warum wird mein Proxy-Dienst bei der ersten neuen Verbindung nach dem Ausfall des alten Tunnels nicht korrekt neu gestartet?
  4. Ist dies der richtige Weg, um einen "On-Demand-SSH-Socken-Proxy" einzurichten? Wenn nicht, wie machst du das?
Alex Stragies
quelle
autosshsollte für den Fall, dass die Verbindung ausfällt (obwohl dies nicht der Systemweg ist), auf die Wiederherstellung der Verbindung achten.
Jakuje
@ Jakuje: Danke für den Kommentar, aber ich möchte nicht, dass die Verbindung dauerhaft ist. Ich möchte, dass es bei Verwendung erzeugt wird und sich dann (im Idealfall nach einem Timeout von x Minuten ohne Datenübertragung) selbst beendet. Auch meine bisherige Lösung verwendet autossh.
Alex Stragies

Antworten:

4
  • Kann / usr / bin / ssh wirklich keine vom System übergebenen Sockets akzeptieren?

Ich denke, das ist nicht allzu überraschend, wenn man bedenkt:

  • OpenSSH ist ein OpenBSD-Projekt
  • systemd unterstützt nur den Linux-Kernel
  • Die systemd-Unterstützung müsste OpenSSH explizit als optionale / Build-Time-Abhängigkeit hinzugefügt werden, daher wäre dies wahrscheinlich ein harter Verkauf.

  • Können nur Root-Einheiten die BindTodeviceOption verwenden?

Benutzer systemd-Instanzen sind im Allgemeinen ziemlich isoliert und können z. B. nicht mit der Hauptinstanz pid-0 kommunizieren. Abhängig von Systemeinheiten sind solche Dinge aus User-Unit-Dateien nicht möglich.

Die Dokumentation für BindToDeviceErwähnungen:

Beachten Sie, dass die Einstellung dieses Parameters dazu führen kann, dass dem Gerät zusätzliche Abhängigkeiten hinzugefügt werden (siehe oben).

Aufgrund der oben genannten Einschränkung können wir darauf hinweisen, dass die Option bei systemd-Benutzerinstanzen nicht funktioniert.


  • Warum wird mein Proxy-Dienst bei der ersten neuen Verbindung nach dem Ausfall des alten Tunnels nicht korrekt neu gestartet?

Soweit ich weiß, sieht die Ereigniskette wie folgt aus:

  • SocksProxyHelper.socket ist gestartet.
  • Ein SOCKS-Client verbindet sich mit localhost: 8118.
  • systemd startet SocksProxyHelper.service.
  • In Abhängigkeit von SocksProxyHelper.servicestartet auch systemd SocksProxy.service.
  • systemd-socket-proxydAkzeptiert den systemd-Socket und leitet seine Daten an weiter ssh.
  • ssh stirbt oder wird getötet.
  • systemd bemerkt und versetzt sich SocksProxy.servicein einen inaktiven Zustand, tut aber nichts.
  • SocksProxyHelper.serviceläuft weiter und akzeptiert Verbindungen, kann jedoch keine Verbindung herstellen ssh, da sie nicht mehr ausgeführt wird.

Das Update ist hinzuzufügen , BindsTo=SocksProxy.servicezu SocksProxyHelper.service. Zitiert seine Dokumentation (Hervorhebung hinzugefügt):

Konfiguriert Anforderungsabhängigkeiten, die dem Stil von sehr ähnlich sind Requires=. Dieser Abhängigkeitstyp ist jedoch stärker: Zusätzlich zu seiner Auswirkung Requires=wird deklariert, dass diese Einheit auch gestoppt wird , wenn die Einheit, an die gebunden ist, gestoppt wird . Dies bedeutet, dass eine Einheit, die an eine andere Einheit gebunden ist und plötzlich in den inaktiven Zustand wechselt, ebenfalls gestoppt wird. Einheiten können aus verschiedenen Gründen plötzlich und unerwartet in den inaktiven Zustand wechseln: Der Hauptprozess einer Wartungseinheit wird möglicherweise nach eigener Wahl beendet , das Sicherungsgerät einer Geräteeinheit wird möglicherweise vom Stromnetz getrennt, oder der Bereitstellungspunkt einer Bereitstellungseinheit wird möglicherweise ohne Beteiligung von entfernt der System- und Servicemanager.

In Verbindung mit After=demselben Gerät ist das Verhalten von BindsTo=sogar noch stärker. In diesem Fall muss sich die Einheit, die an gebunden ist, im aktiven Zustand befinden, damit sich diese Einheit ebenfalls im aktiven Zustand befindet . Dies bedeutet nicht nur eine Einheit an eine andere Einheit gebunden , dass plötzlich inaktiven Zustand eintritt, sondern auch eine , die an eine andere Einheit gebunden ist, die übersprungen aufgrund eines ausgefallenen Zustandsprüfung wird (wie ConditionPathExists=, ConditionPathIsSymbolicLink=, ... - siehe unten) wird gestoppt, sollte es in Betrieb sein. Daher ist es in vielen Fällen am besten, BindsTo=mit zu kombinieren After=.


  • Ist dies der richtige Weg, um einen "On-Demand-SSH-Socken-Proxy" einzurichten? Wenn nicht, wie machst du das?

Es gibt wahrscheinlich keinen "richtigen Weg". Diese Methode hat ihre Vorteile (alles ist "on-demand") und Nachteile (Abhängigkeit von systemd, die erste Verbindung kommt nicht durch, weil ssh noch nicht mit dem Abhören begonnen hat). Vielleicht ist es eine bessere Lösung, die systemd-Socket-Aktivierungsunterstützung in autossh zu implementieren.

Vladimir Panteleev
quelle
Ich habe BindsTo=SocksProxy.serviceden Unit-Abschnitt der Datei ~/.config/systemd/user/SocksProxyHelper.servicenach der After=SocksProxy.serviceZeile hinzugefügt . Ein manueller Neustart des SocksProxy-Dienstes ist jetzt nicht mehr erforderlich, wenn SSH stirbt / gets_killed. Gibt es eine Möglichkeit für systemd, die ursprüngliche Verbindung zu "halten", so dass es keinen TCP-Reset erhält?
Alex Stragies
@Vladimir Panteleev einen Punkt möchte ich klarstellen: Unterstützung für systemd Socket-Aktivierung kann relativ einfach durch Parsen $LISTEN_FDSohne Hinzufügen einer Abhängigkeit von implementiert werden sd_listen_fds(), so dass es immer noch ein harter Verkauf sein kann, aber nicht zu hart.
Amir