8 Min. Lesezeit

Wie eine SSH-Readiness-Checkliste die Sicherheit von Agenten verändert

Nutzen Sie diese SSH-Readiness-Checkliste, um Ergebnisparsing, Host-Identität, Idempotenz, Freigaben und unbekannte Remote-Zustände zu testen, bevor Agenten Shell-Zugriff erhalten.

Wie eine SSH-Readiness-Checkliste die Sicherheit von Agenten verändert

Schreibgeschütztes HTTP ist für einen Agenten ein nachsichtiger erster Kanal. Die Anfrage hat eine Methode, ein begrenztes Ziel, einen Statuscode, Header und meist einen Body mit dokumentierter Form. Ein fehlgeschlagenes GET lässt den Dienst normalerweise unverändert. Anmeldedaten können trotzdem falsch behandelt oder sensible Daten offengelegt werden, aber das Ausführungsmodell gibt Prüfern etwas Überschaubares, über das sie nachdenken können.

SSH verändert die Risikoeinheit. Der Agent ruft keine einzelne definierte Operation auf. Er sendet Text an eine Remote-Shell, deren Verhalten vom Login-Konto, der Shell, dem Arbeitsverzeichnis, der Umgebung, dem Betriebssystem, installierten Werkzeugen, Regeln für Anführungszeichen und dem aktuellen Maschinenzustand abhängt. Ein Befehl kann teilweise erfolgreich sein, die Verbindung verlieren, bevor er sein Ergebnis meldet, und beim nächsten Wiederholungsversuch doppelt ausgeführt werden.

Das macht SSH nicht ungeeignet für Agenten. Es bedeutet, dass „der HTTP-Kanal hat funktioniert“ ein schwacher Beleg dafür ist, SSH hinzuzufügen. Der Zulassungstest muss fünf getrennte Eigenschaften abdecken: vertrauenswürdiges Parsen von Ergebnissen, verifizierte Host-Identität, sicher wiederholbare Befehle, Freigaben mit beschriebenen Folgen und eine ausdrückliche Behandlung unbekannter Remote-Zustände. Fehlt eine davon, bleibt der zweite Kanal ausgeschaltet.

SSH als anderes Ausführungsmodell behandeln

SSH-Readiness beginnt mit der Einsicht, dass eine Remote-Shell kein HTTP-Transport mit einer anderen URL ist. HTTP-APIs stellen Operationen bereit, die der Server auswählt. SSH stellt einen Interpreter bereit, den das Remote-Konto auswählt, und bittet dann den Client, eine unstrukturierte Befehlszeichenfolge dorthin zu transportieren.

Bei einem schreibgeschützten HTTP-Aufruf kann ein Prüfer die Wirkung oft aus GET, dem Host und dem Pfad ableiten. Auch eine Antwort wie Status 404 hat im Protokoll einen üblichen Platz, selbst wenn die Anwendung ihr eine fachliche Bedeutung gibt. Bei SSH kann test -f /srv/app/release && cat /srv/app/release mit 1 enden, weil die Datei fehlt, während cat /srv/app/release mit 1 enden kann, weil die Berechtigung verweigert wird. Wenn Ihr Parser beides auf „Befehl fehlgeschlagen“ reduziert, kann der Agent nicht sicher entscheiden, was als Nächstes zu tun ist.

Auch die Remote-Umgebung verändert die Bedeutung. sed -i verhält sich auf gängigen Betriebssystemen unterschiedlich. Eine Login-Shell kann Startdateien einlesen, die Banner auf stdout ausgeben. PATH kann einen Wrapper statt des erwarteten Programms finden. Locale-Einstellungen können menschenlesbare Diagnosen verändern. Ein Pseudo-Terminal kann Verhalten für Menschen mit Verhalten für einen Parser vermischen. Keine dieser Variablen erscheint in einem typischen HTTP-Anfrageschema.

Schreiben Sie einen Kanalvertrag, bevor Sie Befehle aktivieren. Er sollte den Remote-Benutzer, akzeptierte Hosts, die Shell, das Startverzeichnis, die Umgebungsrichtlinie, das Verbot oder die Zulässigkeit eines Pseudo-Terminals, maximale Laufzeit, Ausgabelimits und das genaue Ergebnisformat festlegen. Verankern Sie ausführbare Pfade für sensible Aktionen. Setzen Sie ein bekanntes Locale, wenn Sie Text verarbeiten müssen. Bevorzugen Sie maschinenlesbare Ausgabe des Remote-Programms, doch nehmen Sie nie an, dass die JSON-Option eines Programms die umgebende Shell strukturiert macht.

Verwenden Sie einen nicht interaktiven Test als erstes Tor:

/usr/bin/ssh \
  -o BatchMode=yes \
  -o StrictHostKeyChecking=yes \
  -o ConnectTimeout=10 \
  -T [email protected] \
  'umask 077; printf "%s\n" "{\"probe\":\"ssh-ready\",\"version\":1}"'

