8 Min. Lesezeit

Wann verändert die SSH-TTY-Zuweisung einen Befehl?

Die SSH-TTY-Zuweisung ändert Abfragen, Streams, Signale und Terminalerkennung. Erfahren Sie, wann -T, -t oder -tt die Automation nicht beschädigt.

Wann verändert die SSH-TTY-Zuweisung einen Befehl?

-t in einem SSH-Befehl sorgt für weit mehr als eine sichtbare Abfrage. Die Option ersetzt drei getrennte entfernte Streams durch ein Terminal, aktiviert dessen Leitungsregeln, gibt der Sitzung ein steuerndes Terminal und veranlasst Programme zu einem Verhalten, das einen zuschauenden Menschen voraussetzt. Das kann einen interaktiven sudo-Aufruf reparieren und dabei unbemerkt einen Parser, eine Pipeline oder den Abbruch beschädigen.

Für unbeaufsichtigte Arbeit sollte kein PTY die Voreinstellung sein. Fordern Sie es nur an, wenn das entfernte Programm tatsächlich Terminalsemantik braucht, und behandeln Sie diese Entscheidung als Teil des Befehlsvertrags. Ich habe zu viele Deployment-Skripte gesehen, die während eines Notfalls -tt erhielten und es noch Jahre später enthielten, als niemand mehr wusste, welchen Fehler es verdeckte.

Ein PTY verändert die Prozessumgebung

Die SSH-TTY-Zuweisung verändert die Dateideskriptoren des entfernten Prozesses, nicht bloß das Aussehen seiner Ausgabe. Ohne PTY verbindet OpenSSH Standardeingabe, Standardausgabe und Standardfehler über Pipes oder Socket-Paare. Mit PTY macht OpenSSH es zum steuernden Terminal und dupliziert denselben Terminaldeskriptor auf alle drei Standardstreams.

Dieses Implementierungsdetail hat sichtbare Folgen. Ein Programm kann isatty() aufrufen und einen interaktiven Codepfad wählen. Der Terminaltreiber kann besondere Eingabezeichen verarbeiten, Eingaben wiederholen, Zeilenenden umwandeln und eine Vordergrund-Prozessgruppe verwalten. Der Standardfehler hat keinen eigenen entfernten Kanal mehr, weil beide Ausgabedeskriptoren auf dasselbe Terminal zeigen.

RFC 4254 hält diese Konzepte auf Protokollebene getrennt. Eine Sitzung kann pty-req und danach eine Shell oder einen exec-Befehl anfordern. Die PTY-Anforderung enthält Terminaltyp, Abmessungen und codierte Terminalmodi. Nichts daran macht aus einer exec-Anforderung eine Login-Shell.

OpenSSH bietet dafür drei nützliche Formen:

  • ssh -T host command schaltet die PTY-Zuweisung ausdrücklich ab.
  • ssh -t host command fordert ein PTY an, wenn der lokale Client ein Terminal besitzt.
  • ssh -tt host command erzwingt die Anforderung auch dann, wenn die lokale Eingabe aus einer Pipe oder einer anderen Quelle ohne Terminal kommt.

Das doppelte -t erzeugt kein leistungsfähigeres entferntes Terminal. Es übergeht die lokale Sicherheitsprüfung. Dieser Unterschied zählt in einem Build-Runner, Agentenprozess oder in printf ... | ssh, wo ein einzelnes -t die Meldung „Pseudo-terminal will not be allocated because stdin is not a terminal“ ausgeben und ohne die erwartete Terminalsemantik fortfahren kann.

Ohne PTY bleibt außerdem ein transparenter Pfad für Bytes erhalten. Das OpenSSH-Handbuch ssh(1) beschreibt diesen Modus als geeignet für eine zuverlässige Übertragung binärer Daten. Ein PTY ist ein zeichenorientiertes Gerät mit Verarbeitungsregeln und daher der falsche Transport für ein Archiv, einen Datenbank-Dump oder maschinenlesbare Ausgabe, deren Bytes unverändert bleiben müssen.

Dieselbe Wahl kann in der Konfiguration verborgen sein. Die OpenSSH-Clientoption RequestTTY akzeptiert no, yes, force oder auto, entsprechend dem Verhalten von -T, -t und der Voreinstellung. Prüfen Sie mit ssh -G host.example die wirksame Clientkonfiguration, wenn ein Befehl ohne entsprechende Option ein Terminal erhält. Hostblöcke und eingebundene Dateien können aus zwei gleich aussehenden Befehlen verschiedene Sitzungen machen.

