Letztens habe ich ein weiteren Kniff gelernt, der in Zusammenhang mit ssh-Verbindungen hilfreich ist.
Führt man mehrere ssh-Kommandos kurz hintereinander aus, muss für jede Verbindung ein erneuter Kontakt zum jeweiligen Server aufgebaut werden.
Das sind zwar immer (je nach Verbindung und Schnelligkeit des Servers) vielleicht nur ein paar Millisekunden, aber zum Beispiel in Zusammenhang mit Ansible-Playbooks kann sich das schon mal addieren und den Lauf durchaus in die Länge ziehen. Zudem ist es nicht sehr ressourcenschonend.
In der ssh-Konfiguration des aktuellen Benutzers
(~/.ssh/config) kann jedoch eine Option gesetzt werden, die ein Socket-File aufmacht und somit die Verbindung offen hält. Mit einem gesetzten Timeout von zum Beispiel 30 Minuten, muss nun nicht mehr jedes Mal eine neue Verbindung initiiert werden. Damit entfällt das ganze Geraffel mit Handshake etc.
Ansible-Playbooks laufen jetzt bei mir wesentlich schneller!
Konfiguration
Konfiguriert wird dieses Verhalten in der ssh-Konfiguration des jeweiligen Benutzers.
Der entsprechende Ausschnitt aus meiner ~/.ssh/config
1Host *
2 ControlPath ~/.ssh/connections/%C
3 ControlMaster auto
4 ControlPersist 30m
Eine paar kleine Erläuterungen und Hinweise zur obigen Datei:
Parameter Host
Das Asterik (*) hinter Host sagt, dass es für jeden Host gilt.
Parameter ControlPath
Das genannte Verzeichnis im ControlPath muss vorher angelegt werden:
1mkdir ~/.ssh/connections
Sofern das Unterverzeichnis ~/.ssh noch nicht existiert, muss es mit den richtigen Rechten angelegt werden.
1mkdir ~/.ssh
2chmod 700 ~/.ssh
Parameter ControlMaster
Dieser Parameter aktiviert erst die gemeinsame Benutzung von mehreren Sitzungen über eine einzelne Netzwerkverbindung. Erst damit wird diese Funktionalität nutzbar bzw. aktiviert.
Parameter ControlPersist
Hier wird die Haltedauer der Verbindung angegeben. In meinem Beispiel 30 Minuten. Nach Ablauf der definierten Zeitspanne werden die Sockets automatisch gelöscht.
Tipps
Problem-Lösungen
Ändern sich die Hostkeys des Servers einmal, kann das Socket-File einfach gelöscht werden.
Dies passiert zum Beispiel in der Entwicklung-Phase wenn neue VMs neu deployed werden müssen und sich dann der ssh-Hostkey ändert. ssh wertet dies beim erneuten Verbindungsversuch als massives Problem und verweigert den Verbindungsaufbau. In so einem Fall, kann das entsprechende Socket einfach gelöscht werden, statt 30 Minuten zu warten.
Warum %C ?
Ja, es gibt noch andere Parameter, wo der Dateinamen dann unter anderem dem Hostnamen entspricht. Dies würde das gezielte Löschen einzelner Sockets im oben beschrieben Fall vereinfachen.
Allerdings hat die Pfad-Länge von ControlPath eine maximal definierte Länge (den genauen Wert habe ich leider vergessen).
Der Parameter %C macht aus der Pfadangabe einen Hash-Wert, der dieses Problem umgeht.
VPN und das ControlPersist
Ich muss des öfteren mal VPN-Verbindungen wechseln. Leider hat dies (bisher) den unschönen Nebeneffekt gehabt, dass das Socket noch bestehen bleibt. Da ich mit jedem neuen Verbindungsaufbau allerdings eine neue Quell-IP etc. bekomme, komme ich nun nicht mehr auf das System. Nun muss ich das entsprechende Socket-File löschen. Da ich ja Hash-Werte benutze, ist das nicht so einfach, zudem ist es eine händische Arbeit; mag ich nicht.
Da ich faul bin, habe ich nach einer Lösung gesucht und gefunden.
Unterhalb von /etc/NetworkManager/dispatcher.d/ habe ich mir folgendes Script hingelegt:
1#!/usr/bin/bash
2# Connection-Pool aufräumen
3# Ort: /etc/NetworkManager/dispatcher.d
4find /home/rainerr/.ssh/connections -type f -delete
Jetzt wird bei jedem neuen VPN-Verbindungsaufbau einfach alles stumpf weggeworfen. \o/
Changelog
| Datum | Änderung |
|---|---|
| 08.02.2024 | neuer Absatz: VPN und das ControlPersist |