OpenSSH dokumentiert BatchMode=yes so, dass Rückfragen deaktiviert werden, darunter Passwort- und Host-Schlüssel-Bestätigungen. -T deaktiviert die Zuweisung eines Pseudo-Terminals. StrictHostKeyChecking=yes verweigert unbekannte oder geänderte Schlüssel. Das erwartete stdout ist ein JSON-Objekt, stderr ist leer und der Remote-Exit-Status ist null. Testen Sie jede Abweichung separat. Ein System, das einen unbekannten Host nicht von fehlerhaftem JSON unterscheiden kann, hat dieses Tor nicht bestanden.

Das Ergebnisformat eindeutig machen

Das Parsen von Ergebnissen ist erst bereit, wenn Transportfehler, Remote-Beendigung, stdout und stderr getrennt bleiben. Sie in ein einziges Textfeld zusammenzuführen, schafft gefährliche falsche Sicherheit.

RFC 4254 definiert stdout als Kanaldaten und stderr als erweiterte Kanaldaten. Er definiert auch Nachrichten für exit-status und exit-signal, doch die Formulierung ist wichtig: Das Senden eines Exit-Status wird empfohlen, ist aber nicht vorgeschrieben, und der Client kann ihn ignorieren. OpenSSH legt über dieses Protokoll eine nützliche lokale Konvention. Sein Befehl ssh endet mit dem Status des Remote-Befehls oder mit 255, wenn ein Fehler auftritt.

Machen Sie diese Konvention nicht zur universellen Wahrheit. Ein Remote-Programm kann selbst mit 255 enden, was an der Prozessgrenze mit dem Client-Fehlerwert von OpenSSH kollidiert. Ein Server oder eine Bibliothek kann die Nachricht exit-status weglassen. Ein Signal ist nicht dasselbe wie ein gewöhnlicher Exit mit einem von null verschiedenen Wert. Der Kanal kann sich nach der Ausgabe schließen, bevor Ihr Client einen endgültigen Status erhält.

Ihr internes Ergebnis sollte wie ein typisierter Datensatz aussehen, nicht wie ein Transkript:

{
  "phase": "completed",
  "transport": "ok",
  "host": "host.example",
  "host_key_fingerprint": "SHA256:verified-value",
  "exit_status": 0,
  "exit_signal": null,
  "stdout": "{\"state\":\"present\",\"release\":\"2026.07\"}\n",
  "stderr": "",
  "truncated": false,
  "started_at": "request timestamp",
  "finished_at": "result timestamp"
}

Halten Sie exit_status optional. phase muss mindestens zwischen rejected, not-started, started, completed und unknown unterscheiden. Erfassen Sie Kürzung als Datenwert. Schneiden Sie Ausgabe niemals still ab und geben Sie den Rest als vollständig an den Agenten weiter. Hängen Sie den verifizierten Host-Fingerabdruck an, der für diese Verbindung verwendet wurde, nicht nur den Hostnamen, den der Agent angefragt hat.

Testen Sie dann eine Ergebnismatrix. Führen Sie einen Befehl aus, der mit leerer Ausgabe erfolgreich ist, einen, der nach Schreiben in beide Streams mit 7 endet, einen, der durch ein Signal beendet wird, einen, der die Frist überschreitet, einen, der ungültiges UTF-8 ausgibt, falls Ihr Stack Bytes zulässt, und einen, der jedes Ausgabelimit überschreitet. Trennen Sie die Client-Verbindung, während ein Remote-Befehl schläft, und prüfen Sie danach das Ergebnis. Ihr Adapter darf nicht exit_status: 0 erfinden, Erfolg aus stdout ableiten oder einen Timeout „fehlgeschlagen“ nennen, wenn er nicht beweisen kann, ob der Befehl lief.

Die Zusammensetzung von Shell-Befehlen verdient eigene Tests. POSIX legt fest, dass eine Pipeline normalerweise den Status ihres letzten Befehls meldet, sofern pipefail nicht aktiviert ist. Daher kann generate | upload Erfolg melden, weil upload leere Eingabe akzeptierte, nachdem generate fehlgeschlagen war. Verlassen Sie sich nicht auf die Standardwerte einer interaktiven Shell. Packen Sie Operationen mit mehreren Befehlen in geprüfte Skripte mit expliziter Fehlerbehandlung und Version und rufen Sie dann einen einzigen Skript-Einstiegspunkt auf.

Hosts verifizieren, bevor ein Agent sie erreichen kann

Die Host-Verifizierung ist ein Inventarproblem, keine Rückfrage, die ein Agent beantworten sollte. Eine gültige Benutzerberechtigung beweist dem Server, wer der Client ist. Der Host-Schlüssel des Servers beweist dem Client, welcher Server geantwortet hat. Sie brauchen beides.

Verwenden Sie StrictHostKeyChecking=no niemals als Lösung für die Automatisierung. Die aktuelle OpenSSH-Dokumentation sagt, dass diese Einstellung neue Schlüssel automatisch hinzufügen kann und eine Verbindung bei geändertem Host-Schlüssel unter Einschränkungen fortsetzen darf. accept-new ist besser, weil es geänderte Schlüssel ablehnt, vertraut aber weiterhin der ersten Verbindung. Für einen Agentenkanal stellen Sie Vertrauen vor dem Lauf bereit und verwenden Sie StrictHostKeyChecking=yes.