Der Server entscheidet ebenfalls mit. PermitTTY kann die Zuweisung verweigern, und ein authorized key-Eintrag kann eine no-pty-Beschränkung tragen. Ein erzwungener Befehl läuft nur dann auf einem PTY, wenn der Client es anfordert und der Server es erlaubt. Behandeln Sie eine Ablehnung als echte Unvereinbarkeit der Schnittstellen, nicht als Anlass für weitere Versuche mit zusätzlichen -t.

Messen Sie beide Modi vor einer Änderung

Eine kleine Sonde zeigt mehr als weiteres Raten über SSH-Optionen. Führen Sie sie mit demselben Konto, derselben Hostkonfiguration und demselben Befehlspfad aus, die auch in der Produktion verwendet werden:

probe='
for fd in 0 1 2; do
    if test -t "$fd"; then kind=tty; else kind=not-tty; fi
    printf "fd%s=%s\n" "$fd" "$kind"
done
printf "term=%s\n" "${TERM-unset}"
printf "stdout-marker\n"
printf "stderr-marker\n" >&2
exit 23
'

ssh -T host.example "$probe" >no-pty.out 2>no-pty.err
printf 'no-pty ssh status=%s\n' "$?"

ssh -tt host.example "$probe" >pty.out 2>pty.err
printf 'pty ssh status=%s\n' "$?"

Der Lauf ohne Terminal sollte die drei Zeilen fdN=not-tty, term=unset und stdout-marker in no-pty.out schreiben. Nur stderr-marker sollte in no-pty.err landen. Das genaue Ergebnis für TERM kann abweichen, weil Clients und Server Umgebungseinstellungen unterschiedlich annehmen. Zeichnen Sie deshalb auf, was Ihr tatsächlicher Weg liefert, statt sich auf das Beispiel zu verlassen.

Der PTY-Lauf sollte alle drei Deskriptoren als tty melden. Beide Marker landen normalerweise in pty.out, häufig mit Wagenrücklauf und Zeilenvorschub als Zeilenende. pty.err enthält gegebenenfalls lokale SSH-Diagnosen, kann aber den ursprünglichen Standardfehler des entfernten Programms nicht als getrennten Stream wiederherstellen. Beide SSH-Befehle sollten 23 zurückgeben, denn die PTY-Zuweisung allein verwirft den entfernten Exit-Status nicht.

Erweitern Sie die Sonde vor einer Änderung um das echte Programm. Fügen Sie command -V tool, pwd, eine gefilterte Ausgabe der Umgebung und Diagnoseoptionen ohne Geheimnisse hinzu. Wenn sich die Ausgabe ändert, suchen Sie die konkrete Ursache der Verzweigung: Terminalerkennung, TERM, Terminalbreite, zusammengeführte Streams, eine Startdatei oder eine Abfrage. „Funktioniert mit -t“ beschreibt nur ein Symptom.

Führen Sie die Sonde auch durch denselben Starter aus. Ein in eine Shell eingefügter Terminalbefehl hat ein lokales TTY; einem Agenten oder CI-Arbeiter fehlt es häufig. Deshalb kann ein Versuch mit -t an der Tastatur vom automatischen Lauf abweichen, bis Sie -tt testen. Ein erzwungenes PTY kann einem Auftrag außerdem Eingaben zuführen, die er nie erwartet hat.

Testen Sie die Eingabe getrennt von der Ausgabe. ssh -n leitet die Standardeingabe des Clients von /dev/null um, und die Einstellung StdinNull bewirkt dies über die Konfiguration. Das hilft, wenn ein entfernter Befehl niemals Eingaben des Aufrufers lesen darf, schaltet die PTY-Zuweisung aber nicht selbst ab. Ein erzwungenes PTY mit leerer Eingabe verändert weiterhin Terminalerkennung, Streamzusammenführung und Verhalten beim Verbindungsabbruch.

Seien Sie vorsichtig mit SSH in einer Schleife. Ohne -n kann der erste entfernte Befehl Zeilen lesen, die für die Schleife bestimmt waren, auch wenn der Prozess sie gar nicht konsumieren sollte. Mit PTY kann das Terminalecho diese Bytes zusätzlich in das Protokoll zurückschreiben. Legen Sie den Besitzer der Standardeingabe fest, bevor Sie andere Unterschiede bewerten.

