Agent Lab: Eine Sandbox, in der KI-Agenten alles dürfen, nur nicht raus
Die Idee
KI-Coding-Agenten sind am nützlichsten, wenn man sie lässt: Pakete installieren, Container bauen, Tests laufen lassen, stundenlang an einem Branch arbeiten, ohne dass ich jeden Befehl bestätige. Auf meinem eigenen Rechner will ich das nicht. Dort liegen meine Daten, und von dort aus ist mein Heimnetz erreichbar.
Das Agent Lab ist meine Antwort darauf: eine eigene Maschine für Agenten auf zwei Mini-PCs mit Proxmox, von überall per SSH erreichbar, ohne offenen Port am Router. Hier steht, welche Überlegungen dahinterstecken.
1. Erst das Schutzziel, dann die Maßnahmen
Die wichtigste Entscheidung war die Frage, wovor ich mich eigentlich schütze. Die Antwort: Was auf den Mini-PCs passiert, bleibt dort. Mein Arbeitsrechner und das Heimnetz bleiben unerreichbar.
Ausdrücklich nicht geschützt sind die Agenten voreinander. Sie laufen alle als derselbe Benutzer, ohne Egress-Firewall und ohne eigene Sandbox pro Agent. Das ist gewollt, denn jede dieser Sperren hätte die Agenten bei ihrer eigentlichen Arbeit behindert. Ein klar benanntes Schutzziel macht solche Lücken zu Entscheidungen statt zu Versehen.
Die Grenze verläuft deshalb zwischen Hypervisor und VM, nicht zwischen Rechnern. In der VM dürfen Agenten alles. Die Proxmox-Hosts bleiben tabu, denn auf einem davon läuft der DNS-Filter für den ganzen Haushalt. Wer den kontrolliert, kontrolliert die Namensauflösung jedes Geräts im Haus.
2. Zwei Sperren, beide gemessen
Eine einzelne Sperre ist eine Konfiguration, die man einmal falsch setzen kann. Deshalb gibt es zwei unabhängige:
- ▸Im Overlay-Netz (Tailscale): Die Agenten-VM trägt ein eigenes Tag, das in den Zugriffsregeln nirgends als Quelle vorkommt. Ich komme zur VM, die VM aber zu nichts. Erlaubt ist nur, was ausdrücklich freigegeben wurde.
- ▸Im lokalen Netz: Die VM hängt nicht im Heimnetz, sondern an einer eigenen Bridge mit eigenem Subnetz. Ins Internet geht es per NAT, ins Heimnetz und auf die Verwaltungsports des Hosts wird abgewiesen. Eine Netzwerkkarte im Heimnetz hat die VM gar nicht mehr.
„Gemessen“ ist dabei wörtlich gemeint. Ich habe aus der VM heraus jedes Ziel einzeln angefragt (Router, DNS-Filter, Hypervisor-Oberfläche, Arbeitsrechner) und mich erst mit einer Ablehnung zufriedengegeben. Eine Regel, die nur im Konfigfile steht, ist eine Annahme.
Eine Ausnahme kam später dazu, und an ihr habe ich am meisten gelernt. Die Sperre ins Heimnetz verwarf auch die Antworten der VM. Tailscale lief dadurch selbst zuhause über ein Relay in Paris, mit knapp 60 ms Latenz. Die Lösung ist eine Regel, die nur Antworten auf Verbindungen durchlässt, die ein Gerät aus dem Heimnetz selbst aufgebaut hat. Die VM darf antworten, aber nie anfangen. Danach lag die Latenz bei 1 ms.
3. Kein offener Port heißt: Jemand anderes nimmt die Verbindung an
Damit mein Laptop von unterwegs nach Hause kommt, muss irgendein Gerät mit öffentlicher Adresse die Verbindung annehmen. Es gibt genau drei Kandidaten: einen offenen Port zuhause, einen eigenen Server im Netz oder einen fremden Rendezvous-Dienst. Port und eigener Server waren raus, also blieb der dritte.
Ich wollte zuerst den Koordinationsserver selbst betreiben (Headscale) und ihn per Cloudflare Tunnel erreichbar machen. Das scheitert technisch: Der Tunnel entfernt bei POST-Anfragen den Upgrade-Header, auf dem das Tailscale-Protokoll aufbaut. Das gilt für jeden Tunnel auf HTTP-Ebene. Endgültig verworfen habe ich die Idee aber aus einem anderen Grund. Ein selbst betriebener Koordinationsserver ist ein weiterer Dienst, den ich absichern, aktualisieren und überwachen müsste, und genau das wäre das schwächste Glied. Es bleibt beim gehosteten Dienst.
Öffentliche Anwendungen laufen dagegen über einen Cloudflare Tunnel. Der baut die Verbindung von innen nach außen auf, die Heim-IP steht in keinem DNS-Eintrag, und eine Anwendung ist nur erreichbar, wenn sie ausdrücklich eingetragen ist.
4. Parallele Agenten brauchen getrennte Arbeitsplätze
Mehrere Agenten im selben Arbeitsverzeichnis gehen schief, das hatte ich in einem anderen Projekt schon erlebt. Hier ist die Trennung deshalb von Anfang an eingebaut:
- ▸Ein Agent, ein Git-Worktree. Ein kleines Skript klont ein Repo einmal und legt pro Aufgabe einen eigenen Worktree an. Jeder Agent hat seinen eigenen Branch und sein eigenes Verzeichnis.
- ▸Ein Multiplexer statt offener Terminals. Die Agenten laufen in einem Terminal-Multiplexer, der als Dienst auf der VM startet. Ich kann mich trennen, den Laptop zuklappen, und die Agenten arbeiten weiter. Später verbinde ich mich vom Arbeitsrechner oder Laptop wieder.
- ▸Echte SSH-Schlüssel, kein Login über den VPN-Dienst. Damit lesen Multiplexer und VS Code Remote dieselbe
ssh_config, und der Zugang hängt nicht an einem einzigen Anbieter.
5. System und Daten getrennt behandeln
Die VM hat zwei Platten mit unterschiedlichen Aufgaben. Die Systemplatte wird gesichert. Die Datenplatte mit Repos, Worktrees und Docker ist von der Sicherung ausgeschlossen, und zwar absichtlich. Der Stand des Codes gehört auf GitHub. Was nur im Worktree liegt und nicht gepusht ist, ist damit auch nicht gesichert. Diese Regel zwingt zu einer sauberen Gewohnheit.
Ähnlich beim Aufräumen: Ein wöchentlicher Job löscht nur, was sich wiederherstellen lässt, also alte Images, Build-Cache und gestoppte Container. Volumes, Repos und Worktrees fasst er nie an. Automatisches Löschen von Daten richtet irgendwann Schaden an.
Was ich bewusst weggelassen habe, steht genauso dokumentiert wie das, was läuft. Ein Beispiel ist direnv: Es führt Dateien aus dem Repo automatisch aus, und bei Code, den Agenten schreiben, ist das ein unnötiges Risiko.
6. Das Netz schützt das Netz, nicht die Schlüssel
Diese Erkenntnis war unbequem: Die ganze Netztrennung schützt das Heimnetz, aber keinen einzigen API-Schlüssel auf der VM. Jeder Agent kann lesen, was der gemeinsame Benutzer lesen kann.
Daraus folgt eine einfache Regel. Ein Schlüssel auf der VM ist pro Dienst beschränkt, hat minimale Rechte und ein Ausgabenlimit und ist in Minuten widerrufbar. Im schlimmsten Fall steht der Dienst hinter dem Schlüssel auf dem Spiel, nie das Netzwerk. Dieses Learning Log ist ein Beispiel dafür: Der Agent, der diesen Eintrag angelegt hat, darf mit seinem Token nur Entwürfe schreiben. Veröffentlichen kann nur ich.
7. Kleine Erkenntnisse unterwegs
- ▸Speicheranzeige ist nicht Speicherverbrauch. Proxmox zeigte für die VM fast 12 GB an, genutzt waren gut 1 GB. Ich hatte das Memory Ballooning ganz abgeschaltet, um eine feste Zuteilung zu bekommen. Damit fehlte aber das Gerät, über das der Gast freie Seiten zurückmelden kann. Die richtige Einstellung ist Minimum gleich Maximum: Die Zuteilung bleibt fest, und freie Seiten gehen trotzdem an den Host zurück.
- ▸Ein DNS-Server gehört nicht an DHCP. Der Router verteilte monatelang eine DNS-Adresse, die der Filter längst nicht mehr hatte. Der Haushalt lief nur weiter, weil die Geräte parallel per IPv6 einen anderen DNS-Server bekamen, und gefiltert wurde in dieser Zeit fast nichts.
- ▸Zwei Dienste, ein Port, ein Problem. Host und VM nutzten hinter derselben NAT denselben Tailscale-Port und teilten sich damit eine Zuordnung im Router. Seitdem die VM einen eigenen Port hat, bleibt die Verbindung direkt.
- ▸Die Plattenwerte waren überraschend. Beim zufälligen Schreiben war die alte SATA-SSD schneller als die abgenutzte NVMe. Deshalb liegt die schreibintensive Arbeit jetzt auf der SATA-Platte.
Wo es gerade steht
Die Sandbox läuft im Alltag: Agenten arbeiten parallel in eigenen Worktrees, und ich verbinde mich vom Arbeitsrechner oder von unterwegs. Offen sind zwei Punkte, die ich ehrlich benennen will. Die Systemsicherung liegt bisher nur auf derselben Platte wie die VM, eine Kopie außer Haus fehlt. Und ein Zurückspielen habe ich noch nie getestet. Bis dahin ist eine genaue Bestandsaufnahme der laufenden VM das Rezept für einen Neuaufbau, aber noch kein Skript.
Fortsetzung folgt.