ssh-keyscan hilft beim Erfassen öffentlicher Host-Schlüssel, authentifiziert sie aber nicht. Das eigene Handbuch warnt, dass ein Netzwerkangreifer einen Schlüssel ersetzen kann, und empfiehlt, die Ausgabe außerhalb des Netzes zu verifizieren oder das Werkzeug nur in einem vertrauenswürdigen Netzwerk einzusetzen. Seine Live-Ausgabe direkt nach known_hosts zu kopieren, verwandelt einen Verifizierungsschritt in eine Aufzeichnung dessen, was zuerst geantwortet hat.

Beschaffen Sie Fingerabdrücke über eine unabhängige Steuerungsebene: eine Cloud-Instanzkonsole, einen Image-Build-Nachweis, ein vom Host-Eigentümer geprüftes Konfigurations-Repository oder die direkte Übergabe durch einen Administrator. Speichern Sie Hostname, Port, erlaubte Host-Schlüssel-Algorithmen, Fingerabdrücke, Eigentümer, Umgebung und das Verfahren zur Rotation. Prüfen Sie auch Aliasse und Jump Hosts. Das Endziel kann perfekt verankert sein, während ein nicht verankerter Jump Host den Vertrauenspfad bricht.

Eine nützliche Zulassungsprüfung vergleicht beobachtete und genehmigte Schlüssel, ohne Vertrauen zu verändern:

ssh-keyscan -T 5 -t ed25519 host.example > observed.keys
ssh-keygen -lf observed.keys

Die Fingerabdruckausgabe enthält Felder für Bitlänge, Fingerabdruck, Host-Bezeichnung und Schlüsseltyp. Ein Mensch oder ein vertrauenswürdiger Inventardienst vergleicht den Fingerabdruck mit dem unabhängig bereitgestellten Wert. Erst nach dieser Übereinstimmung sollte die Automatisierung den known-hosts-Eintrag installieren. Der Scan ist ein zu vergleichender Nachweis, kein vertrauenswürdiger Nachweis.

Planen Sie die Rotation, bevor Sie die Verankerung durchsetzen. UpdateHostKeys von OpenSSH kann zusätzliche Schlüssel lernen, nachdem sich der Server bereits mit einem vertrauenswürdigen Schlüssel authentifiziert hat. Das unterstützt eine schrittweise Rotation. Ob Sie diese Erweiterung nutzen oder einen neuen known-hosts-Satz verteilen: Definieren Sie eine Überschneidungsperiode und einen Notfallweg. Ein geänderter Schlüssel sollte die Ausführung stoppen und einen eigenen Identitätsfehler erzeugen. Er darf niemals einen allgemeinen Wiederholungsversuch, das automatische Löschen des alten Eintrags oder eine Freigabekarte auslösen, die einen eiligen Prüfer bittet, einen unerklärten Fingerabdruck zu akzeptieren.

Idempotenz an der Wirkungsgrenze verlangen

Ein Befehl lässt sich nur dann sicher wiederholen, wenn die Wiederholung nach einer beliebigen Teilausführung denselben beabsichtigten Zustand erzeugt, ohne die Wirkung zu verdoppeln. Schreibgeschützte Syntax verleiht diese Eigenschaft nicht, und ein Exit-Status null beweist sie nicht.

Einige Befehle sind von Natur aus wiederholbar: eine feste Datei lesen, einen Dienstzustand prüfen oder mit mkdir -p unter kontrollierten Berechtigungen ein Verzeichnis erstellen. Andere brauchen Schutzprüfungen. Eine Zeile mit echo ... >> file anzuhängen, eine Benachrichtigung zu senden, einen Benutzer mit generierter Kennung anzulegen, über ein lokales Werkzeug ein Konto zu belasten oder einen Dienst neu zu starten, ist nicht sicher, nur weil der Shell-Befehl kurz ist.

Der übliche Rat, „vorübergehende SSH-Fehler wiederholen“, ist auf dieser Ebene falsch. Er ist verbreitet, weil ein erneuter Verbindungsaufbau viele Netzwerkfehler behebt und HTTP-Client-Bibliotheken Wiederholungen normalisieren. SSH kann die Verbindung verlieren, nachdem der Remote-Prozess seine Änderung festgeschrieben hat, aber bevor der Client den Exit-Status erhält. Eine automatische Wiederholung führt die bereits abgeschlossene Aktion dann erneut aus.

Verlagern Sie die Wiederholungssicherheit in die Remote-Operation. Geben Sie jeder verändernden Anfrage eine stabile Vorgangs-ID, die vor der Freigabe erzeugt wird. Speichern Sie diese ID, wenn möglich, zusammen mit der Wirkung in derselben Transaktion. Läuft die Operation erneut, geben Sie das gespeicherte Ergebnis zurück, statt die Änderung erneut anzuwenden. Wo keine Transaktion Markierung und Wirkung umfasst, fügen Sie eine Abstimmungsabfrage hinzu, die bestimmen kann, welche Seite abgeschlossen wurde.