sudo-Abfragen brauchen einen eindeutigen Vertrag

sudo braucht einen Weg zur Authentifizierung, und ein PTY liefert ein Terminal zum Lesen des Passworts. Laut sudo-Handbuch liest es das Passwort normalerweise vom Terminal des Benutzers. Ohne Terminal scheitert eine Passwortanforderung, sofern kein askpass-Helfer vorhanden ist oder der Aufrufer keine andere Eingabemethode auswählt.

Das erklärt diese bekannte Reparatur:

ssh -t host.example 'sudo systemctl restart example.service'

Sie ist für einen Menschen vertretbar, der ein Passwort eingeben und den Befehl beobachten will. Für unbeaufsichtigte Ausführung ist sie schlecht. Der Auftrag kann unbegrenzt auf Eingabe warten, eine Abfrage kann die erwartete Ausgabe verschmutzen, und irgendwann könnte jemand ein Passwort durch denselben Kanal wie die Befehlsdaten leiten.

Verwenden Sie für Automation nicht interaktives sudo:

ssh -T host.example \
  'sudo -n /usr/bin/systemctl restart example.service'

Die Option -n weist sudo an, nichts abzufragen. Wenn zwischengespeicherte Anmeldedaten oder die sudoers-Richtlinie die Aktion ohne Interaktion nicht erlauben, endet sudo mit einem Fehler. Dieses Scheitern ist nützlich: Der Aufrufer erhält einen eindeutigen Status statt einer versteckten Abfrage. Kombinieren Sie das mit einer engen sudoers-Regel für einen genauen Befehl und seine Argumente, wenn privilegierte Automation wirklich nötig ist. Eine passwortlose Freigabe für jede Shell tauscht ein Verfügbarkeitsproblem gegen ein viel größeres Berechtigungsproblem.

Machen Sie einen unbeaufsichtigten Auftrag nicht von einem zwischengespeicherten sudo-Zeitstempel abhängig. Der Cache gehört zu einem Authentifizierungskontext, dessen Terminal- und Sitzungsdetails durch die Richtlinie variieren. Wenn ein Auftrag funktioniert, weil ein Administrator eine Minute zuvor sudo verwendet hat, und nach einem ruhigen Wochenende scheitert, besitzt er kein Berechtigungskonzept. Er hatte nur Glück mit dem Zeitpunkt.

sudo -S liest ein Passwort aus der Standardeingabe. Damit kann ein Befehl ohne PTY funktionieren, aber das Geheimnis wird mit dem Datenpfad vermischt, und der Aufrufer muss das Passwort verwalten. Vermeiden Sie dies für Agenten und regelmäßige Automation. Ein askpass-Helfer kann zu einem grafischen Ablauf mit einem Menschen passen, bleibt aber interaktive Authentifizierung und gehört nicht improvisiert in einen angeblich unbeaufsichtigten Auftrag.

Hier werden oft zwei PTYs verwechselt. SSH kann vor dem Start von sudo ein entferntes PTY zuweisen. Unabhängig davon kann modernes sudo den erlaubten Befehl für E/A-Protokollierung und Isolation in einem eigenen PTY ausführen; sudo 1.9.14 aktiviert use_pty standardmäßig. Dieses innere PTY stellt die äußere Passwortabfrage nicht bereit, wenn die SSH-Sitzung kein Terminal besitzt. Es beginnt erst, nachdem sudo genug Informationen zur Ausführung hat.

Manche sudoers-Konfigurationen verlangen ein Terminal auch als Richtlinie. Ältere Unternehmenskonfigurationen verwendeten häufig requiretty, das in einem aktuellen System noch vorhanden sein kann. Prüfen Sie die wirksame sudoers-Richtlinie, statt jede Meldung „terminal is required“ als Passwortabfrage zu deuten.

Ein PTY wählt keine Shell-Startdateien

Ein SSH-Befehl mit PTY bleibt ein Befehl, den die konfigurierte Shell des Kontos mit -c ausführt. Das OpenSSH-Handbuch sshd(8) beschreibt genau diesen Ablauf, und der Servercode übergibt den Befehl an die Shell des Benutzers. Die PTY-Zuweisung verändert die Deskriptoren um diese Shell; sie fügt weder -i noch -l oder eine Login-Option hinzu.

