SSH-Zugriff für KI-Agenten: Remote-Befehle ohne private Schlüssel
Der SSH-Zugriff für KI-Agenten sollte über vermittelte Remote-Aktionen erfolgen, nicht über kopierte private Schlüssel. Baue Genehmigungen, Serverlimits, Hostprüfungen und Audit-Trails ein.

Einem KI-Coding-Agenten einen privaten SSH-Schlüssel zu geben, ist die falsche Abstraktion. Der Agent braucht keine dauerhafte Zugangsdaten, die sich jederzeit von jedem Rechner aus verwenden lassen. Er braucht die Berechtigung, eine bestimmte Remote-Aktion auszuführen, während du diese Aktion noch sehen, stoppen und erklären kannst.
Das klingt nach einer kleinen Architekturänderung. Das ist es nicht. Sie trennt ein Geheimnis, das für immer weitergegeben werden kann, von einer SSH-Anfrage mit Aufrufer, Ziel, Befehl, Ergebnis und Verantwortlichem.
Ich habe Teams erlebt, die tagelang Prompt-Regeln für einen Agenten verschärften und anschließend ~/.ssh/id_ed25519 für denselben Prozess lesbar ließen. Die Prompt-Regeln sind Dekoration, sobald der private Schlüssel verfügbar ist. Ein Shell-Befehl kann die Datei kopieren, ausgeben, archivieren oder an einen Ort senden, den du erst Wochen später entdeckst.
Ein privater Schlüssel ist kein API-Token mit kürzerem Namen. Er ist ein wiederverwendbares Berechtigungstoken für jeden SSH-Server, der den zugehörigen öffentlichen Schlüssel akzeptiert.
Gib dem Agenten eine Aktion, keine Identität
Ein Agent sollte eine SSH-Operation anfordern, während eine separate vertrauenswürdige Komponente die Identität verwaltet und die Verbindung herstellt. Diese Komponente erhält strukturierte Eingaben wie Ziel, Remote-Konto, Befehl, Argumente und Timeout. Sie prüft die Anfrage, authentifiziert sich am Server, erfasst das Ergebnis und gibt nur dieses Ergebnis an den Agenten zurück.
Das Geheimnis bleibt auf einem Rechner. Noch wichtiger: Das Recht, es zu verwenden, folgt dem Agent-Prozess nicht mehr überallhin.
Diese Unterscheidung verändert das Fehlerszenario. Wenn ein Agent kompromittiert wird oder schädlichen Anweisungen aus einem Repository folgt, kann er weiterhin einen falschen Befehl anfordern. Er kann aber nicht unbemerkt den privaten Schlüssel exportieren und ihn nächsten Monat von einer kurzlebigen VM aus wiederverwenden. Ein offenes Problem des Zugangsdiebstahls wird zu einem Problem der Autorisierung und Befehlssteuerung.
Das zweite Problem verdient weiterhin Respekt. Es ist einfach ein Problem, das sich betreiben lässt.
Eine nützliche Anfrageform ist absichtlich unspektakulär:
{
"host": "deploy-01.internal.example",
"user": "release",
"command": "/usr/local/libexec/release-service",
"args": ["api", "2025.03.08-4f2c1a7"],
"timeout_seconds": 120
}
Sende keine Shell-Zeichenkette wie ssh deploy-01 'cd /srv/api && git pull && sudo systemctl restart api' durch fünf Schichten und nenne das Kontrolle. Die Regeln der Shell-Auswertung werden dadurch Teil deiner Sicherheitsgrenze, und fast niemand prüft sie auch unter diesem Gesichtspunkt. Halte den Befehlspfad fest, übergib Argumente als einzelne Werte und lasse den Remote-Wrapper Werte außerhalb seiner erwarteten Grammatik ablehnen.
Ich bevorzuge einen Aktionsvertrag, der etwas umständlich zu bedienen ist, gegenüber einem flexiblen Remote-Terminal, das niemand begrenzen kann. Die Umständlichkeit zeigt sich beim Einrichten. Der Schaden eines uneingeschränkten Terminals zeigt sich später.
Der Broker muss ein Ergebnis mit genügend Struktur zurückgeben, damit der Agent ohne Vermutungen weiterarbeiten kann:
{
"exit_code": 0,
"stdout": "released api version 2025.03.08-4f2c1a7\n",
"stderr": "",
"duration_ms": 1842
}
Gib keine Zugangsdaten, Agent-Sockets, Inhalte von known_hosts oder ein interaktives TTY zurück. Das sind Implementierungsdetails der vertrauenswürdigen Seite.
Besitz, Signieren und Ausführen sind verschiedene Berechtigungen
Teams verwenden «SSH-Zugriff» oft so, als würde der Begriff nur eine Sache beschreiben. Tatsächlich umfasst er mindestens drei deutlich unterschiedliche Berechtigungen: einen privaten Schlüssel zu besitzen, einen Agenten zum Erstellen einer Signatur aufzufordern und einen Broker zum Ausführen eines benannten Remote-Befehls zu veranlassen.
Der Besitz des privaten Schlüssels ist die weitreichendste Variante. Wer die Datei lesen kann, kann sie dauerhaft kopieren und gegen jeden erreichbaren Server ausprobieren. Dateiberechtigungen helfen, Festplattenverschlüsselung hilft und Passphrasen helfen ebenfalls. Keine dieser Maßnahmen beantwortet aber die zentrale Frage: Warum brauchte ein KI-Prozess überhaupt eine portable Zugangsdaten?
Ein ssh-agent macht es unnötig, dass jeder Client eine Datei mit privatem Schlüssel liest. Der Prozess kann über SSH_AUTH_SOCK eine Signatur anfordern. Das verbessert die lokale Hygiene auf dem Arbeitsplatzrechner, aber Signieren verleiht weiterhin Authentifizierungsrechte. Das OpenSSH-Handbuch ssh-agent(1) erklärt, dass der Agent private Schlüssel während der Weiterleitung aus dem Netzwerkverkehr heraushält, während der weitergeleitete Aufrufer das Ergebnis von Identitätsoperationen erhält. Das ist eine nützliche Eigenschaft, aber noch kein vollständiges Autorisierungsmodell.
Die Ausführung von Aktionen ist enger begrenzt, wenn du sie entsprechend konstruierst. Ein Broker kann unbekannte Hosts ablehnen, ein anderes Remote-Konto verbieten, eine menschliche Entscheidung verlangen, die Ausführungszeit begrenzen, ein PTY verweigern und den Aufruf protokollieren. Außerdem kann er für jede Operationsklasse eine andere SSH-Identität verwenden.
Dieses letzte Detail ist wichtiger, als viele Teams erwarten. Eine Identität, die Logs lesen, Code deployen, /etc/sudoers bearbeiten und Tunnel öffnen kann, schafft eine Autorisierungsgrenze von der Größe deiner gesamten Flotte. Vier Identitäten mit engen serverseitigen Einschränkungen schaffen vier kleinere Probleme.
Ich würde lieber vier eng begrenzte Identitäten nach einem Fehler rotieren, als ein Wochenende damit zu verbringen, zu beweisen, dass eine Administratoridentität nicht jeden Host erreicht hat.
Dieses Muster macht einen schädlichen Befehl nicht harmlos. Es gibt dir aber mehrere Stellen, an denen du ihn erkennen kannst: vor der Verbindung, bei der Serverauthentifizierung, innerhalb des erzwungenen Remote-Befehls und anschließend im Protokoll.
SSH-Agent-Weiterleitung löst ein anderes Problem
SSH-Agent-Weiterleitung verhindert, dass ein privater Schlüssel auf einen Jump-Host kopiert wird. Sie macht einen entfernten Rechner aber nicht sicher genug für einen Agenten. Der entfernte Host erhält Zugriff auf einen Socket, über den er Operationen von deinem lokalen Authentifizierungsagenten anfordern kann.
OpenSSH formuliert das in ssh_config(5) eindeutig: Agent-Weiterleitung sollte mit Vorsicht aktiviert werden, weil ein Benutzer, der Berechtigungen auf dem entfernten Host umgehen kann, den lokalen Agenten über die weitergeleitete Verbindung verwenden kann. Der Angreifer kann die Bytes des privaten Schlüssels nicht über diese Schnittstelle auslesen, aber er kann die geladenen Identitäten zur Authentifizierung auffordern.
Bei autonomen Tools wird dieser Vorbehalt noch wichtiger. Ein Agent verbindet sich vielleicht mit einem Host, weil eine Aufgabe ihn auffordert, ein Log zu prüfen. Eine schädliche Repository-Anweisung, ein kompromittiertes Remote-Konto oder ein schlecht begrenzter Befehl kann anschließend SSH_AUTH_SOCK finden und die weitergeleitete Signierfähigkeit nutzen. Der private Schlüssel bleibt technisch geheim, während die Authentifizierungsberechtigung missbraucht wird. Für das Opfer ist diese Unterscheidung kaum tröstlich.
Aktiviere ForwardAgent yes nicht global. Setze ForwardAgent no in deine grundlegende Client-Konfiguration und füge nur für einen konkret benannten menschlichen Ablauf, der diese Funktion wirklich benötigt, eine ausdrückliche Ausnahme hinzu.
Host *
ForwardAgent no
AddKeysToAgent no
IdentitiesOnly yes
StrictHostKeyChecking yes
Host legacy-bastion
HostName bastion.internal.example
User ops
ForwardAgent yes
Auch die obige Ausnahme braucht einen Grund, einen Verantwortlichen und ein Löschdatum. Eine dauerhafte Weiterleitungsausnahme wird leicht unsichtbar, weil SSH sie so reibungslos funktionieren lässt.
Zielbeschränkte Identitäten verbessern die Situation, ersetzen aber keine Aktionsgrenze. Das OpenSSH-Handbuch ssh-add(1) erklärt, dass Zielbeschränkungen den gesamten Verbindungsweg prüfen, wenn ein unterstützender Client und Server den Agenten weiterleiten. Es warnt außerdem, dass jemand mit einem entfernten SSH_AUTH_SOCK diesen Socket erneut weiterleiten kann, wobei die Nutzung weiterhin auf erlaubte Ziele beschränkt bleibt.
Verwende Zielbeschränkungen dort, wo sie passen. Verwechsle sie nicht mit einer Befehlsrichtlinie. Sie legen fest, wo sich eine Identität authentifizieren kann, nicht ob nach der Ankunft rm -rf /srv/release-cache ausgeführt werden darf.
Verfolge den Fehler durch den Befehlsweg
Ein plausibler Vorfall beginnt mit einer gut gemeinten Abkürzung: Ein Entwickler legt einen privaten Deployment-Schlüssel in eine Umgebungsvariable, weil der Coding-Agent einen einzigen Release-Befehl ausführen soll. Der Agent liest eine Repository-Issue mit einem vorgeschlagenen Diagnosebefehl. Der Befehl gibt zur Fehlersuche die Umgebung aus, und das Ausführungsprotokoll landet in einem lokalen Sitzungslog.
Der erste Verlust geschah bereits vor SSH. Der private Schlüssel gelangte in einen Prozess, der ihn nicht halten musste.
Der Agent hat nun mehrere Möglichkeiten, ihn offenzulegen oder wiederzuverwenden. Er kann den Wert in eine temporäre Datei schreiben. Er kann ihn mit scp an einen Remote-Host senden. Er kann ihn in einen Git-Commit schreiben. Er kann ihn an einen Subprozess außerhalb der von dir angenommenen Grenzen weitergeben. Ein einmal kopierter privater Schlüssel läuft nicht ab, nur weil du den Agent-Lauf beendet hast.
Angenommen, das Team verwendete stattdessen Agent-Weiterleitung. Die Repository-Anweisung weist den Agenten an, sich mit build-02 zu verbinden, und führt dann einen Befehl aus, der den weitergeleiteten Socket einem lokalen Prozess auf diesem entfernten Rechner zugänglich macht. Der Angreifer kann den privaten Schlüssel nicht ausgeben, aber den Socket auffordern, sich mit einer in der Entwicklerumgebung geladenen Identität an einem anderen Host zu authentifizieren. Die Weiterleitung war nie als allgemeiner Delegationsmechanismus gedacht, wurde aber genau dazu.
Betrachte nun das vermittelte Design. Der Agent sendet die Anfrage release-service api 2025.03.08-4f2c1a7 an deploy-01. Der Broker erkennt, dass dies die erste Anfrage eines neuen Agent-Prozesses ist, und fordert eine Genehmigung an. Die genehmigende Person sieht die Code-Signatur des aufrufenden Prozesses, die Remote-Identität und das Ziel. Der Broker verbindet sich nur mit dem genannten Host. Der Server akzeptiert ausschließlich eine eingeschränkte Deployment-Identität und startet einen einzigen serverseitigen Wrapper.
Die schädliche Anweisung kann weiterhin einen Release anfordern. Sie kann diese Anfrage aber nicht in eine Login-Shell, eine Portweiterleitung, einen kopierten privaten Schlüssel oder einen Umweg über andere Server verwandeln.
Das reduziert den möglichen Schaden erheblich, kostet dich aber Flexibilität. Ein allgemeiner Agent kann sich an ungewöhnliche Produktionszustände anpassen. Eine begrenzte Aktionsschnittstelle kann das nicht. Du musst gezielte Operationen für Logs, Dienststatus, Rollback, Migrationsprüfungen und die Bereinigung von Artefakten ergänzen. Jemand muss diese Schnittstellen betreuen. Diese Arbeit ist nicht optional; uneingeschränktes SSH versteckt sie lediglich.
Die richtige Reaktion besteht darin, den sicheren Weg für die tatsächlich anfallenden Aufgaben auszubauen, statt jedes Mal eine unveränderte Shell zu öffnen, wenn dem sicheren Weg eine Funktion fehlt.
Platziere den SSH-Client hinter einem lokalen Entscheidungspunkt
Ein lokaler Entscheidungspunkt sollte drei Dinge verwalten: die verschlüsselte private Identität, die Berechtigung zu ihrer Verwendung und die dabei entstehenden Nachweise. Der Agent sollte keines davon besitzen.
Sallyport folgt diesem Muster für macOS-Agenten: Der mitgelieferte sp mcp Shim akzeptiert reguläre MCP-Aufrufe, während die Menüleisten-App SSH-Identitäten in ihrem verschlüsselten Tresor aufbewahrt und mit sp-ssh die Verbindung herstellt. Der Agent erhält das Befehlsergebnis statt der Zugangsdaten.
Die Form ist wichtiger als die konkrete Implementierung:
KI-Agent-Prozess
-> lokale Aktionsanfrage
-> Autorisierungsentscheidung
-> SSH-Helfer mit geschützter Identität
-> entfernter sshd und eingeschränktes Konto
-> stdout, stderr, Exit-Status
Halte den Entscheidungspunkt auf dem verwalteten Rechner des Entwicklers, wenn ein Mensch die Arbeit überwachen muss. Verwandle ihn nicht in einen Netzwerkproxy, der stillschweigend jede Anfrage jedes Prozesses signiert. Die lokale Prozessgrenze ermöglicht es, den Aufrufer zuzuordnen und eine unerwartete ausführbare Datei abzulehnen, bevor eine Netzwerkverbindung beginnt.
Die Prozessidentität ist kein dekoratives Feld in einer Genehmigungskarte. Eine Anfrage der erwarteten signierten Anwendung unterscheidet sich von einer Anfrage eines unsignierten Programms aus /tmp, selbst wenn beide behaupten, «der Coding-Agent» zu sein. Unter macOS liefert die Codesignatur dem Genehmigenden etwas Konkretes zur Bewertung.
Ein neuer Prozess sollte sich meiner Ansicht nach erst eine Sitzung verdienen, bevor er eine SSH-Identität verwenden kann. Diese Sitzung sollte verschwinden, sobald der Prozess endet. Langfristige Freigaben sind einfach zu betreiben, aber nach einer Kompromittierung schwer zu erklären.
Eine Sperre des Tresors sollte jede SSH-Aktion verweigern. Es darf keinen teilweisen Rückfall auf einen zwischengespeicherten privaten Schlüssel, eine exportierte PEM-Datei oder einen Helferprozess mit eigener versteckter Kopie geben. Wenn dein Notfallweg den Schutz umgeht, wird er irgendwann zum normalen Weg.
Mach das Remote-Konto absichtlich unspektakulär
Der Remote-Server muss begrenzen, was eine erfolgreiche SSH-Authentifizierung tun kann. Ein geschützter privater Schlüssel ist nur die eine Hälfte der Kontrolle. Der Server muss diese Identität als zweckgebundenes Konto behandeln, nicht als menschliches Administratorkonto.
Lege ein separates Unix-Konto für die Aktion an, etwa release, diagnostics oder backup. Gib ihm kein persönliches Shell-Profil, kein weitreichendes Home-Verzeichnis und keinen Passwort-Login. Lege seine öffentliche Identität nicht neben die uneingeschränkte persönliche Identität eines Engineers in dieselbe authorized_keys-Datei und behaupte dann, die Konten seien getrennt.
Für eine Release-Operation kann ein authorized_keys-Eintrag so aussehen:
restrict,command="/usr/local/libexec/release-service" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExampleOnlyReplaceThis release-broker
Die Option restrict deaktiviert Port-, Agent- und X11-Weiterleitung, die PTY-Zuweisung sowie die Ausführung von ~/.ssh/rc. Das OpenSSH-Handbuch sshd(8) dokumentiert restrict ausdrücklich für diesen Zweck und zeigt die Option zusammen mit einem erzwungenen Befehl.
Der erzwungene Befehl darf die ursprüngliche Befehlszeile nicht an sh -c übergeben. Er sollte SSH_ORIGINAL_COMMAND ignorieren, sofern du keinen eng begrenzten Parser mit Tests hast. Der Wrapper sollte ein festes Protokoll akzeptieren, jedes Feld validieren, einen Audit-Eintrag schreiben und die eigentliche Operation mit klar getrennten Argumenten aufrufen.
Ein kleiner Shell-Wrapper ist akzeptabel, solange er klein bleibt:
#!/bin/sh
set -eu
service=${1:-}
version=${2:-}
case "$service" in
api|worker) ;;
*) echo "unsupported service" >&2; exit 64 ;;
esac
case "$version" in
*[!0-9A-Za-z._-]*|"") echo "invalid version" >&2; exit 64 ;;
esac
exec /usr/bin/sudo /usr/local/sbin/deploy-approved-release "$service" "$version"
Rufe diesen Wrapper mit festen Argumenten aus dem Broker auf. Lass den Client seinen Pfad nicht selbst wählen. Wenn du weitere Operationen brauchst, erstelle weitere Wrapper oder einen kleinen Befehlsverteiler, der benannte Unterbefehle akzeptiert und alles andere ablehnt.
Hier ziehe ich eine klare Grenze: Verbinde keinen autonomen Agenten mit einem gemeinsamen ops-Konto mit normaler Shell und versuche, das durch einen besseren Prompt auszugleichen. Ein gemeinsames Shell-Konto macht jede serverseitige Schutzmaßnahme freiwillig.
Verwende für zustandsbehaftete Arbeiten idempotente Operationen. Ein Release-Wrapper sollte prüfen, ob das angeforderte Artefakt bereits aktiv ist, ob der Dienst gesund ist und ob ein Rollback-Punkt existiert, bevor er etwas ändert. Der Agent kann eine Anfrage nach einem Timeout wiederholen. Deine Remote-Operation sollte diese Wiederholung nicht als Erlaubnis verstehen, die Aktion zweimal auszuführen.
Hostprüfung und Befehlsgrammatik verdienen gleich viel Aufmerksamkeit
Eine private Identität schützt die Client-Authentifizierung. Sie beweist nicht, dass der Agent den vorgesehenen Server erreicht hat. Wenn deine Automatisierung jeden neuen Host-Fingerprint akzeptiert, können ein DNS-Fehler, eine manipulierte Hosts-Datei oder ein aktiver Angreifer im Netzwerk die Verbindung zu einem Server umleiten, der deinen Befehl erhält und seine Ausgabe erfährt.
Verwende für Automatisierungsidentitäten StrictHostKeyChecking yes. Verteile geprüfte Host-Fingerprints über das Konfigurationsmanagement oder pflege eine sorgfältig kontrollierte known_hosts-Datei. Wenn ein Host seinen SSH-Hostschlüssel wechselt, führe die Änderung ausdrücklich und mit einer Prüfung über einen unabhängigen Kanal durch. Bringe dem Agenten nicht bei, die Host-Key-Abfrage mit «yes» zu beantworten.
Ein minimales Client-Profil für eine nicht interaktive Aktion sieht oft so aus:
Host deploy-01.internal.example
HostName deploy-01.internal.example
User release
IdentityAgent /path/to/broker.sock
IdentitiesOnly yes
StrictHostKeyChecking yes
UserKnownHostsFile /Library/Application Support/agent-ssh/known_hosts
BatchMode yes
RequestTTY no
ForwardAgent no
IdentitiesOnly yes verhindert, dass SSH jede über einen Agenten verfügbare Identität am Ziel ausprobiert. Das reduziert unnötige Authentifizierungsversuche und verhindert, dass versehentlich eine persönliche Identität verwendet wird, wenn die vorgesehene Aktionsidentität fehlschlägt. Das OpenSSH-Handbuch ssh_config(5) beschreibt die Option als Möglichkeit, konfigurierte Identitätsdateien statt zusätzlicher Identitäten eines Agenten oder Providers zu verwenden.
Lass Agenten Hostnamen möglichst nicht selbst auswählen. Eine Anfrage sollte sich auf ein genehmigtes logisches Ziel beziehen, etwa production-api-release. Die vertrauenswürdige Seite sollte diesen Namen auf Hostname, Remote-Konto, Host-Fingerprint, Identität und Befehlsfamilie abbilden. Diese Zuordnung ist im normalen Sinn eine Richtlinie, sollte aber als für Menschen prüfbare Daten vorliegen und nicht als ausgeklügelte Sprache, die zu Umgehungen einlädt.
Auch die Befehlsgrammatik braucht Zurückhaltung. Beliebige Argumente für ein festes Programm können weiterhin beliebige Ausführung ermöglichen, wenn das Programm Dateipfade, Plugin-Namen, Konfigurationsimporte oder --exec-Flags akzeptiert. Prüfe die tatsächliche CLI. Schreibe die erlaubten Tokens auf. Teste fehlerhafte Eingaben, Leerzeichen, Shell-Metazeichen, ungewöhnliche Unicode-Zeichen und wiederholte Flags.
Zwanzig Minuten, in denen du deinen eigenen Wrapper mit hässlichen Argumenten angreifst, finden mehr als eine weitere Genehmigungsabfrage.
Genehmige Berechtigungen, sobald sie nützlich werden
Die menschliche Genehmigung gehört an die Grenze, an der ein Prozess erstmals eine SSH-Fähigkeit erhält, nicht nach jeden harmlosen Befehl und auch nicht erst, nachdem ein destruktiver Befehl den Server erreicht hat.
Eine Genehmigung pro Sitzung ist ein praktikabler Standard für einen Agent-Lauf. Der erste SSH-Versuch eines neuen Prozesses löst eine Entscheidung aus. Die Genehmigung sollte angeben, welcher signierte Prozess angefragt hat, welche Identität er verwenden möchte und welche Art von Remote-Zugriff er erhält. Nach der Genehmigung kann genau dieser Prozess bis zu seinem Ende erlaubte Anfragen ausführen.
So werden routinemäßige Diagnosen nicht zu einer Klickfolge. Gleichzeitig vermeidest du die noch schlechtere Alternative: eine Genehmigung, die für jeden zukünftigen Prozess namens node, python oder claude auf dem Rechner gilt.
Einige Identitäten verdienen bei jeder Nutzung eine zweite Schranke. Produktions-Deployments, Notfallneustarts, Datenbankexporte, Änderungen an der Infrastruktur und Befehle, die die Netzwerkerreichbarkeit verändern können, sind naheliegende Kandidaten. Der Preis ist eine Unterbrechung. Der Vorteil: Eine kompromittierte Sitzung kann die gefährlichste Identität nicht stillschweigend verwenden, nachdem du eine risikoarme Statusprüfung genehmigt hast.
Sallyport kann eine Genehmigung pro Aufruf für eine einzelne SSH-Identität verlangen, während die normale Sitzungsautorisierung die Freigabe an einen bestimmten Agent-Prozess bindet. Die Tresorsperre verweigert Aktionen ebenfalls, solange der Tresor gesperrt ist, statt einem Hintergrundagenten nach dem Weggehen der Person die weitere Arbeit zu erlauben.
Der Genehmigungsdialog darf nicht verlangen, dass Benutzer einen Absatz aus serialisiertem JSON lesen. Zeige eine kurze Zusammenfassung der Aktion und mache anschließend die Details verfügbar: Ziel, Remote-Konto, fester Befehlsname, übergebene Argumente und Timeout. Menschen erkennen production-db und staging-db schnell. Nach der zehnten Abfrage erkennen sie Gefahren in einer vollständigen Shell-Pipeline nicht mehr zuverlässig.
Eine Ablehnung muss eine eigene Ausgabe sein. Der Agent braucht ein ausdrückliches Ergebnis, damit er melden kann, dass ihm die Berechtigung fehlte, statt es mit einem anderen Konto, Host oder einer Umgehung zu versuchen. Wiederholte Versuche nach einer Ablehnung sollten sichtbar protokolliert werden.
Ein Audit-Trail muss den kompromittierten Aufrufer überleben
Von Agenten erzeugte Logs reichen nicht aus. Wenn der Agent-Prozess das Protokoll seiner eigenen SSH-Aufrufe schreiben oder löschen kann, kann er eine angenehme Version der Geschichte hinterlassen.
Protokolliere die Aktivität außerhalb des Agent-Prozesses. Halte mindestens die Identität des aufrufenden Prozesses, die Sitzungs-ID, die Zeit, das Ziel, das Remote-Konto, den Aktionsnamen, Argumente nach den Regeln zur Schwärzung, das Autorisierungsergebnis, Exit-Code und Dauer sowie eine begrenzte Aufzeichnung von stdout und stderr fest. Bei lauten Befehlen kannst du die ersten und letzten 50 Zeilen aufzeichnen oder einen Inhalts-Hash mit einem geschützten vollständigen Artefakt speichern, wenn die Ausgabe Geheimnisse enthalten könnte.
Protokolliere keine privaten Schlüssel, Bearer-Token oder beliebigen Umgebungsvariablen. Ein Auditsystem, das ein zweites Zugangsdatenleck erzeugt, ist schlimmer als ein fehlendes Auditsystem, weil sich Menschen darauf verlassen werden.
Manipulationsnachweise verändern die Untersuchung. Ein verkettetes Log kann zeigen, dass jemand Einträge nachträglich entfernt oder umsortiert hat, während eine normale Textdatei im Append-Modus meist nur beweist, dass eine Datei existiert. Die Prüfung sollte funktionieren, ohne den Tresor zu entsperren. Sonst kannst du die Aufzeichnungen gerade in dem Zustand nicht untersuchen, in dem du die Nachweise am dringendsten brauchst.
Die Red-Team-Assessment-Leitlinien von CISA liefern einen konkreten Grund, sich mit der Begrenzung von Zugangsdaten zu beschäftigen. Eine veröffentlichte Untersuchung beschreibt, wie ein Team Dutzende private SSH-Schlüssel aus zugänglichen Dateien erlangte und privilegierte Identitäten zur Bewegung zwischen Linux-Systemen verwendete. Die Lehre ist nicht, dass jeder Agent zum Eindringling wird. Die Lehre ist, dass wiederverwendbares SSH-Material zu einem Inventar für laterale Bewegungen anwächst, sobald es Orte erreicht, an denen es nicht benötigt wird.
Wenn ein unerwarteter Befehl auftaucht, widerrufe zuerst die Agent-Sitzung. Deaktiviere anschließend die betroffene Identität auf dem Server, prüfe das verifizierte Aktivitätsprotokoll und untersuche die sshd- und System-Logs des Zielhosts. Rotiere die private Identität, sobald die Möglichkeit besteht, dass sie die geschützte Grenze verlassen hat. Ein vermitteltes Modell beschleunigt diesen Ablauf, weil der Widerruf einer Sitzung zukünftige Aktionsanfragen stoppt, ohne dass du erst einen kopierten privaten Schlüssel finden musst.
Verwende vier enge Wege statt einer allgemeinen Shell
Für die praktische Einführung inventarisierst du die Remote-Aktionen, die deine Agenten bereits ausführen, und ordnest sie nach ihrer Tragweite. Beginne nicht mit der Frage, welche privaten Schlüssel sie brauchen. Diese Frage setzt am falschen Ende an.
Die meisten Teams finden eine kleine Gruppe wiederkehrender Operationen:
- Einen begrenzten Dienststatus oder einen kurzen Ausschnitt aus einem aktuellen Log lesen.
- Ein bereits gebautes Artefakt in einer Umgebung deployen.
- Eine Migrationsprüfung ausführen, die keine Daten verändert.
- Nach einem Release einen benannten Dienst neu starten.
- Diagnosedaten für einen fehlgeschlagenen Job sammeln.
Baue für jede dieser Aufgaben einen Aktionsweg. Weise eine eigene Remote-Identität oder ein eigenes Konto zu, wenn sich die Server unterscheiden. Erzwinge den Befehl serverseitig. Fixiere die Hostidentität. Entscheide, ob die Aktion eine Sitzungsfreigabe oder eine Genehmigung bei jeder Nutzung braucht. Protokolliere erlaubte und abgelehnte Aufrufe.
Halte einen menschlichen SSH-Weg für ungewöhnliche Reparaturarbeiten offen. Menschen brauchen während eines Vorfalls manchmal eine interaktive Shell. So zu tun, als wäre das nie nötig, drängt sie zu unsicheren Auswegen. Dieser Weg sollte eine separate persönliche Identität, nach Möglichkeit MFA, gegebenenfalls einen Jump-Host und die üblichen Vorfallkontrollen verwenden. Teile die Automatisierungsidentität nicht, nur weil dadurch eine Zeile in authorized_keys entfällt.
Das sicherere Muster erfordert mehr anfängliche Entwicklungsarbeit: Wrapper brauchen Tests, Host-Fingerprints brauchen Verantwortliche und dein Aktionskatalog braucht Pflege. Nimm diese Kosten in Kauf. Die Alternative besteht darin, einem probabilistischen Textgenerator Zugangsdaten zu geben, die jede Schutzmaßnahme überleben können, die du um seine aktuelle Aufgabe herum aufgebaut hast.
Beginne mit dem privaten SSH-Schlüssel, der am nächsten an der Produktion liegt. Entferne ihn aus der Reichweite des Agenten, ersetze einen weitreichenden Shell-Befehl durch eine begrenzte Aktion und prüfe das entstehende Protokoll nach einem echten Lauf. Diese erste Grenze zeigt dir genau, wo die restliche Arbeit verborgen ist.
FAQ
Kann ein KI-Agent SSH verwenden, ohne auf einen privaten Schlüssel zuzugreifen?
Ein Agent kann SSH-Befehle ausführen, ohne einen privaten Schlüssel zu erhalten, wenn ein separater lokaler Broker die Identität verwaltet und den SSH-Handshake selbst ausführt. Der Agent übermittelt Host, Konto, Befehl und Argumente. Der Broker entscheidet, ob die Anfrage genehmigt wird, und gibt stdout, stderr sowie den Exit-Code zurück. Der Unterschied ist entscheidend: Ein kopierter privater Schlüssel kann überall wiederverwendet werden, während eine vermittelte Aktion gestoppt, eingeschränkt und protokolliert werden kann.
Ist SSH-Agent-Weiterleitung für KI-Agenten sicher?
SSH-Agent-Weiterleitung hält den privaten Schlüssel vom entfernten Host fern, stellt aber eine Signierfähigkeit über einen weitergeleiteten Unix-Socket bereit. Ein Prozess, der diesen Socket erreichen kann, kann sich mit den Identitäten authentifizieren, die in deinem lokalen Agenten geladen sind. OpenSSH warnt, dass Benutzer, die Berechtigungen auf dem entfernten Host umgehen können, den weitergeleiteten Agenten für Authentifizierungsvorgänge verwenden können.
Sollte ein KI-Agent eine eigene SSH-Identität haben?
Verwende für jede Automatisierungsgrenze eine eigene SSH-Identität. Produktions-Deployments, schreibgeschützte Diagnose, Backups und Repository-Wartung sollten kein gemeinsames, weitreichendes Konto verwenden. Jede Identität sollte nur den nötigen Serverzugriff und den benötigten erzwungenen Befehl erhalten. Eine allgemeine Administratoridentität ist bequem, macht aber jeden Fehler des Agenten deutlich teurer.
Wie beschränke ich eine SSH-Identität auf einen einzigen Befehl?
Ein erzwungener Befehl eignet sich, wenn die Aufgabe eine eng begrenzte Form hat, etwa das Deployment eines Dienstes, das Erstellen eines Gesundheitsberichts oder das Rotieren eines kontrollierten Artefakts. Setze restrict,command="..." vor die öffentliche Identität in authorized_keys und validiere alle Argumente anschließend im serverseitigen Wrapper. Verlasse dich nicht auf einen erzwungenen Befehl, der ein ungequotetes SSH_ORIGINAL_COMMAND an eine Shell übergibt.
Sollte sich ein KI-Agent jemals als root per SSH anmelden?
In der Regel gar nicht. Lege auf dem Host ein separates Dienstkonto an, verbiete die direkte Root-Anmeldung und erlaube nur die sudo-Unterbefehle, die der Wrapper benötigt. Wenn eine Aufgabe tatsächlich Root-Rechte braucht, mache diese Berechtigung in einem kleinen serverseitigen Programm sichtbar, statt einem Agenten eine interaktive Root-Shell zu geben.
Wann sollten SSH-Aktionen eine menschliche Genehmigung erfordern?
Eine Genehmigung pro Sitzung eignet sich, wenn ein bekannter Agent-Prozess während eines begrenzten Laufs mehrere risikoarme Aufrufe benötigt. Eine Genehmigung pro Aufruf passt für Identitäten, die Deployments ausführen, Firewall-Regeln ändern, auf Produktionsdatenbanken zugreifen oder destruktive Wartungsbefehle ausführen können. Die Genehmigung ist nur dann hilfreich, wenn der Dialog zeigt, welcher signierte Prozess anfragt und welches Konto sowie welcher Host verwendet werden.
Wie sollte ein Agent SSH-Hostidentitäten verifizieren?
Verwende festgelegte oder geprüfte Host-Fingerprints in known_hosts, setze StrictHostKeyChecking yes und lasse unbekannte Hosts fehlschlagen, statt sie automatisch hinzuzufügen. Erlaube einem Agenten nicht, einen geänderten Host-Fingerprint einfach zu akzeptieren, nur damit eine Aufgabe abgeschlossen wird. Eine geänderte Host-Identität ist ein Vorfall, bis jemand das Gegenteil nachweist.
Was sollte ich bei KI-gesteuerten SSH-Befehlen protokollieren?
Sinnvolle Einträge enthalten die Identität des anfragenden Prozesses, die Sitzungs-ID, den Zielhost, das Remote-Konto, den exakten Befehl und seine Argumente, die Genehmigungsentscheidung, Start- und Endzeit, den Exit-Status sowie die Regeln für aufgezeichnete Ausgaben. Protokolliere auch Ablehnungen. Ein erfolgreicher Befehl ohne Identität des Aufrufers ist bei einer Untersuchung nur ein schwacher Beleg.
Was soll ich tun, wenn ein KI-Agent einen privaten SSH-Schlüssel erhalten hat?
Rotieren die betroffene Identität, entferne ihren öffentlichen Schlüssel von allen autorisierten Stellen, beende aktive Sitzungen und prüfe Befehlsverlauf sowie Logs der Zielsysteme. Wenn der private Schlüssel in einem Modell-Prompt, Repository, Chatverlauf oder Build-Artefakt gelandet ist, behandle jeden möglichen Kopierweg als offengelegt. Gestalte den Ablauf anschließend so um, dass der Agent Aktionen anfordert, statt wiederverwendbare Zugangsdaten zu erhalten.
Eignet sich ein lokales Mac-SSH-Gateway für CI oder kopflose Automatisierung?
Ein lokaler Broker für den Mac passt gut, wenn Entwickler Coding-Agenten auf verwalteten Macs ausführen und bei sensiblen Aktionen anwesend sein müssen. Für unbeaufsichtigte CI-Runner, Linux-Build-Hosts oder serverseitige Jobs ohne lokale Desktop-Genehmigungsgrenze ist er ungeeignet. Diese Fälle brauchen eine andere Ausführungsgrenze, etwa kurzlebige Workload-Identitäten und einen kontrollierten Runner.