Ein kleines Deployment-Skript kann den Vertrag sichtbar machen:

#!/bin/sh
set -eu

op_id=$1
release=$2
state_dir=/var/lib/agent-ops
record="$state_dir/$op_id"

test -d "$state_dir" || exit 70
if test -f "$record"; then
  cat "$record"
  exit 0
fi

current=$(/usr/bin/readlink /srv/app/current || true)
if test "$current" = "/srv/app/releases/$release"; then
  /usr/bin/printf '{"operation":"%s","state":"already-current"}\n' "$op_id"
  exit 0
fi

test -d "/srv/app/releases/$release" || exit 66
/usr/bin/ln -sfn "/srv/app/releases/$release" /srv/app/current.new
/usr/bin/mv -f /srv/app/current.new /srv/app/current
/usr/bin/printf '{"operation":"%s","state":"changed","release":"%s"}\n' \
  "$op_id" "$release" > "$record.tmp"
/usr/bin/mv -f "$record.tmp" "$record"
cat "$record"

Dieses Beispiel ist nicht überall atomar. Der Symlink-Tausch und der Vorgangsdatensatz sind zwei Dateisystemänderungen, sodass ein Absturz zwischen ihnen eine Lücke hinterlässt. Die explizite Prüfung von current stimmt diese spezielle Lücke ab. Ihre Operation braucht einen Schutz, der an ihre eigene Wirkung gebunden ist, keinen allgemeinen Marker, der aus diesem Skript kopiert wurde.

Klassifizieren Sie jeden erlaubten Befehl als schreibgeschützt, konvergent, dedupliziert oder nicht wiederholbar. Konvergent bedeutet, dass wiederholte Ausführung auf einen erklärten Zustand zuläuft, etwa beim Setzen eines Konfigurationswerts. Dedupliziert bedeutet, dass die Remote-Seite die Vorgangs-ID erkennt. Nicht wiederholbare Aktionen benötigen nach einer Unsicherheit eine getrennte Statusabfrage und eine menschliche Entscheidung. Kann der Eigentümer einen Befehl nicht klassifizieren, lassen Sie ihn nicht zu.

Dem Prüfer die Wirkung zeigen, nicht den Shell-Text

SSH-Schlüssel von Agenten fernhalten
Sallyport bewahrt den SSH-Schlüssel in seinem verschlüsselten Vault auf und führt den Befehl selbst aus.

Eine Freigabe ist nur dann nützlich, wenn ein Prüfer vor der Aktion Ziel, Berechtigung, beabsichtigte Wirkung und die schlimmste plausible Folge erkennen kann. Rohtext der Shell ist ein notwendiger Nachweis, aber eine schlechte Zusammenfassung.

Vergleichen Sie systemctl restart api mit einer Freigabe, die sagt: Produktionshost api-03, Remote-Benutzer deploy, Dienst api neu starten, aktive Verbindungen können abbrechen, Vorgangs-ID rel-2026-07-24-04, Befehlsversion restart-service/v2. Die zweite Beschreibung gibt dem Prüfer Fakten, die er mit einer Änderung abgleichen kann. Sie zeigt auch fehlenden Kontext. Kann der Agent nicht sagen, welchen Host oder Dienst er betrifft, sollte er keine Freigabe erhalten.

Die Freigabe-Nutzdaten sollten an die exakte Ausführungsanfrage gebunden sein. Nehmen Sie den kanonischen Host und Port, den verifizierten Fingerabdruck, das Remote-Konto, den Digest des Befehls oder geprüften Skripts, normalisierte Argumente, Arbeitsverzeichnis, Ergänzungen der Umgebung, Timeout, angeforderte Berechtigungsänderung, Vorgangs-ID und die Information auf, ob die Aktion wiederholbar ist. Hashen Sie diese Nutzdaten und führen Sie nur den genehmigten Hash aus. Andernfalls kann ein Agent für einen Befehl Freigabe erhalten und vor dem Versand ein Argument ändern.

Stellen Sie Shell-Quoting exakt dar, verlangen Sie aber nicht, dass ein Prüfer es gedanklich ausführt. Parsen Sie nur Befehlsformen, die Sie selbst kontrollieren. Bleibt beliebiger Shell-Text im Umfang, kennzeichnen Sie ihn als beliebig und zeigen Sie die ganze Zeichenfolge ohne Auslassungen. Markieren Sie Umleitungen, Befehlssubstitution, Pipes, Ausführung im Hintergrund, sudo, Dateilöschung, Berechtigungsänderungen, Paketoperationen, Dienststeuerung und Netzwerk-Downloads. Eine Markierung ist kein Urteil. Sie zeigt dem Prüfer, wo Folgen verborgen sein können.

Der Umfang einer Freigabe muss mit wachsenden Wirkungen enger werden. Eine Sitzungsfreigabe kann für feste, schreibgeschützte Tests gegen ein genehmigtes Inventar angemessen sein. Eine Freigabe pro Aufruf passt zu Zustandsänderungen, der Nutzung eines privilegierten Remote-Kontos oder Befehlen, deren Argumente das Ziel auswählen. Lassen Sie nicht zu, dass eine harmlose Freigabe für uname stillschweigend ein späteres Deployment autorisiert, nur weil beide denselben SSH-Schlüssel nutzen.