Das ist wichtig, wenn PATH, ein Sprachmanager oder ein Alias an der interaktiven Eingabeaufforderung vorhanden ist, in der Automation aber fehlt. -t kann den Pfad scheinbar reparieren, weil eine Startdatei das Terminal prüft oder weil das aufgerufene Werkzeug ein Terminal erkennt. Es kann auch gar nichts bewirken. Eine Abhängigkeit davon bindet den Auftrag an Dateien, die Entwickler für ihre eigenen Terminals bearbeiten.

Bash besitzt einen Sonderfall, der die verbreitete Annahme schwerer durchschaubar macht. Laut Handbuch liest eine interaktive Login-Shell Profildateien, eine interaktive Shell ohne Login .bashrc, und eine nicht interaktive Shell nutzt BASH_ENV. Bash versucht zudem, den Start durch einen entfernten Shell-Daemon zu erkennen, und kann dann selbst ohne Interaktion .bashrc lesen, außer beim Aufruf als sh. Das ist Bash-Verhalten, kein Versprechen von SSH, und lässt sich nicht auf jede Kontoshell übertragen.

Wählen Sie den Shellmodus direkt, wenn Sie ihn brauchen:

# A predictable noninteractive Bash command with explicit inputs
ssh -T host.example \
  'PATH=/usr/local/bin:/usr/bin:/bin /bin/bash -c '\''command -v deploy && deploy'\'''

# A login environment, requested because the command truly depends on it
ssh -T host.example \
  '/bin/bash -lc '\''command -v deploy && deploy'\'''

Die zweite Form liest absichtlich Login-Startdateien und übernimmt deren Risiken: Eine Ausgabe aus einem Profil kann ein Protokoll beschädigen, und das Profil kann sein Verhalten ohne Prüfung des Deployments ändern. Für Produktionsaufträge sind ein absoluter Programmpfad und eine kleine, ausdrücklich gesetzte Umgebung meist besser.

Aliasse bilden eine weitere Falle. Nicht interaktives Bash erweitert sie nur mit aktiviertem expand_aliases, und eine Shellfunktion existiert nur, wenn ein Startmechanismus sie definiert oder importiert. Falls ssh host deploy erst nach dem Hinzufügen von -t funktioniert, prüfen Sie, ob deploy ein echtes Programm ist. Ein Terminal sollte nicht bestimmen, ob das entfernte Konto das Programm findet.

Denken Sie daran, dass SSH eine Befehlszeichenfolge sendet und keinen Argumentvektor für das endgültige Programm. Die entfernte Kontoshell analysiert diese Zeichenfolge, nachdem die lokale Shell bereits ihre eigenen Anführungszeichen verarbeitet hat. Die PTY-Zuweisung verändert keine dieser Analysen. Wenn Werte Leerzeichen oder Shell-Metazeichen enthalten können, senden Sie ein Skript mit festen Eingaben, verwenden Sie einen entfernten Helfer mit festgelegtem Datenformat oder schützen Sie jede Ebene bewusst. Ein Terminal kann kein Argument reparieren, das die lokale Shell zu früh erweitert hat.

Ctrl-C folgt Terminalregeln nur mit PTY

Jede entfernte Aktion sperren
Das Tresortor verweigert alle SSH-Aktionen, solange die Mac-App gesperrt ist.

Mit PTY ist Ctrl-C normalerweise ein Eingabebyte, das der entfernte Terminaltreiber interpretiert. POSIX nennt es das Zeichen INTR. Wenn das Terminalflag ISIG gesetzt ist, verwirft der Treiber das Byte und sendet SIGINT an jeden Prozess in der Vordergrundgruppe des Terminals. Deshalb kann eine entfernte Vordergrundpipeline als eine Aufgabe stoppen.

Der lokale SSH-Client versetzt das lokale Terminal in einen passenden Modus und sendet Tastendrücke über den Kanal. Das entfernte PTY verwaltet kanonische Eingabe, Echo, besondere Zeichen und Fenstergröße. Programme wie Vollbildeditoren können diese Modi verändern, und nach einem ungewöhnlichen Abbruch kann die lokale Anzeige falsch aussehen, bis das Terminal zurückgesetzt wird.

