- Fly.io wollte sich in den Remote-SSH-Editing-Flow von VSCode einklinken und stellte dabei fest, dass VSCode statt einer leichtgewichtigen Nutzung der Remote-Shell eine eigene Agent-Struktur installiert und ausführt
- LLM-Codegenerierung ist in einer mit der Ausführungsumgebung verbundenen Agent-Loop nützlicher, kann aber auch die Systemeinstellungen des Entwicklungs-Notebooks verändern, weshalb eine isolierte Linux-Instanz nötig ist
- Tramp von Emacs erweitert Funktionen auf Remote-Umgebungen, indem es in interaktiven Umgebungen wie SSH Bourne-Shell-Befehle ausführt; VSCode hingegen lädt über einen Bash-Snippet-Stager einen Agent und ein Node-Binary herunter
- Der VSCode-Agent läuft über portweitergeleitetes SSH und baut eine WebSockets-Verbindung zum VSCode-Frontend auf, über die er Dateien durchsuchen, beliebige Dateien bearbeiten, Shell-PTYs ausführen und sich selbst persistent machen kann
- Schon VSCode-Remote-Editing auf Entwicklungsservern zu erlauben, ist eine große Belastung; während eines Produktions-Incidents wäre diese Vorgehensweise noch bedenklicher, bei einer Custom-Verbindung für Fly Machines ließ sich diese Struktur jedoch vermeiden
Erforderliche Isolation für LLM-Agent-Loops
- Fly.io interessierte sich dafür, sich in den Ablauf zu integrieren, mit dem VSCode Remote-Editing per SSH durchführt
- Denn viele Menschen nutzen VSCode, insbesondere auch VSCode-Forks, die Code mit LLMs generieren
- Von LLMs generierter Code ist nützlich, wenn er weiß, was die Nutzer tun; noch wirksamer wird er, wenn sich der Loop mit der Ausführungsumgebung schließen lässt
- Das LLM generiert Code
- Das Agent-Scaffolding führt den Code aus
- Der Code erzeugt Fehler
- Der Agent gibt die Fehler an das LLM zurück
- Dieser Prozess wiederholt sich
- Diese Struktur kann ein halbwegs wirksames Gegenmittel gegen Halluzinationen sein, ist aber riskant, wenn man sie unverändert auf dem Entwicklungs-Notebook laufen lässt
- Das LLM kann nicht nur das Git-Projekt bearbeiten, an dem gearbeitet wird, sondern wiederholt auch Systemeinstellungen verändern
- Die bessere Form ist, eine geschlossene Agent-Konfiguration in einer sofort startenden, sauberen Linux-Instanz auszuführen und zu verhindern, dass diese Umgebung dem Nutzer Schaden zufügen kann
Funktionsweise des VSCode-Remote-SSH-Agenten
- Tramp von Emacs ist Elisp-Code und kommt einem geistigen Vorfahren von Remote-Editing-Systemen nahe
- Wenn es an eine interaktive Umgebung andockt, in der sich Bourne-Shell-Befehle ausführen lassen, etwa eine SSH-Session, erweitert es Emacs-Funktionen auf diese Umgebung
- VSCode hat ebenfalls eine Tramp-ähnliche Funktion, ist aber nicht einfach eine nach TypeScript portierte, vereinfachte Tramp-Struktur
- Statt bei Remote-Verbindungen nur vorhandene Tools zu verwenden, führt VSCode einen Bash-Snippet-Stager aus, um einen Agent herunterzuladen
- Dieser Agent enthält eine Binary-Installation von Node
- Die vermutlich zugehörige Quelle ist das server/node-Verzeichnis von microsoft/vscode
- Der Agent arbeitet über portweitergeleitetes SSH und erzeugt eine WebSockets-Verbindung zum laufenden VSCode-Frontend
- Das Subprotokoll kann durch das Dateisystem navigieren
- Beliebige Dateien lassen sich bearbeiten
- Es kann eigene Shell-PTY-Prozesse starten
- Es kann sich selbst persistent machen
- Für Tools, die auf diese Weise funktionieren, gibt es in der Sicherheitsbranche eine Bezeichnung, die hier aber nicht direkt genannt wird, weil das gegenüber VSCode unfair wäre
- VSCode-Remote-Editing auf einem Entwicklungsserver zu erlauben, ist beunruhigend; wenn dieselbe Methode während eines Produktions-Incidents eingesetzt wird, wird die Sorge noch größer
- Beim Erstellen einer Custom-Verbindung zu Fly Machines musste man sich um diese Struktur nicht kümmern, weshalb es im tieferen Sinne wohl kein wichtiges Problem war
1 Kommentare
Meinungen auf Hacker News
Nachdem er etwa einen Monat lang versucht hatte, einen langen Beitrag über Software zu schreiben, an der er drei bis vier Jahre herumgebastelt hatte, wurde Kurt nervös, weil seit August nichts mehr im Blog erschienen war, und beschloss schließlich, den schlichtesten Beitrag zu schreiben.
Die Idee war, entgegen dem bisherigen Vorgehen einen Low-Effort-Beitrag zu schreiben, und er dachte, in 30 Minuten ließe sich einer verfassen. Das war einfach nur etwas, woran er herumgebastelt hatte, in Textform; vermutlich hat er sich weniger Gedanken darüber gemacht als die Leser.
Der Satz im README „A compromised remote could use the VS Code Remote connection to execute code on your local machine.“ war viel klarer, und neben diesem Sicherheitshinweis sollte wohl eine CVE-Nummer stehen.
Die aktuell sichtbaren ersten beiden Beiträge, McCord-Valims FLAME-Livebook-GPU-Beitrag und dieser Beitrag mit „murid“, zeigen den psychologischen Verlauf eines Entwicklers ziemlich treffend.
System-Binaries könnte man erlauben, aber das würde komplizierter, und VSCode müsste womöglich mehr auf den Client verlagern. Grob gesucht findet man auf der ssh-Server-Seite chroot-Optionen, aber im Handbuch des ssh-Clients steht dazu nicht viel.
Oder die Lösung könnte darin bestehen, remote einen Docker-Container herunterzuladen, einen Container mit dem gemounteten Remote-Verzeichnis zu starten und sich dann per ssh mit diesem Container zu verbinden.
Das Problem bei einem Ansatz, nur Dateien in Unterverzeichnissen zu synchronisieren, ist, dass auch von VSCode gestartete Remote-Ausführung und Debugging nötig sind. Deshalb brauchen auch Plugins Remote-Zugriff oder müssen remote ausgeführt werden, und bei manchen Code-Beobachtungen wären die Kosten einer vollständigen Vorabsynchronisierung aller Unterverzeichnisse zu hoch, wenn sie lokal liefen.
Das klingt vielleicht naiv, aber ich verstehe nicht recht, warum das ein Sicherheitsproblem ist. Wenn man sich per ssh mit einer Maschine verbinden und Socket-Port-Forwarding nutzen kann, hat man im Grunde ohnehin die Berechtigung, auch alles andere zu tun, und das VSCode-Protokoll scheint das nur auf eine für sie bequeme Weise offenzulegen.
Ich frage mich, ob es deshalb ein Sicherheitsproblem ist, weil jemand im selben Netzwerk wie die Remote-Maschine, aber ohne SSH-Rechte, eine Verbindung zu dem per SSH weitergeleiteten Port herstellen kann. Aus Nutzersicht gefällt mir das SSH-System von VSCode, weil es ziemlich gut funktioniert.
sshoder PuTTY bekommt.VSCode installiert einen Remote-Agenten auf der Zielmaschine, nutzt ssh als Transportprotokoll und erklärt, diesen Transportkanal mit dem Nutzer zu teilen. Wenn er nur das tut, was man will, ist das kein Problem; aber ein agentenbasiertes System, das beliebige APIs offenlegt, schafft eine viel größere Angriffsfläche und ein höheres Risiko als der vertraute, aber weiterhin heikle Ansatz, über ssh ein Terminal nachzuahmen.
Das Protokoll über diese Verbindung kann durch das Dateisystem navigieren, beliebige Dateien bearbeiten, eigene Shell-PTY-Prozesse starten und sich selbst persistent machen. Nur weil ein Client per ssh auf einen Remote-Server zugreift, heißt das nicht, dass dieser Server auf dem Client beliebigen Code ausführen kann; mindestens muss der Client ausdrücklich irgendeine Aktion ausführen.
Es ist aber in demselben Sinne ein Sicherheitsproblem, in dem „curl | bash“ eines ist. Eine noch nähere Analogie wäre vielleicht curl | bash in der
bashrc.Weil der Agent am Netzwerk hängt und ständig läuft, wird ein Loch in der Firewall des Entwicklungsservers zugleich zu einem Loch in der Firewall des Laptops.
Je mehr man darüber weiß, wie VSCode funktioniert, desto mehr wirkt es wie etwas, das mit Duct Tape und den verfluchtesten Ideen zusammengehalten wird, auf die JavaScript-Entwickler kommen könnten.
Allein bei der SSH-Erweiterung gibt es zwei Formate für Workspace-URIs. Eines besteht praktisch nur aus dem Hostnamen, das andere aus einem hexadezimal codierten JSON-Dokument; Letzteres wird verwendet, wenn zusätzliche Informationen wie ein bestimmter Benutzername nötig sind oder der Hostname Großbuchstaben enthält.
Der Grund, warum das tatsächlich nötig ist: Wenn es in den zuletzt verwendeten Workspaces gespeichert wird, wird es aus irgendeinem Grund in Kleinbuchstaben umgewandelt.
SSH-Verbindungen unterstützen auch Einstellungen dafür, welche Erweiterungen auf dem Server installiert werden sollen, aber wenn man zu viele einträgt, kann man sich nicht mehr mit Windows-Hosts verbinden. Sie werden über CMD als Kommandozeilenargumente übergeben, CMD hat aber ein Limit von 8191 Zeichen, und über dieses CMD wird dann PowerShell aufgerufen.
Man kann benutzerdefinierte Autovervollständigung, Diagnosen usw. anbieten und für sprachübergreifende Unterstützung auch ein eigenes Go to definition bauen.
Ich wünschte, Microsoft würde mich für ein paar Monate einstellen, in eine Ecke setzen und mich dieses Chaos entwirren lassen.
Ich habe Server für Kurse zu Netzwerken, Binary Exploitation und einführender Systemprogrammierung betrieben, und dieses Ding ist ein großes Ärgernis. Wegen dieses dämlichen Trojaners für Remote-Zugriff verstehen die Studierenden nicht, wie man den OpenSSH-Client benutzt.
Ich habe ein paar Dinge versucht, um das zu beheben. In die motd des Kursservers habe ich geschrieben, dass man das VSCode-Remote-Server-Plugin nicht verwenden soll, und vor dem Kurs habe ich
ncdu /homelaufen lassen, um zu zeigen, dass Studierende mit mehr als 100 MB Server-Plattenverbrauch ausnahmslos VSCode-Nutzer sind.Außerdem habe ich das Limit für Benutzerprozesse auf 45 gesetzt, weil dieser VSCode-Trojaner für Remote-Zugriff aus irgendeinem Grund jeweils etwa 50 Node-Prozesse verwendet. Wenn Studierende die motd und die Warnungen im Unterricht ignorierten, liefen sie in das Limit und mussten uns bitten, Prozesse zu beenden, damit sie sich wieder verbinden konnten.
Am Ende habe ich das Prozesslimit durch ein Skript ersetzt, das alle 10 Sekunden den
.vscode-server-Trojaner für Remote-Zugriff komplett abschießt.In einem Kurs, in dem ich Tutor war, gab es eine Aufgabe, bei der man grundlegenden Maschinencode verarbeiten und damit Assembly- und Ausführungswerkzeuge für die gelernte ISA nachbilden sollte; die Studierenden mussten mit Werkzeugen wie
hexdumpdie Byte-Struktur von Dateien verstehen.Sublime hat Objektdateien jedoch „hilfsbereit“ wie die Textdarstellung von hexdump gerendert, dabei Leerzeichen für bessere Lesbarkeit eingefügt und sie in einer anderen Endian-Reihenfolge angezeigt als
hexdumpauf dem Linux-Server der Uni.Jedes Semester kamen einige Studierende mit der Frage, warum ihr Code, der ASCII-Strings wie
AD DE EF BElesen sollte, unbekannten Text findet; sie hatten nicht geprüft, dass die tatsächlichen Byte-Werte mit 0xDE, 0xAD, 0xBE, 0xEF beginnen.Ich bin mir nicht sicher, was hier die Alternative sein soll. Das Bearbeiten über SSH in VSCode funktioniert erstaunlich gut, und ich habe schon vor langer Zeit aufgehört, auf Remote-Maschinen mit vim, nano oder micro herumzufummeln.
Der Agent lässt mich ungestört und leise arbeiten. Es fühlt sich fast so an, als würde ich lokal auf meiner Maschine arbeiten, und das ist aus meiner Sicht ein großer Vorteil.
Es kann ein Sicherheitsrisiko sein, aber die Developer Experience ist unvergleichlich. Welche anderen Editoren VSCode verdrängt, ist mir ziemlich egal; das Tool soll mich einfach arbeiten lassen, ohne im Weg zu stehen.
Es deployt keine Binaries, sondern liest und schreibt Bytes über Pipes, und jede sinnvolle Ausführung passiert lokal. Vor allem erzeugt es keine Persistenz: Es ist ein Unterschied, ob „ein VSCode-Plugin zugreifen kann, solange man per SSH verbunden ist“, oder ob „ein VSCode-Plugin für immer zugreifen kann“.
Wenn sie auf mehreren Remote-Systemen arbeiten, wissen sie oft nicht, womit sie gerade verbunden sind oder wie der Verbindungsstatus ist. Das Terminal ist langsam, und die Persistenz des Sitzungszustands ist uneinheitlich.
Das ist eine deutlich schlechtere Erfahrung als
tmuxund ein ordentlicher Texteditor. Außerdem ist der Server sehr schwergewichtig und beendet sich nicht sauber; es ist auch üblich, sechs Serverinstanzen gleichzeitig laufen zu haben.Die Hälfte der Updates geht kaputt, und man verliert auch mal eine Stunde, weil man nicht weiß, wie man sich mit dem echten ssh-Client auf den Host einloggt und den kaputten vscode-Server aufräumt.
Was haben wir daraus gelernt? Dass Remote Code Execution existiert? Dass falsch platziertes Vertrauen in Entwicklungswerkzeuge oft bereut wird? Dass modernes Softwaredesign ein Chaos ist? Mit ein wenig Aufmerksamkeit wäre das alles offensichtlich gewesen.
SSH ist eine Lösung aus den 90ern. Es ist Telnet mit ein paar angeflanschten Funktionen, und obwohl es „secure“ shell heißt, ist es im Wortsinn weniger sicher als Telnet+TLS.
Leute, die dachten, sie hätten ja schon einen Tunnel mit einer Benutzersitzung auf dem Server und müssten deshalb keinen separaten Netzwerktransport und kein Sicherheitsprotokoll für Anwendungen bauen, haben alle möglichen seltsamen, aber gefeierten Dinge auf SSH draufgesetzt.
Das ist das Ergebnis davon, Konzepte aus verteilten Betriebssystemen zu verwerfen, die seither entwickelten fortgeschrittenen Authentifizierungs- und Autorisierungsmethoden zu ignorieren und dann das Schlechteste und Einfachste zu übernehmen.
Dass so ein „SSH-Agent“ absurd ist, stimmt nicht. Wir haben uns nicht darauf zubewegt, die richtigen Werkzeuge für die Aufgabe zu bauen, und deshalb stopfen wir immer mehr in vorhandene Werkzeuge, die nie für diesen Zweck entworfen wurden. Wir haben kein Recht, überrascht zu tun.
Das ist die Welt, die wir geschaffen haben. Wir alle haben sie geschaffen, durch Arbeit oder durch stillschweigende Zustimmung. Wenn nicht bei SSH, dann gilt es genauso für Politik, Handel, Schulen und alles andere. Wir leben jeden Tag in dem Haufen, den wir selbst aufgeschichtet haben, und jeder Tag, an dem wir nichts tun, legt noch eine Schaufel obendrauf. Man kann nicht die Schaufel in der Hand halten und so tun, als sei das überraschend oder verrückt.
Wenn man also ausgehende HTTPS-Verbindungen generell erlaubt, sollte man in der Regel auch alle ausgehenden Verbindungen außer SMTP erlauben. Tatsächlicher schädlicher Traffic wird ohnehin über HTTPS getunnelt, und der verbleibende Effekt ist nur, die Verbreitung neuer Protokolle zu behindern, die nicht die Komplexität und Ineffizienz eines Tunnels mitschleppen.
Ich wünschte, Web-Logins würden eher so funktionieren wie SSH.
Manchmal rauszugehen und Gras anzufassen, ist gut für die Seele. Und ich hätte gern auch Vorschläge, wie man ein besseres SSH-Protokoll bauen könnte. Beschwerden ohne konstruktive Kritik sind wenig nützlich.
Der Begriff „SSH agent“ ist hier verwirrend, weil er normalerweise einen Daemon meint, der Authentifizierungs-Tokens zwischenspeichert.
Außerdem macht dieser Ansatz den bekannten macOS-SSH-Agent kaputt: https://github.com/maxgoedjen/secretive/issues/543
Ich stimme völlig zu, dass vscode remote auf Produktionsservern zu verwenden wahnsinnig ist.
Die übrigen Funktionen, die als „absurd“ beschrieben werden, klingen allerdings nach erwartbaren Funktionen.
Ich bin bis zum Staff Engineer bei MAANG gekommen, und ich glaube, das wäre mit plain Vim allein schwer zu erreichen gewesen. Gleichzeitig sehe ich, dass andere High Performer weiterhin eher Vim oder Emacs nutzen.
Es gibt viele hervorragende Entwickler, die VCode, JetBrains usw. verwenden, aber die Neigung, Einstiegshürden aktiv zu suchen, die Magie von Werkzeugen durch Erkundung zu entzaubern und vollständig Open Source sowie stark anpassbare, Community-getriebene Projekte zu schätzen, erklärt dieses Phänomen für mich besser als Funktionen oder Bedienkomfort.
Wenn ich lese, wie kompliziert Remote Editing in VSCode ist, habe ich eher weniger Lust, VSCode zu verwenden. Man kann sich einfach per ssh auf die Maschine einloggen und den Editor auf dieser Maschine verwenden.
Die Lösung von VSCode funktioniert, ist aber weder elegant noch allgemein anwendbar und außerdem leichter kaputtzubekommen. Und sorry an die Emacs-Nutzer, aber Tramp ist immer noch ziemlich furchtbar, und netrw ist auch nicht besser.
watchexec+rsyncMan kann bestimmte Dateipfade überwachen und genau das synchronisieren, was nötig ist. Man arbeitet weiterhin auf dem lokalen Dateisystem, hat also keine Editierlatenz, kann alle lokalen Tools nutzen, und die Synchronisierung ist in Millisekunden erledigt.
Man kann dafür sorgen, dass lokal gelöschte Dateien auch remote gelöscht werden, und nach der Arbeit auf der Remote-Maschine bleibt immer eine lokale Kopie zurück. Das war bei Tramp immer etwas, das man manuell synchronisieren musste. Außerdem ist es editorunabhängig.
Diese VS-Code-Funktion macht mir, jetzt da ich weiß, was sie tatsächlich tut, Unbehagen.
Als ich Copilot eingeschaltet habe, wurde die Toolbar noch größer, und Text flog an die Stelle, an der ich gerade schreiben wollte. Vim lässt mich einfach Code sehen, nachdenken und schreiben. Mit VSCode fällt es mir schwer, in einen Flow-Zustand zu kommen.
Ich bin Mitte 30; an der Uni habe ich emacs benutzt und bin im ersten Job zu vim gewechselt. Für ein extrem undurchsichtiges Java-Projekt habe ich IntelliJ benutzt, aber ansonsten bin ich bei vim geblieben.
Nur wenn ich komplexe Regex-Bearbeitung brauche, starte ich gelegentlich vim.
Statt mit bestehenden Remote-Tools zusammenzuarbeiten, verteilt VSCode einen umfassenden Agenten, der die Installation eines Node.js-Binarys, eine WebSocket-Verbindung zurück zum VSCode-Frontend und weitreichende Systemzugriffsfunktionen umfasst.
Dieser VSCode-Agent hat umfassende Berechtigungen, darunter das Durchsuchen des Dateisystems, das Bearbeiten von Dateien, das Erzeugen von Shell-PTY-Prozessen und sogar die Fähigkeit zur Selbstpersistenz.
Falls es um die Remote-Seite geht, ist klar, dass elisp Tramp bei den Abhängigkeiten leichtgewichtiger ist; aber ich frage mich, ob die Angriffsfläche wirklich so anders ist. Anders gesagt: Ich weiß nicht, ob das Remote-Node-Binary Berechtigungen hat, die ein Benutzer, der beliebige ssh-Befehle ausführt, nicht hätte.
Wenn das ursprüngliche Ziel war, einem LLM alle Schlüssel zu einer temporären, wegwerfbaren virtuellen Maschine zu geben, frage ich mich, ob der vom Agenten geöffnete Socket bedeutet, dass es auch die Entwickler-Maschine erreichen kann, die man eigentlich isolieren wollte.
Das klingt verrückt, aber der Kernel selbst könnte einen Webserver oder ein anderes Protokoll mit Verschlüsselung und Authentifizierung bereitstellen und über eBPF die direkte Kontrolle über die gesamte Maschine ermöglichen. Das könnte ein völlig anderes Paradigma für Client/Server-Fernsteuerung werden.
Natürlich könnte es auch ein Sicherheitsloch sein, das groß genug ist, dass der Death Star hindurchpasst.