Die festen Kontrollen von Sallyport passen sauber zu dieser Trennung: Die Sitzungsautorisierung identifiziert einen neuen Agentenprozess, während ein Schlüssel pro Aufruf eine Freigabe bei jeder Nutzung verlangen kann. Die wichtige Designarbeit liegt weiterhin in der Anfrage: Die Karte muss die Remote-Wirkung offenlegen, denn der Besitz eines genehmigten Kanals erklärt nicht, was ein Befehl bewirkt.

Testen Sie die Integrität von Freigaben, nicht nur ihr Erscheinungsbild. Ändern Sie ein Byte eines genehmigten Arguments und bestätigen Sie, dass die Ausführung stoppt. Lassen Sie zwei Anfragen um dieselbe Vorgangs-ID konkurrieren. Widerrufen Sie die Sitzung zwischen Freigabe und Versand. Sperren Sie den Anmeldedatenspeicher, nachdem die Karte erscheint. Jeder Test sollte mit einer aufgezeichneten Ablehnung oder einer erneut zu genehmigenden Anfrage enden, niemals mit einer Ausführung nach bestem Bemühen.

Unbekannten Remote-Zustand als Ergebnis erster Klasse modellieren

Unbekannt ist ein gültiges Ergebnis, wenn der Client nicht beweisen kann, ob die Remote-Wirkung abgeschlossen wurde. Es als Fehler zu bezeichnen, lädt zu Wiederholungen ein. Es Erfolg zu nennen, verbirgt unvollendete Arbeit.

Betrachten Sie eine häufige Abfolge. Ein Agent verbindet sich, startet ein Skript und das Skript ersetzt eine Konfigurationsdatei. Das Neuladen des Dienstes beginnt. In diesem Moment bricht der Netzwerkpfad ab. Der Client erhält weder Exit-Status noch endgültiges stdout. Ein lokaler Timeout tritt ein und markiert den Aufruf als fehlgeschlagen. Der Agent wiederholt ihn. Der zweite Lauf sieht die neue Datei, sendet ein weiteres Neuladen und überschreibt möglicherweise den Diagnosedatensatz des ersten Laufs. Der ursprüngliche Aufruf hat tatsächlich gearbeitet, obwohl der Client seinen Abschluss nie beobachtet hat.

RFC 4254 macht diese Mehrdeutigkeit erwartbar. Das Protokoll transportiert Befehlsausgabe, Exit-Status, Exit-Signal, EOF und Kanalschluss als getrennte Nachrichten. Es empfiehlt die Rückgabe eines Exit-Status, garantiert sie aber nicht. Selbst ein sauberer Kanalschluss sagt dem Client nur etwas über den Kanal, nicht darüber, ob ein externes System den gewünschten fachlichen Zustand erreicht hat.

Definieren Sie die Zustandsmaschine vor der Auslieferung:

  1. not_started: Verbindung, Identität, Authentifizierung oder Freigabe scheiterte vor dem Versand.
  2. started: Die Remote-Seite hat den Befehl angenommen, doch es gibt noch kein endgültiges Ergebnis.
  3. completed: Ein endgültiger Status und die gesamte begrenzte Ausgabe sind eingetroffen.
  4. unknown: Der Versand könnte erfolgt sein, doch der Client hat den Nachweis über den Abschluss verloren.
  5. reconciled: Eine unabhängige Abfrage hat später den resultierenden Zustand festgestellt.

Nur not_started lässt sich im Allgemeinen sicher automatisch wiederholen, und selbst diese Bezeichnung muss von einer vertrauenswürdigen Grenze stammen. Wenn Bytes mit dem Befehl den Server erreicht haben könnten, verwenden Sie unknown. Eine Frist bricht einen Remote-Prozess nicht ab, sofern Sie kein bestätigtes Abbruchprotokoll haben. Das Schließen des Client-Sockets ist kein solches Protokoll.

Jeder verändernde Befehl braucht vor der Freigabe einen benannten Plan zur Abstimmung. Der Plan kann den Vorgangsdatensatz abfragen, eine bereitgestellte Release-Kennung vergleichen, den Zustand des Dienstmanagers lesen oder das nachgelagerte System nach der stabilen Vorgangs-ID fragen. Führen Sie die Abstimmung nach Möglichkeit mit einer schreibgeschützten Berechtigung durch. Bewahren Sie die ursprüngliche Anfrage, ihre Teilausgabe, Zeitstempel, den Host-Fingerabdruck und die Vorgangs-ID auf, damit die Nachfolgeabfrage die richtige Frage beantwortet.

Setzen Sie ein Budget für unbekannte Zustände. Entscheiden Sie, wie lange das System wartet, wer die Warnung erhält, welche Aktionen hinter der ungelösten Operation blockieren und wann ein Mensch übernimmt. Erlauben Sie niemals, dass zwei unsichere Operationen gegen dieselbe Ressource konkurrieren. Serialisieren Sie nach Ressource oder verwenden Sie eine Remote-Sperre mit Eigentümer und Ablaufregel, die einen Client-Verbindungsabbruch übersteht.