Ohne PTY gibt es keinen entfernten Terminaltreiber, der Ctrl-C interpretiert, und keine Terminal-Vordergrundgruppe. RFC 4254 definiert eine getrennte SSH-Kanalanforderung signal, erlaubt Systemen ohne Signalunterstützung jedoch, sie zu ignorieren. Die Kombination aus Client, Server, Wrapper und aufgerufenem Programm kann daher anders abbrechen als ein interaktives Terminal.

Ctrl-Z und Jobsteuerung zeigen den Unterschied noch schneller. In einem Terminal kann das Zeichen SUSP SIGTSTP an die Vordergrundgruppe senden, und eine interaktive Shell kann den Job später fortsetzen. Ein einmaliger entfernter Befehl erhält durch ein PTY noch keine brauchbare interaktive Jobsteuerung. Nach dem Anhalten kann der SSH-Client auf eine gestoppte entfernte Gruppe warten, ohne Shellprompt für fg.

Verlassen Sie sich bei einer entfernten Transaktion nicht darauf, dass jemand im richtigen Moment Ctrl-C drücken kann. Definieren Sie den Abbruch im entfernten Befehl. Ein Shell-Wrapper kann Signale abfangen und seine Kindgruppe beenden, ein Dienstmanager kann den Prozess besitzen, und ein entfernter Timeout kann die Laufzeit begrenzen. Testen Sie anschließend den Verbindungsabbruch und nicht allein die Tastatur.

ssh -tt host.example '
  trap '\''printf "wrapper got INT\n" >&2; exit 130'\'' INT
  printf "remote shell pid=%s\n" "$$"
  sleep 300
'

Ctrl-C sollte den PTY-Pfad auslösen und die Kontrolle zurückgeben. Wiederholen Sie den Test mit dem echten Programm, weil Shells, Terminalanwendungen und Prozessmanager verschiedene Handler installieren. Testen Sie auch das Schließen der Netzwerkverbindung. Der Abbau des PTY kann ein Hangup für die steuernde Sitzung auslösen, während ein Kind ohne PTY mit offener Ausgabepipe den SSH-Kanal offen halten kann. Einen Prozess in den Hintergrund zu schicken ist in keinem Modus ein Plan für saubere Ablösung.

Übergeben Sie lange Arbeiten an einen entfernten Dienstmanager oder ein Jobsystem und geben Sie eine Jobkennung zurück. So erhält der Abbruch ein eindeutiges entferntes Ziel, und SSH meldet nur, ob die Übergabe erfolgreich war. Ein kurzer Clientausfall entscheidet dann nicht, ob eine halb abgeschlossene Migration weiterläuft.

Der Exit-Status bleibt erhalten, Wrapper können ihn ersetzen

OpenSSH gibt den Exit-Status des entfernten Befehls in beiden Modi zurück. Das Clienthandbuch sagt, dass ssh mit diesem Status oder bei einem Fehler mit 255 endet. RFC 4254 beschreibt die Kanalnachricht exit-status als vorzeichenlosen 32-Bit-Wert und eine getrennte Nachricht exit-signal für die Beendigung durch ein Signal.

Die PTY-Zuweisung macht einen Erfolgsstatus nicht verlässlicher. Die Shellzusammensetzung bestimmt, welcher Status zum Status des entfernten Befehls wird. Der folgende Befehl meldet den Status von printf und kann dadurch ein fehlgeschlagenes Deployment verbergen:

ssh -tt host.example 'deploy; printf "finished\n"'

Bewahren Sie das Ergebnis ausdrücklich:

ssh -T host.example '
  deploy
  rc=$?
  printf "deploy_status=%s\n" "$rc" >&2
  exit "$rc"
'
rc=$?
printf 'ssh_status=%s\n' "$rc"
exit "$rc"

Lokale Pipelines können ihn erneut verbergen. In Shells ohne Funktion für den Pipelinestatus gibt ssh host command | tee log gewöhnlich den Status von tee zurück. Schreiben Sie die SSH-Ausgabe zuerst in eine Datei, nutzen Sie eine Shell mit getesteter Pipelinestatus-Funktion oder lesen Sie die einzelnen Statuswerte. Nehmen Sie nicht an, dass set -e jede Pipeline, Bedingung oder Subshell repariert.

