SSH-Verbindungs-Multiplexing: Risiken von Control-Sockets
SSH-Verbindungs-Multiplexing kann einen authentifizierten Zugriff offenhalten, nachdem eine Aufgabe beendet wurde. Erfahre, wie du Control-Sockets isolierst, Sitzungen schließt und Belege sicherst.

SSH-Verbindungs-Multiplexing kann einen authentifizierten Weg zu einem Host offenlassen, nachdem der Befehl, der ihn erstellt hat, beendet wurde. Dieses Verhalten ist beabsichtigt. Bei einer automatisierten Aufgabe, einem Agentenlauf oder einem Deployment-Job wird es jedoch leicht missverstanden, wenn dieser angeblich abgeschlossen ist.
Ich habe Teams dabei erlebt, wie sie ein vermeintlich geschlossenes Wartungsfenster untersuchten und feststellten, dass ein lokaler ssh-Master weiterhin einen aktiven Transport hielt, ein Socket noch neue Clients akzeptierte und ein späterer Befehl ihn ohne erneute interaktive Authentifizierung wiederverwendete. Nichts Ungewöhnliches war passiert. Die Konfiguration tat genau das, was OpenSSH dokumentiert. Das Team hatte das Ende eines Shell-Befehls mit dem Ende des Zugriffs gleichgesetzt.
Der entscheidende Unterschied liegt zwischen einem abgeschlossenen Clientbefehl und einem beendeten authentifizierten Transport. Multiplexing macht daraus zwei getrennte Ereignisse. Wenn du autonome Arbeit über SSH ausführst, müssen deine Bereinigung und deine Belege diesen Unterschied berücksichtigen.
Ein Control-Socket kann länger leben als der Befehl, der ihn geöffnet hat
SSH-Multiplexing verwendet eine einzige langlebige SSH-Verbindung, den Master, um Arbeit für spätere SSH-Clientprozesse zu übertragen. Diese späteren Clients werden in der OpenSSH-Dokumentation oft als Slaves bezeichnet. Ein Slave wiederholt den normalen Verbindungsaufbau und die Benutzerauthentifizierung nicht, wenn er den lokalen Master erfolgreich über dessen Control-Socket erreicht.
Eine typische Konfiguration wirkt harmlos:
Host build-box
HostName 192.0.2.44
User deploy
ControlMaster auto
ControlPath ~/.ssh/cm/%C
ControlPersist 20m
Der erste Aufruf von ssh build-box erstellt eine Netzwerkverbindung und einen Unix-Domain-Socket unter ~/.ssh/cm/. Spätere Befehle wie ssh build-box 'uname -a', scp und sftp können diesen Socket verwenden. Mit ControlPersist 20m bleibt der Master nach dem Ende seiner letzten Sitzung zwanzig Minuten verfügbar.
Diese Abfolge ist daher normal:
- Eine Aufgabe führt
ssh build-box 'apply-change'aus und endet mit Status null. - Der Master bleibt verbunden, weil
ControlPersistihn verfügbar halten soll. - Neunzehn Minuten später führt ein anderer lokaler Prozess
ssh build-box 'read-status'aus. - Dieser Prozess öffnet einen Kanal über den bereits authentifizierten Transport.
Der spätere Befehl kann durch das lokale Betriebssystem und die Socket-Berechtigungen autorisiert sein. Auf dem entfernten Host führt er jedoch nicht zu einer neuen SSH-Authentifizierung. Wer nur den ursprünglichen Anmeldeeintrag betrachtet, kann leicht annehmen, dass die Aktivität viel früher endete.
OpenSSH beschreibt ControlMaster im Handbuch zu ssh_config als Möglichkeit, mehrere Sitzungen über eine einzige Netzwerkverbindung zu führen, und ControlPersist als Möglichkeit, den Master im Hintergrund offen zu halten. Lies beides zusammen: ControlPersist ist nicht nur eine Einstellung zur Leistungsoptimierung. Die Option verändert den Zeitraum, in dem ein lokaler Prozess neue Kanäle auf einer authentifizierten Verbindung anfordern kann.
Für Menschen, die an einem Rechner arbeiten, kann dieser Kompromiss sinnvoll sein. Für aufgabenbezogene Automatisierung braucht er einen klar benannten Verantwortlichen und eine ausdrückliche Stop-Aktion.
Ein Authentifizierungsereignis ist kein Befehlsereignis
Teams vermischen oft Authentifizierung, Verbindung, Kanal und Befehl. In SSH sind das getrennte Dinge, und Multiplexing macht den Unterschied sichtbar.
Der ursprüngliche Master baut eine TCP-Verbindung zum Server auf, prüft den Host, handelt die Kryptografie aus und authentifiziert das Konto. Nach der Authentifizierung kann er SSH-Kanäle öffnen. Ein Shell-Befehl, eine interaktive Shell, eine SFTP-Übertragung, eine lokale Portweiterleitung und eine entfernte Portweiterleitung verwenden auf diesem Transport Kanäle oder kanalbezogene Anfragen.
Ein neuer lokaler ssh-Aufruf, der einen verwendbaren Control-Socket findet, sendet eine Anfrage über diesen Socket. Der Master entscheidet, ob er den gewünschten Kanal öffnet. Er benötigt den privaten Schlüssel nicht erneut. Eine erneute Agentenabfrage ist nicht nötig. Der Server muss keinen weiteren Anmeldeversuch erhalten.
Das bedeutet nicht, dass OpenSSH ein wiederverwendbares Passwort im Socket speichert. Diese Beschreibung ist ungenau und führt zu falschen Analysen. Das Sicherheitsproblem ist ein bereits authentifizierter Transport mit einer lokalen Schnittstelle, über die er zum Handeln aufgefordert werden kann. Ein Angreifer, der den Socket verwenden kann, braucht möglicherweise die ursprüngliche Zugangsinformation überhaupt nicht.
Dieser Unterschied verändert die Fragen bei einem Vorfall. Ob der Schlüssel auf der Festplatte verblieben ist, ist wichtig, entscheidet aber nicht darüber, ob der Zugriff bestehen blieb. Stelle stattdessen folgende Fragen:
- Blieb ein Masterprozess mit dem entfernten Ziel verbunden?
- Konnte ein anderer lokaler Prozess seinen Control-Socket erreichen?
- Akzeptierte der Master zusätzliche Sitzungen, Dateiübertragungen oder Weiterleitungsanfragen?
- Wer konnte unter dem Besitzer des Sockets laufen oder das Socket-Verzeichnis durchqueren?
- Wann wurde der Master tatsächlich beendet?
Ein Task-Runner, der den Exit-Code eines Befehls meldet, beantwortet keine dieser Fragen. Der Code beschreibt nur den Kindprozess, auf dessen Ende er gewartet hat.
Gemeinsame Sockets machen lokale Prozessgrenzen zu Zugriffsgrenzen
Ein Control-Socket ist ein lokaler Unix-Domain-Socket. Sein Speicherort und seine Berechtigungen im Dateisystem bestimmen, welche lokalen Prozesse versuchen können, mit dem Master zu kommunizieren. Deshalb kann ein weit gefasster ControlPath unabhängige Arbeiten miteinander verbinden, selbst wenn die Aliase der entfernten Hosts ordentlich aussehen.
Betrachte ein CI-Runner-Konto mit dieser Konfiguration:
Host *
ControlMaster auto
ControlPath /tmp/ssh-%r@%h:%p
ControlPersist 1h
Job A verbindet sich als deploy mit app.internal. Er erstellt einen Master und einen Socket in /tmp. Danach endet Job A. Job B läuft unter demselben lokalen Konto und verbindet sich mit demselben Ziel. Wenn Job B den Socket benennen und darauf zugreifen kann, kann er den von Job A authentifizierten Transport wiederverwenden.
Das ist beliebt, weil wiederholte Befehle dadurch ohne nennenswerte Änderungen an der Anwendung schneller werden. Für unabhängige Jobs ist es falsch, weil die Wiederverwendungsgrenze auf Host, Port und Benutzer basiert, nicht auf der Aufgabe, der die Berechtigung gehört. Ein gemeinsames Runner-Konto macht diesen Fehler zu einem regelmäßigen aufgabenübergreifenden Zugriff.
Das Verzeichnis ist genauso wichtig wie die Socket-Datei. Auf Unix-Systemen benötigt ein Prozess Suchberechtigung für Verzeichnisse, um einen Pfad erreichen zu können. Ein Socket in einem Verzeichnis mit privatem Besitzer und dem Modus 0700 schafft eine deutlich klarere Grenze als ein gemeinsam genutztes temporäres Verzeichnis. Die Berechtigungen der Socket-Datei selbst bleiben wichtig, aber sie sind nicht die gesamte Kontrolle.
Verwende ein für die Aufgabe erstelltes Verzeichnis, das dem ausführenden Konto gehört. Ein Shell-Wrapper kann das erledigen, ohne sich auf eine globale SSH-Konfiguration zu stützen:
set -eu
run_id="release-4821"
cm_dir="$HOME/.ssh/task-control/$run_id"
mkdir -p "$cm_dir"
chmod 700 "$cm_dir"
socket="$cm_dir/%C"
ssh -o ControlMaster=auto \
-o ControlPersist=5m \
-o ControlPath="$socket" \
build-box 'id && hostname'
Das %C-Token vermeidet einen langen ausgeschriebenen Namen und verringert Kollisionen zwischen unterschiedlichen Verbindungsparametern. Das OpenSSH-Handbuch zu ssh_config definiert es als Hash über Verbindungsdetails. Es enthält jedoch weder dein Deployment-Ticket noch deine Agentensitzung oder Aufgaben-ID. Das übergeordnete Verzeichnis liefert in diesem Beispiel die fehlende Grenze.
Lege einen Control-Socket nicht in einem ausgecheckten Repository, einem weitgehend beschreibbaren Arbeitsbereich oder einfach aus Bequemlichkeit in /tmp ab. Bequemlichkeit macht aus einem lokalen Socket eine versehentlich gemeinsam nutzbare Fähigkeit.
ControlPersist ist eine Aufbewahrungsrichtlinie, kein Bereinigungsplan
ControlPersist weist SSH an, einen Master verfügbar zu halten, nachdem Client-Sitzungen geschlossen wurden. Die Option akzeptiert yes, wodurch der Master unbegrenzt im Hintergrund läuft, oder einen Zeitwert wie 10m. Beides sind Entscheidungen über die Aufbewahrungsdauer.
Ein Timeout hilft, wenn ein Client vor der Bereinigung abstürzt. Es beweist nicht, dass die Aufgabe gleichzeitig mit dem Zugriff endete. Während des Timeouts kann ein Prozess mit Zugriff auf den Socket neue Arbeit anfordern. Eine Stunde ist besonders schwer zu rechtfertigen, wenn eine Deployment-Aufgabe zwei Minuten dauerte.
Es gibt Situationen, in denen ein kurzer Timeout sinnvoll ist. Ein kontrollierter Automatisierungsprozess kann mehrere Befehle nacheinander ausführen und von einer bestehenden Verbindung profitieren. In diesem Fall sollte der Timeout kürzer als die erwartete Leerlaufzeit sein. Isoliere den Socket auf diesen Lauf und beende ihn nach erfolgreichem Abschluss. Der Timeout dient dann als Rückfallebene bei Fehlern und nicht als gewöhnlicher Schließmechanismus.
Die Einstellung ControlPersist yes braucht einen Verantwortlichen mit einem langfristigen Grund für den Zugriff. Ein interaktiver Arbeitsplatz eines Administrators kann diesen Grund haben. Eine kurzlebige Aufgabe nicht.
Ein weiterer häufiger Fehler ist die Annahme, dass ein Befehlsfehler den Master schließt. Eine Shell kann nach einem fehlgeschlagenen entfernten Befehl frühzeitig zurückkehren, während der Hintergrund-Master weiterläuft. Eine Abbruchanforderung der Aufgabe kann dasselbe bewirken. Die Bereinigung muss nach Erfolg, Fehler und Unterbrechung laufen und festhalten, ob das Herunterfahren funktioniert hat.
Wenn deine Automatisierung einen Trap verwendet, halte die Bereinigung eng begrenzt und prüfe ihr Ziel. Entferne nicht blind zuerst den Socket-Pfad. Das Entfernen eines Pfads kann die Untersuchung erschweren, während Masterprozess und Verbindung weiter bestehen.
cleanup() {
ssh -S "$socket" -O exit build-box >/dev/null 2>&1 || true
rmdir "$cm_dir" 2>/dev/null || true
}
trap cleanup EXIT HUP INT TERM
Dieses Muster fordert den Master auf, sich zu beenden, bevor es versucht, das Verzeichnis zu entfernen. Wenn ssh -O exit fehlschlägt, bewahre das Verzeichnis auf und untersuche den Fehler, statt die Belege zu löschen. Schreibe in produktivem Code den Fehler, die Prozess-ID und den Socket-Pfad in den Aufgaben-Datensatz.
exit und stop haben unterschiedliche operative Bedeutungen
OpenSSH stellt Steuerbefehle über ssh -O bereit. Betreiber verwenden regelmäßig den falschen Befehl, weil beide Namen nach Bereinigung klingen.
ssh -O check host fragt, ob ein Master läuft, und meldet seine Prozess-ID, wenn einer antwortet. ssh -O exit host fordert den Master zum Beenden auf. Für eine abgeschlossene Aufgabe ist exit normalerweise der gewünschte Befehl, weil er den wiederverwendbaren Transport beendet.
ssh -O stop host weist einen Master an, keine neuen multiplexierten Sitzungen mehr anzunehmen. Bestehende Sitzungen laufen weiter. Das kann nützlich sein, wenn ein Betreiber aktive Arbeit auslaufen lassen muss. Es erfüllt jedoch nicht die Aussage, dass der gesamte SSH-Zugriff mit Abschluss der Aufgabe endete. Ein laufender Master mit aktiven Kanälen hat weiterhin eine aktive Netzwerkverbindung.
Verwende den Socket-Pfad ausdrücklich, wenn die Diagnose nicht von der aktuellen Konfiguration des Benutzers abhängen soll:
ssh -S "$socket" -O check build-box
# Master running (pid=41782)
ssh -S "$socket" -O exit build-box
# Exit request sent.
ssh -S "$socket" -O check build-box
# Control socket connect(...): No such file or directory
Die Wörter und der genaue Fehlertext unterscheiden sich je nach Plattform und OpenSSH-Version. Erfasse deshalb sowohl die Standardausgabe als auch die Standardfehlerausgabe, statt einen einzelnen Satz als feste Schnittstelle zu behandeln. Die Form der Belege ist entscheidend: Eine erfolgreiche Prüfung weist einen aktiven Master nach, ein erfolgreiches exit sendet die Beendigungsanforderung, und eine spätere fehlgeschlagene Prüfung stützt die Aussage, dass kein Control-Socket geantwortet hat.
Es gibt einen schwierigen Sonderfall. Nach dem Absturz eines Masters kann der Socket bestehen bleiben, und eine PID kann zwischen zwei Prüfungen verschwinden. Ein veralteter Pfad beweist nicht, dass der Zugriff noch besteht. Umgekehrt beweist eine nicht antwortende Prüfung nicht, dass die entfernte Verbindung beendet wurde, wenn du den Pfad vor der Untersuchung entfernt hast. Prüfe Prozesstabelle und offene Unix-Sockets, bevor du etwas löschst.
Unter macOS ist lsof oft das schnellste lokale Prüfwerkzeug:
lsof -nP -U | grep '/.ssh/task-control/'
ps -p 41782 -o pid=,ppid=,lstart=,etime=,command=
Speichere die Ausgabe im Aufgabendatensatz. Der erste Befehl ordnet einen Unix-Socket einem Prozess zu. Der zweite liefert Elternprozess, Startzeit, verstrichene Zeit und Aufrufdetails. Betrachte grep als interaktives Hilfsmittel, nicht als Auditkontrolle. Ein echter Collector sollte die relevanten Datensätze direkt abfragen und speichern.
Portweiterleitungen machen einen untätigen Master folgenreicher
Ein scheinbar untätiger Master kann weiterhin Weiterleitungsstatus halten oder eine spätere Weiterleitungsanfrage akzeptieren. Deshalb reicht es nicht aus, nur Shell-Befehle zu zählen.
Eine lokale Weiterleitung stellt einen lokalen Listener bereit, der Datenverkehr über die SSH-Verbindung sendet. Eine entfernte Weiterleitung weist den Server an, zu lauschen und Verbindungen über den Client zurückzusenden. Eine dynamische Weiterleitung erstellt einen SOCKS-Proxy. Je nachdem, wie Sitzung und Master gestartet wurden, können alle drei die Aufgabe überdauern, die sie eingerichtet hat.
Die OpenSSH-Handbücher dokumentieren Steuerbefehle wie forward und cancel für Weiterleitungsanfragen, wenn Multiplexing aktiv ist. Das ist operativ nützlich. Es bedeutet aber auch, dass ein Prozess, der den Socket erreicht, neben einem gewöhnlichen Shell-Befehl weitere Netzwerkpfade anfordern kann, abhängig von Serverrichtlinien und dem Zustand des Masters.
Behandle Weiterleitungen bei automatisierten Aufgaben als ausdrückliche Ausnahme. Erfasse Bind-Adresse, lokalen oder entfernten Port, Zielhost und Zielport sowie das Ergebnis der Bereinigung. Lass einen allgemeinen SSH-Wrapper nicht stillschweigend LocalForward, RemoteForward oder DynamicForward aus einer weit gefassten Host *-Konfiguration des Benutzers übernehmen.
Prüfe die aufgelösten Einstellungen, bevor du einem Alias vertraust:
ssh -G build-box | grep -E '^(controlmaster|controlpath|controlpersist|localforward|remoteforward|dynamicforward) '
ssh -G gibt die effektive Konfiguration aus, nachdem OpenSSH Host-Matching und Standardeinstellungen angewendet hat. Diese Prüfung findet einen überraschend häufigen Fehler: Eine Aufgabe verwendet einen einfachen Host-Alias, aber eine eingebundene Konfigurationsdatei aktiviert weit entfernt von der eigentlichen Aufgabenkonfiguration Multiplexing oder Weiterleitungen. Je nach Version kann der Befehl weitere Felder anzeigen. Speichere die vollständige Ausgabe von ssh -G, nicht nur die erwarteten Zeilen.
Ein entferntes System kann eine einzige Quellverbindung protokollieren, während mehrere weitergeleitete Anwendungsverbindungen darüber laufen. Netzwerk-Telemetrie, SSH-Serverprotokolle und Aufgabenprotokolle beantworten jeweils unterschiedliche Teile dieses Bildes. Keines kann die anderen ersetzen.
Serverprotokolle allein können die lokale Entscheidungskette nicht rekonstruieren
Der entfernte SSH-Server sieht den Transport und alles, was seine Protokollierung zu Kanälen und Befehlen festhält. Er kann jedoch nicht zuverlässig erkennen, warum ein lokaler Prozess die Berechtigung erhielt, einen Control-Socket zu verwenden, welcher Aufgabe das Socket-Verzeichnis gehörte oder ob ein anderer lokaler Prozess ihn nach dem Ende der ursprünglichen Aufgabe wiederverwendete.
Das ist kein Vorwurf an Serverprotokolle. Sie arbeiten an einer anderen Stelle des Systems. sshd kann Authentifizierungs- und Verbindungsereignisse aufzeichnen. Ein Wrapper für erzwungene Befehle oder ein Auditsystem kann entfernte Befehle erfassen. Diese Aufzeichnungen bleiben nützlich. Standardmäßig identifizieren sie jedoch nicht jeden lokalen Multiplex-Client, weil der Server alle Kanäle als Teil desselben bereits authentifizierten Transports sehen kann.
Bewahre Belege auf beiden Seiten der Grenze auf. Ein nützlicher Aufgabendatensatz enthält:
- die vollständig aufgelöste Clientkonfiguration aus
ssh -G, ohne Geheimnisse; - den entfernten Hostnamen, die Adresse, das Konto, das Ergebnis der Host-Fingerabdruckprüfung und die anfängliche PID des Masters;
- den Pfad des Control-Sockets, das private übergeordnete Verzeichnis sowie die beobachteten Erstellungs- und Endzeiten;
- jeden angeforderten entfernten Befehl, jede Übertragung und jede Weiterleitungsaktion mit ihrem Exit-Status;
- das Ergebnis von
checkvor der Bereinigung, das Ergebnis vonexitsowie die Prüfung von Prozess und Socket nach der Bereinigung.
Füge eine Aufgabenkennung zum Verzeichnisnamen und zum Protokolldatensatz hinzu, nicht zu einem globalen Control-Socket-Pfad, den jede Aufgabe gemeinsam verwendet. Die Kennung verbindet lokale Ereignisse, ist aber nicht allein eine Sicherheitsgrenze.
Das Hashen oder Signieren des Datensatzes nach der Erfassung hilft, spätere Änderungen zu erkennen. Fehlende Ereignisse lassen sich dadurch jedoch nicht reparieren. Erfasse Lebenszyklusereignisse während ihres Auftretens. Ein nach einem Vorfall aus der Shell-Historie zusammengesetzter Datensatz ist schwacher Beleg, besonders wenn Hintergrund-Master und Wiederholungsversuche beteiligt sind.
Bei agentengesteuerter Arbeit muss zwischen der Absicht des Agenten und der ausgeführten SSH-Aktion unterschieden werden. «Version X bereitstellen» ist eine Absicht. ssh build-box 'sudo systemctl restart api' ist eine Aktion. Der Datensatz zur Socket-Wiederverwendung zeigt, ob diese Aktion einen neuen Transport erhielt oder über einen bestehenden lief. Das sind unterschiedliche Audit-Fakten.
Aufgabenspezifische Sockets geben der Bereinigung einen Verantwortlichen
Das sicherste Muster für kurze automatisierte Arbeiten ist einfach: Verwende für jede Aufgabe ein eigenes Control-Socket-Verzeichnis, erlaube die Wiederverwendung nur innerhalb dieser Aufgabe und sende vor der Meldung des Abschlusses eine ausdrückliche exit-Anfrage.
Ein praktischer Wrapper braucht einen klaren Lebenszyklus. Er sollte das Verzeichnis mit restriktiven Berechtigungen erstellen, vor der ersten Verbindung einen Datensatz schreiben, Befehle mit demselben ausdrücklich gesetzten ControlPath ausführen, den Master beenden, das Ergebnis prüfen und erst dann das leere Verzeichnis entfernen. Eine Aufgabe, die die Bereinigung nicht überprüfen kann, sollte einen Bereinigungsfehler melden, selbst wenn der entfernte Befehl erfolgreich war.
Dieses Beispiel verwendet mktemp, um nicht selbst einen eindeutigen Verzeichnisnamen erraten zu müssen:
set -eu
base="$HOME/.ssh/task-control"
mkdir -p "$base"
chmod 700 "$base"
cm_dir=$(mktemp -d "$base/run.XXXXXX")
chmod 700 "$cm_dir"
socket="$cm_dir/%C"
finish() {
status=$?
ssh -S "$socket" -O exit build-box >>"$cm_dir/cleanup.log" 2>&1 || \
printf '%s\n' 'master exit request failed' >>"$cm_dir/cleanup.log"
ssh -S "$socket" -O check build-box >>"$cm_dir/cleanup.log" 2>&1 || true
exit "$status"
}
trap finish EXIT HUP INT TERM
ssh -o ControlMaster=auto \
-o ControlPersist=2m \
-o ControlPath="$socket" \
build-box 'deployctl apply release-4821'
Die kurze Einstellung ControlPersist deckt einen Prozess ab, der stirbt, bevor sein Trap ausgeführt wird. Sie sollte nicht als Erlaubnis verstanden werden, dass eine andere Aufgabe den Master wiederverwenden darf. Das zufällige Verzeichnis verhindert diese Wiederverwendung, weil die zweite Aufgabe den Pfad der ersten weder kennt noch übernimmt.
Vor der Übernahme dieses genauen Beispiels ist eine Korrektur nötig: Schreibe keine sensiblen Befehlsargumente, Umgebungswerte oder kopierten privaten Daten in cleanup.log. Auditdatensätze müssen genug Details enthalten, um festzustellen, wer was getan hat. Sie dürfen jedoch kein neuer Geheimnisspeicher werden. Maskiere Argumente an der Grenze des Wrappers, solange du ihre Bedeutung noch kennst.
Sallyport leitet SSH-Aktionen über seinen gebündelten zustandslosen Helfer sp-ssh weiter und bewahrt SSH-Schlüssel in seinem verschlüsselten Tresor auf, statt sie dem Agenten zugänglich zu machen. Dadurch entfällt ein häufiger Fehler bei der Verwaltung von Zugangsdaten. Teams sollten dennoch die Aktionsgrenze definieren und Datensätze aufbewahren, aus denen hervorgeht, wann der Lauf beendet wurde.
Globale Komforteinstellungen unterlaufen Aufgabengrenzen
Ein globaler Host *-Abschnitt aktiviert Multiplexing oft für jede interaktive Shell, jedes Skript, Repository und jeden untergeordneten Automatisierungsprozess eines Kontos. Das ist zu weit gefasst, wenn dasselbe Konto Aufgaben mit unterschiedlichen Freigaben oder Verantwortlichen ausführt.
Die Einstellung kann aus Include-Dateien, Konfigurationsmanagement, persönlichen Dotfiles eines Entwicklers oder einem Build-Image stammen. Auch die Befehlszeile kann sie überschreiben. Leite das aktive Verhalten nie aus einer einzigen sichtbaren Konfigurationsdatei ab. Verwende ssh -G mit dem genauen Host-Alias und dem Benutzerkontext, den die Aufgabe verwendet.
Wenn eine Automatisierungsumgebung keinen privaten ControlPath garantieren kann, deaktiviere Multiplexing für diese Aktion:
ssh -o ControlMaster=no \
-o ControlPath=none \
build-box 'maintenancectl status'
Das kostet für jeden Aufruf eine neue Verbindung und Authentifizierung. Für Aktionen mit hohen Folgen, seltenen Notfallzugriff oder Arbeit, die Aufgaben- und Vertrauensgrenzen überschreitet, ist das ein guter Preis. Die wiederholte Authentifizierung liefert ein klareres Autorisierungsereignis und macht die Betrachtung des Lebenszyklus deutlich eindeutiger.
Verwechsle ControlMaster=auto nicht mit einer Garantie, dass ein Prozess nur seine eigene Verbindung wiederverwendet. auto bedeutet, dass der Client versucht, einen Master am konfigurierten Pfad zu finden, und einen neuen erstellt, wenn er keinen findet. Der konfigurierte Pfad entscheidet, wessen Verbindung er finden kann.
Manche Teams argumentieren, ein gemeinsamer Socket sei unproblematisch, weil alle Jobs unter einem Dienstkonto laufen. Das stimmt nur, wenn jeder Job mit dieser Unix-Identität dieselbe Berechtigung hat, über dieses Konto auf jedes Ziel zuzugreifen, und wenn das Team akzeptiert, dass ein Job den aktiven Transport eines anderen erben kann. In den meisten ausgereiften Umgebungen ist das tatsächlich nicht gewünscht.
Ein sauberes Aufgabenende braucht einen Nachweis über das Schließen des Transports
Erkläre eine SSH-Aufgabe nicht für abgeschlossen, sobald der letzte entfernte Befehl zurückkehrt. Erkläre sie erst dann für abgeschlossen, wenn die Aufgabe ihren Master geschlossen und dies nachweisbar aufgezeichnet hat oder gemeldet hat, dass dies nicht möglich war.
Der abschließende Datensatz sollte einem Ermittler zeigen, ob ein späterer Befehl die Verbindung noch hätte wiederverwenden können. Er braucht eine Aufgabenidentität, die aufgelöste SSH-Konfiguration, den Socket-Pfad, Details zum Masterprozess, Aktivitätsaufzeichnungen, die Ergebnisse ausdrücklicher Steuerbefehle und die Beobachtung nach der Bereinigung. Außerdem braucht er Belege vom entfernten System für Änderungen, die unabhängig von SSH weiterliefen, etwa einen Neustart eines Dienstes oder einen abgelösten Prozess.
Lege einen Standard fest, den Betreiber auch unter Druck ausführen können: Socket isolieren, vor der Bereinigung prüfen, exit anfordern, bestätigen, dass kein Master antwortet, und das Ergebnis aufbewahren. Dieses Verfahren ist nützlicher als ein langes Standard-Timeout, weil es eine Annahme über den Zugriff in eine überprüfbare Tatsache verwandelt.
Wenn die Arbeit so sensibel ist, dass ein verbliebener authentifizierter Transport nicht akzeptabel wäre, optimiere sie nicht mit einem gemeinsam genutzten Master. Öffne eine neue Verbindung, führe die Aktion aus, schließe sie und bewahre den Datensatz auf. Die zusätzlichen Sekunden sind günstiger, als erklären zu müssen, warum ein Zugriffspfad nach dem vermeintlichen Ende der Aufgabe weiterbestand.
FAQ
Kann SSH ControlMaster eine authentifizierte Verbindung nach dem Ende meines Befehls am Leben halten?
Ja. Eine ControlMaster-Verbindung authentifiziert sich einmal. Danach können spätere SSH-Clients den lokalen Master auffordern, neue Kanäle zu öffnen. Wenn ControlPersist den Master am Leben hält, können diese späteren Kanäle noch geöffnet werden, nachdem der ursprüngliche Befehl und die Aufgabe, die ihn gestartet hat, bereits beendet sind.
Was ist der Unterschied zwischen einer SSH-Master- und einer Slave-Verbindung?
Der Masterprozess ist die ursprüngliche SSH-Verbindung, die den Netzwerktransport und den lokalen Control-Socket besitzt. Ein Slave-Prozess ist ein später ausgeführter SSH-Befehl, der diesen Socket kontaktiert und den Master auffordert, eine Sitzung, Weiterleitung oder einen anderen Kanal zu öffnen.
Wie schließe ich einen gemeinsam genutzten SSH-Control-Socket sicher?
Verwende ssh -O exit host-alias, wenn deine Konfiguration den Host-Alias auf den gewünschten ControlPath auflöst. Wenn du den Socket direkt angeben musst, verwende ssh -S /path/to/socket -O exit host. Prüfe vorher mit -O check, damit nicht versehentlich die falsche Verbindung beendet wird.
Ist SSH-Multiplexing für Automatisierung sicher?
SSH-Multiplexing vermeidet wiederholte Authentifizierungen und macht viele kurze SSH-Befehle deutlich schneller. Es ist unsicher, wenn niemand für seine Lebensdauer verantwortlich ist, mehrere unabhängige Aufgaben dasselbe Socket-Verzeichnis verwenden oder eine Aufgabe nach Ablauf der Freigabegrenze weiterhin Kanäle öffnen kann.
Zeigen SSH-Serverprotokolle jeden über Multiplexing gesendeten Befehl?
Der entfernte SSH-Server zeichnet oft eine einzige Transportanmeldung auf und erkennt spätere lokale Befehle möglicherweise nicht als neue Authentifizierungsereignisse. Wenn du Aktivitäten belastbar nachvollziehen musst, erfasse Clientprozesse, Multiplexing-Konfiguration, Lebenszyklusereignisse des Control-Sockets und Befehlsprotokolle auf Aufgabenebene.
Sollte ich mich bei der SSH-Bereinigung auf ein ControlPersist-Timeout verlassen?
Ein Timeout ist eine Obergrenze, aber kein Beleg dafür, dass die Verbindung mit dem Ende der Aufgabe geschlossen wurde. Verwende bei der Bereinigung ssh -O exit und bestätige anschließend, dass der Socket verschwunden ist und ssh -O check fehlschlägt. Für abgestürzte Clients bleibt ein Timeout ein sinnvoller Rückfallmechanismus.
Wo sollten SSH-Control-Sockets gespeichert werden?
Behandle Control-Sockets wie lokale Zugangsdaten. Lege sie in einem privaten Verzeichnis ab, das dem ausführenden Konto gehört, verwende einen aufgabenbezogenen Pfad, meide gemeinsam genutzte temporäre Verzeichnisse und entferne veraltete Pfade erst, nachdem du geprüft hast, ob noch ein Masterprozess sie besitzt.
Was bedeutet %C in SSH ControlPath?
ControlPath legt den Pfad des Unix-Sockets fest. %C wird zu einem aus Verbindungsattributen abgeleiteten Hash und verhindert viele Probleme mit Pfadlängen und Namenskollisionen. Eine eigene Identität für die Aufgabe entsteht dadurch jedoch nicht.
Macht das Schließen des SSH-Masters bereits gestartete Arbeit auf dem entfernten Host rückgängig?
Nein. Das Schließen eines multiplexierten Transports beendet die authentifizierte Verbindung auf der Clientseite. Es macht jedoch keine bereits auf dem entfernten Host ausgeführten Änderungen rückgängig, beendet keinen abgelösten entfernten Prozess und widerruft keine Zugangsdaten, die eine andere Sitzung noch verwenden kann. Die Bereinigung muss die entfernte Arbeit separat abdecken.
Welche Belege sollten wir nach dem Ende einer automatisierten SSH-Aufgabe aufbewahren?
Beginne mit einem reproduzierbaren Datensatz: der vollständig aufgelösten SSH-Konfiguration, der Prozess-ID des Masters, dem Socket-Pfad, dem entfernten Ziel, Start- und Endzeit sowie dem Ergebnis eines expliziten Abschaltbefehls. Bewahre diesen Datensatz zusammen mit dem Befehlsprotokoll der Aufgabe und den relevanten Protokollen des entfernten Hosts auf.