Das Remote-Konto einschränken, bevor Sie Befehle erweitern

Anfragenden Agenten identifizieren
Die erste Freigabe für einen Prozess zeigt zuerst dessen Autorität für die Codesignatur.

Die SSH-Readiness hängt stärker von Remote-Berechtigungen als von der Absicht auf Client-Seite ab. Ein perfekter Freigabebildschirm kann kein Login-Konto ausgleichen, das den Host umschreiben kann.

Erstellen Sie ein eigenes Konto für den Agentenkanal. Geben Sie ihm nur den kleinsten Dateisystemzugriff und die Dienstberechtigungen, die für zugelassene Operationen nötig sind. Vermeiden Sie ein allgemeines Administratorkonto. Ist eine Rechteerhöhung nötig, erlauben Sie benannte Befehle mit festen Pfaden und kontrollierten Argumenten. Behandeln Sie uneingeschränktes sudo, Shell-Escapes in erlaubten Programmen, beschreibbare Skriptverzeichnisse und beschreibbare ausführbare Dateien als gleichwertige Wege zu umfassenderem Zugriff.

Einschränkungen in authorized_keys von OpenSSH können die Angriffsfläche einer Berechtigung verringern. Abhängig von Ihrem Design kann ein erzwungener Befehl jede Verbindung durch einen Dispatcher leiten, während Optionen Pseudo-Terminals, Agent-Weiterleitung, X11-Weiterleitung und Port-Weiterleitung deaktivieren können. Auch die Serverkonfiguration kann Weiterleitung einschränken. Nutzen Sie das tatsächliche Handbuch des Servers und testen Sie die wirksame Konfiguration, denn ein permissives Include oder ein Match-Block kann Ihre Annahme aufheben.

Ein Dispatcher sollte einen kleinen Operationsnamen und Daten annehmen, beides validieren und eine ausführbare Datei über absoluten Pfad aufrufen, ohne beliebigen Shell-Text neu zusammenzusetzen. Zum Beispiel kann read-release keine Argumente annehmen, während activate-release eine Release-Kennung akzeptiert, die einem strengen Format entspricht. Der SSH-Kanal bleibt der Träger, aber die Remote-Oberfläche ähnelt zunehmend einer definierten API.

Leiten Sie den Authentifizierungsagenten eines Entwicklers nicht in eine autonome Sitzung weiter. Agent-Weiterleitung lässt die Remote-Seite über den weitergeleiteten Socket Signaturen anfordern, solange die Verbindung besteht. Ein kompromittierter Remote-Host kann den privaten Schlüssel vielleicht nicht auslesen, aber seine Signaturfähigkeit nutzen. Geben Sie dem Kanal eine eigene Berechtigung, deren serverseitige Autorisierung bereits eng ist.

Prüfen Sie die Dateisystemeigentümerschaft bis zu jeder ausführbaren Datei und Konfigurationsdatei. Kann das eingeschränkte Konto ein übergeordnetes Verzeichnis verändern, den Dispatcher ersetzen, eine eingelesene Startdatei beeinflussen oder über PATH ein Programm voranstellen, ist die Allowlist nur Dekoration. Prüfen Sie auch Interpreter. Die Berechtigung, einen breit einsetzbaren Interpreter auszuführen, bedeutet oft die Berechtigung, alles zu tun, was das Konto tun kann.

Halten Sie die erste Befehlsmenge langweilig: feste Inventar-Abfragen, Gesundheitsprüfungen mit begrenzter Ausgabe und eine konvergente Änderung mit getestetem Abstimmungspfad. Port-Weiterleitung, interaktive Shells, beliebige Uploads, Paketverwaltung und freie Root-Befehle gehören in spätere Prüfungen, falls sie überhaupt dazugehören.

Beobachtbarkeit bei Kürzung und Verbindungsabbrüchen beweisen

Jeden Remote-Befehl aufzeichnen
Jeder SSH-Aufruf erscheint im Aktivitätsjournal mit Nachweisen aus dem gemeinsamen Auditprotokoll.

Audit-Nachweise sind bereit, wenn sie Autorisierung, Versand, Remote-Identität und beobachtetes Ergebnis rekonstruieren können, ohne sich auf die Zusammenfassung des Agenten zu verlassen. Protokolle müssen Unsicherheit bewahren, statt sie wegzuredigieren.

Erfassen Sie eine stabile Anfragen-ID und Vorgangs-ID, die Identität des Agentenprozesses oder der Sitzung, die Freigabeentscheidung, die Methode des Freigebenden, den Hash der genehmigten Nutzdaten, das kanonische Ziel, den Host-Schlüssel-Fingerabdruck, das Remote-Konto, Startzeit, Versandzeit, Endzeit, Exit-Status oder Signal, Bytezahlen für jeden Stream, Kürzungsmarkierungen und die endgültige Zustandsklassifizierung. Halten Sie stdout und stderr getrennt. Verbietet eine Richtlinie die Aufbewahrung vollständiger Ausgabe, speichern Sie den erlaubten Teil plus einen Digest und klare Metadaten zur Aufbewahrung.