Der Status 255 ist mehrdeutig, weil OpenSSH ihn für Clientfehler reserviert, während auch ein entferntes Programm mit 255 enden kann. Wenn dieser Unterschied zählt, lassen Sie den entfernten Wrapper einen strukturierten Abschlussdatensatz auf einem geschützten Kanal ausgeben oder ordnen Sie Anwendungsstatus einem vereinbarten Bereich zu. Authentifizierungsfehler, Fehler bei der Hostprüfung, Transportverlust und ein echter entfernter 255 dürfen nicht denselben Wiederholungsversuch auslösen.

Fehler beim Verbindungsaufbau treten auf, bevor ein entfernter Wrapper etwas ausgeben kann. Klassifizieren Sie sie lokal mit Client-Timeouts und ausreichenden SSH-Diagnosen, halten Sie diese Diagnosen aber aus der Datendatei des Programms fern. Sobald der Server den Wrapper startet, sollte er eine Laufkennung und einen abschließenden Statusdatensatz liefern. So unterscheidet der Aufrufer „nie gestartet“ von „gestartet, dann Verbindung verloren“. Das verhindert blinde Wiederholungen von Befehlen, die den Zustand bereits geändert haben könnten.

Auch die Beendigung durch Signale braucht diese Sorgfalt. Eine Shell stellt ein Signal oft als 128 plus Signalnummer dar, doch das SSH-Protokoll kann ein Ausgangssignal direkt melden, und das Clientverhalten muss nicht immer dem Kindstatus einer lokalen Shell entsprechen. Definieren Sie die Statuswerte Ihres Wrappers, statt nach einem Ausfall alle Werte über 128 rückwärts zu deuten.

Ein PTY führt Streams zusammen und verändert Bytes

Anmeldedaten vom Agenten fernhalten
SSH-Schlüssel bleiben im Tresor verschlüsselt und gelangen nie in Agentenkontext oder Terminaleingabe.

Mit der PTY-Anforderung geben Sie die saubere Trennung von entfernter Standardausgabe und Standardfehler auf. Die OpenSSH-Serverimplementierung dupliziert die Slave-Seite des PTY auf die Deskriptoren 0, 1 und 2. Das Protokoll bietet einen erweiterten Datenkanal für Standardfehler, aber ein an ein einzelnes Terminal angeschlossener Prozess hat beide Ausgabestreams bereits in dieselbe Bytefolge geschrieben.

Das beschädigt ein häufiges Automationsmuster:

ssh -T host.example command >result.json 2>diagnostic.log

Ohne PTY kann der Standardfehler des entfernten Programms diagnostic.log erreichen, während das JSON in result.json bleibt. Mit PTY können entfernte Warnungen, Passwortabfragen, Banner, Fortschrittsanzeigen und JSON gemeinsam in result.json landen; lokale SSH-Diagnosen können weiterhin in diagnostic.log erscheinen. Eine Umleitung am Client kann Bytes nicht mehr trennen, nachdem der Server sie zusammengeführt hat.

Die Terminalausgabe kann einen Zeilenvorschub außerdem in Wagenrücklauf plus Zeilenvorschub umwandeln. Eingaben können als Echo erscheinen, der kanonische Modus kann auf eine ganze Zeile warten, und Steuerzeichen können Terminalfunktionen auslösen. Für ein Terminal ist das korrekt, in einem Binärprotokoll bedeutet es beschädigte Daten.

Programme mit Terminalerkennung ergänzen häufig Farben, Fortschrittsbalken, Pager oder Abfragen. Auf einem Terminal können sie zeilenweise puffern und über eine Pipe blockweise. Dadurch wirkt ein Lauf ohne PTY festgefahren, obwohl er arbeitet. Korrigieren Sie die Pufferung möglichst in der Anwendung: Wählen Sie deren einfache Ausgabeoption, ungepufferten Modus oder Protokolleinstellung. Ein vorgetäuschtes Terminal ändert mehrere Bedingungen zugleich und kann das eigentliche Pufferproblem verbergen.

Erzeugt ein Befehl Maschinendaten, behalten Sie -T bei und lassen Sie das Programm ein nicht interaktives Format ausgeben. Braucht es tatsächlich ein Terminal, behandeln Sie die gesamte Ausgabe als Transkript. Analysieren Sie ein PTY-Transkript nicht wie eine stabile API.

SSH eines Agenten muss ohne Dialog scheitern

Aktive Agentensitzung stoppen
Das Sessions-Journal widerruft einen genehmigten Lauf ohne Änderung des entfernten Terminals.

Ein autonomer Aufrufer kann einen Terminaldialog nicht sicher führen. Eine Abfrage, die einem Menschen bei der Fehlerbehebung hilft, kann einen Agenten warten lassen, zu erfundener Eingabe bringen oder eine teilweise Aktion als Erfolg einstufen lassen. Der SSH-Befehl muss festlegen, ob Interaktion erlaubt ist, bevor Anmeldedaten, Privilegien oder entfernter Zustand ins Spiel kommen.

Kombinieren Sie bei Agentenläufen das fehlende PTY mit unterdrückten Abfragen auf jeder Ebene. SSH-Hostauthentifizierung und Hostprüfung brauchen eine vorbereitete Richtlinie. Privilegienerhöhung sollte sudo -n verwenden. Das entfernte Werkzeug sollte seine nicht interaktive Option, einen eindeutigen Timeout und Eingaben über Dateien oder benannte Argumente erhalten, statt eines Dialogs. Erfassen Sie Standardausgabe, Standardfehler und Status getrennt.

Beheben Sie eine fehlende Passwortabfrage nicht, indem Sie dem Agenten ein Passwort oder einen privaten Schlüssel geben. Authentifizierungsmaterial und Terminalverhalten sind getrennte Fragen. Ein PTY verringert nicht die Möglichkeiten gestohlener Anmeldedaten, und kein PTY schützt keine Daten, die bereits in der Prozessumgebung liegen.

Sallyport verlagert die Grenze für Anmeldedaten aus dem Agentenprozess: Ein MCP-fähiger Agent fordert eine SSH-Aktion über den eingebauten zustandslosen Helfer sp-ssh an, während der verschlüsselte Tresor den SSH-Schlüssel liefert und das Activity-Journal den Aufruf aufzeichnet. Der Befehl braucht weiterhin einen bewussten PTY-Vertrag, denn Geheimnisisolierung kann nicht entscheiden, ob das entfernte Programm Terminalsemantik erwartet.

Eine Genehmigung unterscheidet sich ebenfalls von einer entfernten Abfrage. Eine lokale Genehmigungskarte kann eine definierte Aktion vor der Ausführung erlauben; eine Abfrage des entfernten Terminals erscheint in einer bereits offenen Sitzung und kann nach früheren Nebenwirkungen eintreffen. Halten Sie menschliche Genehmigungen aus dem entfernten Bytestrom heraus, damit eine Ablehnung eindeutig ist und Protokolle die versuchte Aktion erkennen.

Braucht ein Agent ein interaktives Wartungswerkzeug, teilen Sie den Ablauf. Lassen Sie den Agenten einen Befehl oder eine Anforderung vorbereiten und übergeben Sie die laufende Terminalsitzung anschließend einem Menschen. Oder ersetzen Sie das Werkzeug durch eine nicht interaktive Aktion für Automation. Wer einen Agenten als schreibenden Bediener behandelt, erhält von beiden Systemen die am schlechtesten testbare Variante.

Wählen Sie den Modus als Teil der Schnittstelle

Der richtige Modus folgt aus der Schnittstelle des entfernten Programms, nicht aus einer allgemeinen Regel für oder gegen PTYs. Verwenden Sie bei der Prüfung diese Liste:

  • Verwenden Sie -T für JSON, Archive und exakte Bytes, weil es transparente Daten und getrennte Fehlerausgabe bewahrt.
  • Verwenden Sie -T mit sudo -n für unbeaufsichtigte privilegierte Arbeit, damit die Authentifizierung scheitert statt zu warten.
  • Verwenden Sie -t, wenn ein Mensch ein sudo-Passwort eingibt oder eine Terminalschnittstelle bedient.
  • Verwenden Sie -tt aus einer Pipe oder einem Agentenstarter nur nach Prüfung der übergangenen lokalen TTY-Kontrolle.
  • Übergeben Sie lange Aufträge an einen entfernten Manager, denn ein PTY bietet keine dauerhafte Prozessverantwortung.

Notieren Sie die Wahl neben dem Befehl. Tests sollten Deskriptortypen, Streamtrennung, Abbruch und Status prüfen, nicht bloß einige erwartete Wörter. Falls ein Abhängigkeitsupdate plötzlich ein Terminal verlangt, lassen Sie den Test scheitern und untersuchen Sie die neue Abfrage oder Erkennungsverzweigung, bevor Sie -t hinzufügen.