Ausgabelimits brauchen zwei Verhaltensweisen: lokale Erfassung beenden und entscheiden, was remote geschieht. Den Kanal nach einem Megabyte einfach zu schließen, kann den Prozess weiterlaufen lassen. Ein Remote-Wrapper kann Ausgabe begrenzen, sie in eine kontrollierte Datei schreiben und einen Digest melden, doch auch dieser Wrapper braucht Festplattenquoten und Bereinigung. Testen Sie einen Befehl, der stdout nie schließt, ein Kind, das seinen Elternprozess überlebt, und einen Prozess, der endlos stderr schreibt.

Protokolle sollten auch zeigen, was nicht geschehen ist. Eine Host-Schlüssel-Abweichung, ein gesperrter Vault, eine abgelehnte Freigabe, eine abgelaufene Sitzung, eine fehlerhafte Anfrage oder ein nicht erlaubter Befehl müssen vor der Rückgabe einen Ablehnungsdatensatz erzeugen. Andernfalls sehen Betreiber eine Lücke und können ein stilles System nicht von einer Umgehung unterscheiden.

Sallyport zeichnet Agentenläufe und einzelne Aufrufe in einem verschlüsselten, Hash-verketteten Auditprotokoll auf, und sp audit verify prüft die Kette offline über verschlüsselten Daten ohne Schlüssel. Das gibt dem Kanal manipulationssichere lokale Nachweise, doch Ihre Remote-Vorgangs-IDs und Abstimmungsergebnisse müssen weiterhin in Anfrage und Ergebnis erscheinen, damit ein Operator den Aufruf mit dem Maschinenzustand verbinden kann.

Führen Sie Fehlerinjektion durch und sammeln Sie dabei die Nachweise, die ein Incident-Prüfer erhalten würde. Beenden Sie den Client vor dem Versand, direkt danach, mitten in stdout und nachdem der Remote-Prozess geendet hat, aber vor dem lokalen Abschluss. Rotieren Sie den Host-Schlüssel ohne Aktualisierung des Inventars. Füllen Sie das Remote-Dateisystem vor dem Schreiben einer Markierung. Geben Sie bei erfolgreichem Exit fehlerhafte strukturierte Ausgabe zurück. Stellen Sie in jedem Fall eine Frage: Kann ein Prüfer erkennen, welche Berechtigung verwendet wurde, was sich verändert haben könnte und was als Nächstes geschehen muss?

SSH erst zulassen, wenn die Tore bestanden sind

Der zweite Kanal ist bereit, wenn das Team sein Verhalten bei Fehlern nachweisen kann, nicht wenn ein Befehl im Idealfall einen Testhost erreicht. Verwenden Sie ein schriftliches Tor mit Verantwortlichen und aufbewahrten Nachweisen.

Der Zulassungsdatensatz sollte enthalten:

  1. Einen Kanalvertrag, der Shell, Konto, Verzeichnis, Umgebung, Timeouts, Ausgabelimits und Ergebnisschema benennt.
  2. Ein verifiziertes Host-Inventar mit einer unabhängigen Quelle für Fingerabdrücke, Abdeckung von Jump Hosts und einem getesteten Rotationsprozess.
  3. Einen Befehlskatalog, der Wiederholungsverhalten klassifiziert und für jede Änderung die Abstimmungsabfrage benennt.
  4. Eine Freigabespezifikation, die an exakten Host, Konto, Befehlsversion, Argumente, Berechtigung, Timeout und Vorgangs-ID gebunden ist.
  5. Ergebnisse der Fehlerinjektion, die unbekannte Zustände, Ablehnungen, Kürzung, Widerruf und Audit-Rekonstruktion beweisen.

Bestehen Sie zuerst die schreibgeschützten Tests. Lassen Sie dann eine konvergente Schreiboperation in einer entbehrlichen Umgebung zu. Trennen Sie sie an jeder Grenze und stimmen Sie das Ergebnis ab. Wiederholen Sie das gegen einen produktionsähnlichen Host mit einer harmlosen Ressource. Prüfen Sie die Nachweise mit der Person, der dieser Host gehört, nicht nur mit dem Team, das das Agenten-Gateway gebaut hat.

Halten Sie Rollback und Wiederholung getrennt. Ein Rollback ist eine neue, ausdrückliche Änderung mit eigener Freigabe, Vorgangs-ID, Vorbedingungen und möglichem unbekanntem Zustand. Einen umgekehrten Befehl nach einem Timeout automatisch auszuführen, kann eine Änderung beschädigen, die tatsächlich korrekt abgeschlossen wurde. Das System muss den aktuellen Zustand feststellen, bevor es ihn erneut verändert.

Legen Sie Entfernungskriterien neben Zulassungskriterien fest. Deaktivieren Sie eine Operation, wenn sich ihr Skript-Digest ohne Prüfung ändert, ihr Host das Inventar verlässt, die Abstimmung nicht mehr funktioniert, die Ausgabe unbegrenzt wird oder Betreiber ein unbekanntes Ergebnis nicht erklären können. Kanalzugang ist kein dauerhaftes Abschlussabzeichen.

SSH verdient seine Zulassung eine Operation nach der anderen. Wenn Sie den Server nicht verankern, die Wirkung nicht beschreiben, sie nicht sicher wiederholen, alle Ergebniszustände nicht unterscheiden und den Aufruf danach nicht rekonstruieren können, lautet das richtige Ergebnis der Checkliste „nicht bereit“. Behalten Sie den schreibgeschützten HTTP-Kanal und schließen Sie die fehlende Grenze, bevor eine Remote-Shell eine mehrdeutige Wiederholung in eine zweite Produktionsänderung verwandelt.

FAQ

Wann ist ein KI-Agent für SSH-Zugriff bereit?

Ein Agent ist bereit, wenn die Host-Identität fest verankert ist, Befehle typisierte Ergebnisse liefern, Änderungen sicher wiederholbar sind, Freigaben genau an die Wirkung gebunden sind und Verbindungsabbrüche einen ausdrücklichen unbekannten Zustand erzeugen. Ein erfolgreicher Test-Login beweist nur die Verbindung.

Ist schreibgeschütztes SSH sicher genug, um es zuerst zu aktivieren?

Das ist die richtige erste Stufe, doch das Remote-Konto braucht weiterhin enge Berechtigungen und begrenzte Ausgabe. Ein Befehl, der nur lesend wirkt, kann Startdateien ausführen, über PATH ein unerwartetes Programm aufrufen oder Geheimnisse in der Ausgabe offenlegen.

Sollte automatisiertes SSH StrictHostKeyChecking no verwenden?

Nein. Stellen Sie verifizierte Host-Schlüssel vor dem Lauf bereit und verwenden Sie StrictHostKeyChecking=yes. Das Deaktivieren der Prüfung tauscht eine betriebliche Rückfrage gegen einen Identitätsfehler, den die Automatisierung möglicherweise nicht bemerkt.

Kann ssh-keyscan known_hosts sicher erstellen?

ssh-keyscan kann einen Schlüssel erfassen, aber den empfangenen Schlüssel nicht authentifizieren. Vergleichen Sie seinen Fingerabdruck mit einem Wert aus einem unabhängigen vertrauenswürdigen Kanal, bevor Sie ihn installieren.

Beweist der SSH-Exit-Code 0, dass die Änderung erfolgreich war?

Er beweist nur, dass der gemeldete Status des Remote-Befehls null war. Der Befehl kann Erfolg schlecht definieren, eine Pipeline kann einen früheren Fehler verdecken oder der gewünschte externe Zustand kann trotzdem falsch sein. Prüfen Sie daher strukturierte Ausgabe oder gleichen Sie den Zustand ab.

Was bedeutet der SSH-Exit-Code 255?

Der OpenSSH-Client verwendet 255 bei einem Fehler und gibt sonst den Status des Remote-Befehls zurück. Da ein Remote-Programm ebenfalls 255 wählen kann, müssen Transportzustand und Remote-Exit-Status im Adapter getrennt bleiben.

Wann ist ein SSH-Befehl idempotent?

Ein SSH-Befehl ist idempotent, wenn seine Wiederholung nach jeder Teilausführung denselben gewünschten Zustand erzeugt, ohne die Wirkung zu verdoppeln. Testen Sie die Wirkungsgrenze statt der Befehlsschreibweise und nutzen Sie stabile Vorgangs-IDs oder zustandsbasierte Schutzprüfungen.

Sollte ein Agent einen SSH-Timeout automatisch wiederholen?

Nur wenn das System beweisen kann, dass der Befehl nie gestartet wurde. Falls die Übermittlung erfolgt sein könnte, markieren Sie das Ergebnis als unbekannt und führen Sie vor einer weiteren Änderung eine schreibgeschützte Abfrage zur Abstimmung aus.

Was sollte eine SSH-Freigabekarte zeigen?

Zeigen Sie den kanonischen Host, den verifizierten Fingerabdruck, das Remote-Konto, die beabsichtigte Wirkung, die genaue Befehls- oder Skriptversion, normalisierte Argumente, die Berechtigungsänderung, das Timeout und die Vorgangs-ID. Binden Sie die Freigabe an diese Nutzdaten, damit sich nach dem Klick nichts ändern kann.

Wie sollten Teams den SSH-Zugriff von Agenten testen?

Simulieren Sie Fehler vor, während und nach der Remote-Ausführung, darunter Änderungen am Host-Schlüssel, Ausgabeüberläufe, Signale, Timeouts und Verbindungsabbrüche. Die Nachweise sollten einem Operator zeigen, was sich geändert haben könnte und welche Abstimmungsaktion sicher ist.

Sallyport

Sallyport führt API-Aufrufe und SSH-Befehle für Ihren KI-Agenten aus. Die Schlüssel bleiben in einem lokalen Tresor auf Ihrem Mac; Sie geben jeden Lauf frei, und jede Aktion landet in einem versiegelten Journal.

© 2026 Sallyport · Open Source unter Apache-2.0 · Oleg Sotnikov