Nehmen Sie den gewählten Modus als strukturierte Metadaten in Protokolle auf, statt ihn aus farbiger Ausgabe oder einer Abfrage abzuleiten. Wenn eine Störung mehrere Hosts betrifft, trennt dieses eine Feld Terminalverhalten von Authentifizierungs-, Netzwerk- und Anwendungsfehlern, bevor jemand etwas erneut ausführt.

Die Serverrichtlinie kann PTYs über die OpenSSH-Konfiguration oder eine authorized key-Beschränkung ablehnen. Auch deshalb sollten sie keine zufällige Abhängigkeit werden. Ein für Automation gebauter Befehl sollte mit -T nutzbar bleiben; ein interaktiver Befehl sollte klar scheitern, wenn er kein Terminal erhalten kann.

Behandeln Sie jeden Vorschlag für -tt als Schnittstellenänderung. Führen Sie die Sonde erneut aus, leiten Sie beide lokalen Streams um, senden Sie Ctrl-C, erzwingen Sie einen von null verschiedenen Status des entfernten Befehls und trennen Sie die Verbindung während des Laufs. Wenn sich das Ergebnis nicht genau beschreiben lässt, ist der Befehl nicht für unbeaufsichtigte Ausführung bereit.

FAQ

Was bewirkt ssh -t genau?

Es fordert den SSH-Server auf, ein PTY zuzuweisen und die entfernte Sitzung damit zu verbinden. Programme sehen Terminaldeskriptoren, entfernte Streams werden zusammengeführt, und Eingaberegeln können Signale erzeugen.

Was ist der Unterschied zwischen ssh -t und ssh -tt?

-t erzwingt eine PTY-Anforderung, wenn der lokale Client ein Terminal besitzt. Als -tt erzwingt es die Zuweisung auch ohne Terminal an der lokalen Standardeingabe, wie oft in Pipelines und Agentenstartern.

Weist SSH einem entfernten Befehl standardmäßig ein TTY zu?

Normalerweise läuft ein ausdrücklich angegebener entfernter Befehl ohne PTY. Verwenden Sie -T für eine eindeutige Wahl oder -t, wenn der Befehl tatsächlich ein Terminal braucht.

Warum scheitert sudo über SSH ohne TTY?

Wenn sudo ein Passwort braucht, liest es dieses normalerweise am Terminal des Benutzers. Nutzen Sie für Automation sudo -n und eine enge sudoers-Regel, damit der Befehl scheitert statt abzufragen.

Ist sudo -S in einem SSH-Skript sicher?

sudo -S überträgt dem Skript die Passwortbeförderung und mischt das Geheimnis in die Standardeingabe. Vermeiden Sie es bei Agenten und regelmäßiger Automation; verwenden Sie eine Genehmigung ohne Abfrage.

Lädt ssh -t .bashrc oder .profile?

Nein, die PTY-Zuweisung wählt keine Shell-Startdateien. Fordern Sie bei Bedarf ausdrücklich eine interaktive oder Login-Shell an, obwohl eine explizite Umgebung und ein Programmpfad vorhersehbarere Aufträge ergeben.

Warum werden stdout und stderr mit ssh -t gemischt?

OpenSSH verbindet die Deskriptoren 1 und 2 mit derselben PTY-Slave-Seite, sodass der Server nur einen Terminal-Bytestrom hat. Eine spätere Clientumleitung kann die ursprünglichen Streams nicht rekonstruieren.

Ändert ein PTY den SSH-Exit-Code?

Das PTY selbst tut es nicht; OpenSSH gibt weiterhin den Status des entfernten Befehls zurück. Wrapper, Pipelines, Signale und der besondere Clientfehler 255 können das Ergebnis ändern oder verdecken.

Warum reagiert Ctrl-C mit und ohne ssh -t unterschiedlich?

Der PTY-Treiber wandelt das Unterbrechungszeichen in SIGINT für seine Vordergrundgruppe um. Ohne PTY gibt es diese entfernte Gruppe nicht, sodass der Abbruch von SSH-Signalen und Prozessstruktur abhängt.

Sollten KI-Agenten ssh -tt für möglicherweise nachfragende Befehle verwenden?

Nein. Ein Agentenbefehl sollte Abfragen unterdrücken und mit einem brauchbaren Status scheitern; ein erzwungenes Terminal kann einen Konfigurationsfehler in einen endlosen Dialog verwandeln und Diagnoseausgaben mischen.

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