Alle Artikel
KI-Agenten isolieren: Kata Containers und Agent Sandbox auf EKS
KI-Agenten führen Code aus, den sie selbst geschrieben haben, und niemand hat ihn zuvor geprüft. Wie lässt sich das sicher betreiben? In dieser Anleitung baue ich auf Amazon EKS eine Sandbox für KI-Agenten auf: Kata Containers isolieren den Code in einer eigenen Micro-VM, Agent Sandbox verwaltet ihren Lebenszyklus. Die Sandbox hat weder ausgehenden Netzwerkverkehr noch Zugangsdaten.
·
Jannis Schoormann

KI-Agenten sind vom Generieren von Text dazu übergegangen, Code auszuführen. Ein Coding-Agent schreibt ein Skript und führt es aus, ein Datenanalyse-Agent generiert Code und führt ihn auf Ihren Dateien aus, und ein Recherche-Agent ruft eine Webseite ab, parst sie und folgt den darin gefundenen Links. In jedem dieser Fälle hat ein Modell den Code wenige Sekunden zuvor geschrieben. Kein Mensch hat ihn geprüft, und jeder Text, den der Agent unterwegs gelesen hat, könnte ihn beeinflusst haben.
In diesem Beitrag baue ich auf Amazon EKS eine Sandbox für KI-Agenten auf, eine isolierte Ausführungsumgebung für diesen Code auf Basis von Kata Containers und Agent Sandbox. Jede Sandbox erhält über Kata Containers ihre eigene leichtgewichtige virtuelle Maschine, und Agent Sandbox, ein Kubernetes-SIG-Apps-Projekt, verwaltet ihren Lebenszyklus. Am Ende führt ein LLM-Agent auf Ihrem Laptop Code, Shell-Befehle und Dateioperationen innerhalb einer Kata-VM aus und erhält die Ergebnisse zurück. Die VM hat keinen ausgehenden Netzwerkverkehr (Egress), keine Zugangsdaten und kein Kubernetes-Token.
Warum KI-Agenten eine Sandbox brauchen: Risiken von generiertem Code
Das klassische Container-Sicherheitsmodell geht davon aus, dass Sie wissen, was Sie ausführen: Sie haben das Image gebaut, gescannt und über eine Pipeline bereitgestellt. Von Agenten generierter Code passt nicht in dieses Modell. Die Workload entsteht zur Laufzeit, ist jedes Mal anders, und wer auch immer den vom Agenten verarbeiteten Text geschrieben hat, steuert teilweise mit, was der Agent tut.
Eine bösartige Anweisung, versteckt in einer Webseite, einem GitHub-Issue, einem PDF oder einer Tool-Antwort, kann das Modell dazu bringen, Code zu schreiben, der Umgebungsvariablen ausliest, das Netzwerk scannt, den Metadaten-Endpunkt der Cloud abfragt oder Daten irgendwohin sendet.
Daraus ergibt sich ein einfaches Bedrohungsmodell: Gehen Sie davon aus, dass der Code in der Sandbox feindlich ist, und fragen Sie, was er erreichen kann.

Warum ein normaler Container nicht ausreicht: Container-Isolation und gemeinsamer Host-Kernel
Ein Container ist ein Prozess, auf den Namespaces, cgroups, seccomp und Capabilities angewendet werden. Für vertrauenswürdigen Code ist das eine solide Grenze. Doch alle Container auf einem Node teilen sich den Host-Kernel, sodass jeder Syscall des Agenten-Codes im selben Kernel landet, der auch Ihr kubelet, Ihre anderen Mandanten und die Zugangsdaten Ihres Nodes betreibt. Eine einzige Kernel-Schwachstelle genügt, um diese Grenze zu überwinden, und Linux liefert jedes Jahr mehrere CVEs zur Rechteausweitung aus.
Was Agenten über Isolation hinaus benötigen
Agenten-Workloads verhalten sich zudem anders als typische Kubernetes-Workloads:
Sie sind zustandsbehaftete Singletons: Eine Agentensitzung hat einen Workspace, installierte Pakete und Zwischendateien.
Sie benötigen eine stabile Identität, denn der Agent muss seine Sandbox beim nächsten Tool-Aufruf wieder erreichen.
Die Startzeit spielt eine Rolle. Nutzer warten auf eine Antwort, daher fällt ein Kaltstart von 30 Sekunden pro Tool-Aufruf auf.
Sie sind die meiste Zeit im Leerlauf. Sitzungen pausieren, während das Modell nachdenkt oder der Nutzer liest, deshalb möchte man sie in den Ruhezustand versetzen, statt sie laufen zu lassen.
Deployments und StatefulSets bilden das nicht gut ab. Agent Sandbox deckt den Lebenszyklus ab, und Kata sorgt darunter für die Isolation.
Was ist Kata Containers? Isolation per Micro-VM in Kubernetes
Kata Containers führt jeden Pod in einer leichtgewichtigen virtuellen Maschine aus, während Kubernetes weiterhin einen normalen Container sieht. Die beteiligten Komponenten:
kubelet und containerd: Für Kubernetes ändert sich nichts. Die Pod-Spezifikation verweist lediglich auf eine andere
RuntimeClass.Der Kata-Shim (
containerd-shim-kata-v2): containerd ruft ihn anstelle von runc auf, und er startet und verwaltet die VM.Der VMM (Virtual Machine Monitor): Er bootet mithilfe von KVM eine Micro-VM. Er läuft entweder als separater Prozess (QEMU, Cloud Hypervisor, Firecracker) oder, wie in diesem Beitrag, integriert im Rust-Shim (runtime-rs): Dragonball läuft im Shim-Prozess selbst.
Der Gast-Kernel: ein minimaler, auf schnellen Start optimierter Linux-Kernel. Mit diesem Kernel kommuniziert der Code des Agenten.
Der kata-agent: Er läuft in der VM und erzeugt dort im Auftrag des Shims die eigentlichen Container.
Kubernetes bindet dies über eine RuntimeClass ein:
overhead teilt dem Scheduler mit, dass jeder Kata-Pod zusätzliche CPU und zusätzlichen Arbeitsspeicher für den VMM und den Gast-Kernel kostet. scheduling.nodeSelector stellt sicher, dass Kata-Pods nur auf Nodes landen, auf denen Kata installiert ist.
Kata benötigt Hardwarevirtualisierung, also /dev/kvm auf dem Node, und diese Anforderung prägt das gesamte Setup. Reguläre EC2-Instanzen stellten dies historisch nicht bereit, daher führt der direkte Weg auf AWS über Bare-Metal-Instanzen.

Agent Sandbox: Lebenszyklus für Agenten-Workloads
Agent Sandbox (Kubernetes Agent Sandbox) ist ein SIG-Apps-Projekt, das mit den Ressourcen Sandbox, SandboxTemplate, SandboxClaim und SandboxWarmPool eine Kubernetes-native API für das ergänzt, was es „isolierte, zustandsbehaftete Singleton-Workloads“ nennt. Es verwaltet den Lebenszyklus und überlässt die Isolation der RuntimeClass.
Die API:
Sandbox(Kern): eine isolierte Umgebung mit stabiler Identität, getragen von einem Pod. Sie hat einen Lebenszyklus, den Sie pausieren und fortsetzen können.SandboxTemplate(Erweiterung): eine wiederverwendbare Vorlage, zum Beispiel „Python-Executor auf Kata ohne Egress“.SandboxClaim(Erweiterung): eine Anforderung einer Sandbox auf Basis einer Vorlage. So fordert eine Anwendung eine Sandbox an, ohne die Pod-Details zu kennen.SandboxWarmPool(Erweiterung): vorab gestartete Sandboxes, die darauf warten, angefordert zu werden. Dadurch wird die Boot-Latenz der VM verborgen.
Die fünfte Komponente ist der Sandbox Router, ein HTTP-Proxy, der jede Anfrage anhand von Headern (X-Sandbox-ID, X-Sandbox-Namespace, X-Sandbox-Port) an die richtige Sandbox weiterleitet. Laut Projektdokumentation funktioniert direktes Port-Forwarding auf Pods mit sicheren Runtimes wie Kata nicht, weshalb der Router der unterstützte Zugriffspfad ist.

Anleitung: Kata Containers und Agent Sandbox auf Amazon EKS einrichten
Was wir aufbauen
Ein EKS-Cluster mit zwei verwalteten Nodegroups:
system: einet3.largefür CoreDNS, den Agent-Sandbox-Controller und den Router.kata-metal: einec5.metalmit nativem KVM, mit Label und Taint versehen, sodass dort nur Sandbox-Workloads landen.
kata-deploy, das Kata und die RuntimeClass
kata-dragonballauf dem Metal-Node installiert.Den Agent-Sandbox-Controller und den Router.
Eine
Sandbox, die einen kleinen Python- und Shell-Executor innerhalb einer Kata-VM ausführt. Eine NetworkPolicy blockiert jeglichen Egress und erlaubt Ingress nur vom Router.Einen LLM-Agenten auf Ihrem Laptop, der Python- und Shell-Befehle in der Sandbox ausführt und Dateien hinein- und herausbewegt.

Kostenhinweis.
c5.metalkostet in us-east-1 etwa 4,08 $/h und in eu-central-1 etwas mehr, zuzüglich 0,10 $/h für die EKS-Control-Plane. Die Abrechnung für die Metal-Instanz beginnt etwa 20 Minuten nach Beginn der Anleitung, sobald die Nodegroups erstellt sind. Schritt 8 (Aufräumen) ist zwingend erforderlich. Ich empfehle dringend, vor dem Start einen AWS-Budget-Alarm einzurichten.
Alle Dateien befinden sich im zugehörigen Repository: https://github.com/Liquid-Reply/agent-sandboxing-demo
Schritt 1: Ein Cluster mit Bare-Metal-Nodegroup
Der Cluster benötigt:
Eine Bare-Metal-Nodegroup für Kata. Kata benötigt
/dev/kvm, was bei verwalteten EKS-Nodegroups eine*.metal-Instanz bedeutet (hierc5.metalmit 96 vCPUs). Versehen Sie sie mit Labels (kata-host=true,workload=sandbox) und einem Taint (sandbox=true:NoSchedule), damit dort nur Sandbox-Workloads landen.Amazon Linux 2023 auf dieser Nodegroup, da kata-deploy Binärdateien und die containerd-Konfiguration auf den Host schreibt und das schreibgeschützte Root-Dateisystem von Bottlerocket dies verhindert.
Eine Nodegroup ohne Taint für das System, auf der CoreDNS, der Agent-Sandbox-Controller und der Router laufen, die den Sandbox-Taint alle nicht tolerieren. Ohne sie bleiben sie im Status
Pending. Eine einzelnet3.large(etwa 0,08 $/h) genügt.Durchsetzung von Netzwerkrichtlinien, die das VPC CNI bei EKS standardmäßig nicht vornimmt. Aktivieren Sie sie mit
enableNetworkPolicy: "true"im Addonvpc-cni, andernfalls wird die Abriegelung aus Schritt 5 stillschweigend ignoriert.
Der relevante Teil der cluster.yaml:
Die vollständige Datei im Repository setzt außerdem autoModeConfig.enabled: false, weil neuere eksctl-Versionen Auto Mode als Standard ankündigen. eksctl ersetzt keine Umgebungsvariablen, halten Sie die Werte daher synchron mit env.sh.
Schritt 2: kata-deploy installieren
kata-deploy ist ein DaemonSet, das die Kata-Binärdateien, den Gast-Kernel und das Image auf dem Node installiert, containerd konfiguriert und die RuntimeClasses anlegt.
kata-values.yaml:
Zwei Dinge haben mich hier Zeit gekostet:
Verwenden Sie für das DaemonSet keine Selektion über
katacontainers.io/kata-runtime. kata-deploy setzt dieses Label auf dem Node erst nach seiner eigenen Installation; wenn das DaemonSet danach selektiert, entsteht ein Henne-Ei-Problem. Das Label gehört ausschließlich an die RuntimeClass, und das Chart setzt es dort bereits.Setzen Sie
defaultShim. Das Chart verwendet standardmäßigqemu-runtime-rs, und sobaldshims.disableAlldiesen Shim deaktiviert hat, gerät der kata-deploy-Pod sofort in einen Crashloop mitDEFAULT_SHIM 'qemu-runtime-rs' must be one of the configured SHIMS for this architecture: [dragonball].helm templaterendert in beiden Fällen fehlerfrei, weil die Prüfung nur innerhalb des Containers läuft. Deshalb installiere ich ohne--wait: Wenn der Pod in einen Crashloop gerät, hängt--waitsonst für das gesamte Timeout.
kata-deploy startet containerd auf dem Metal-Node neu. Warten Sie nach Abschluss des Rollouts etwa eine Minute, bevor Sie Kata-Pods erstellen.
Warum dragonball: Der Go-Shim (kata-qemu) ist seit Kata 4.0 zugunsten von runtime-rs, der Rust-Implementierung, als veraltet markiert. Innerhalb von runtime-rs empfiehlt die Kata-Dokumentation den integrierten VMM-Modus. Dragonball läuft im Shim-Prozess statt als separater QEMU- oder Cloud-Hypervisor-Prozess, sodass es keine IPC zwischen Shim und VMM gibt und Lebenszyklus und Aufräumen an einer Stelle stattfinden.
Schritt 3: Kata Containers testen: Gast-Kernel und Host-Kernel vergleichen
Der einfachste Beweis dafür, dass ein Pod in seiner eigenen VM läuft, ist der Vergleich des Kernels im Pod mit dem Kernel auf dem Host.
manifests/kata-smoke.yaml:
Der Gast-Kernel ist der minimale Kernel von Kata; der Host läuft mit dem Kernel von AL2023. Sind beide identisch, läuft der Pod auf runc, und die RuntimeClass wurde nicht angewendet.
Schritt 4: Agent-Sandbox-Controller und Router installieren
Diese Anleitung verwendet nur Sandbox. Ich installiere trotzdem die Erweiterungen (SandboxTemplate, SandboxClaim, SandboxWarmPool), weil Sie diese in der Produktion einsetzen würden.
Als Nächstes der Router:
Schritt 5: Die Sandbox, ein abgeriegelter Code-Executor
In der Sandbox läuft eine kleine HTTP-API (executor.py), die ausschließlich die Standardbibliothek nutzt und dem Agenten einen minimalen Workspace bietet. Sie wird aus einer ConfigMap in python:3.14-slim eingebunden, sodass Sie kein Image bauen müssen. Die Endpunkte:
/executeführt Python in einem persistenten Worker-Prozess aus, sodass Variablen und Importe zwischen den Aufrufen erhalten bleiben. Stürzt der Code den Worker ab, geht nur dieser Zustand verloren./shellführt einen Befehl mitsh -caus./files/writeund/files/readbewegen Dateien nach/tmphinein und heraus; das Root-Dateisystem ist schreibgeschützt./resetlöscht den Python-Zustand.
Jeder Aufruf hat ein Timeout und liefert stdout, stderr und exit_code zurück.
Die Dateien in sandbox/:
executor.py: die Ausführungs-API.sandbox.yaml: die RessourceSandbox.networkpolicy.yaml: die Abriegelung.kustomization.yaml: bündelt alles und erzeugt die ConfigMapkata-demo-executor.
Die NetworkPolicy entfernt jeglichen Egress und erlaubt Ingress nur vom Router auf Port 8888.
Kata und die NetworkPolicy schützen unterschiedliche Dinge. Kata schützt den Node und die anderen Mandanten vor dem Code. Die NetworkPolicy schützt alles, was über das Netzwerk erreichbar ist: das Internet, andere Dienste und den Instance-Metadata-Endpunkt, der die IAM-Zugangsdaten des Nodes herausgibt. Eine VM mit offenem Egress ist weiterhin eine hervorragende Plattform für Datenexfiltration.
Die PolicyEndpoints sind das, was der Network-Policy-Agent des VPC CNI tatsächlich durchsetzt. Gibt es keinen Eintrag, ist die Richtlinie nicht aktiv.
Schritt 6: Zugriff über den Router
Der Router ermittelt die Ziel-Sandbox anhand der Header und leitet die Anfrage weiter. Fehlt X-Sandbox-ID, wird 400 zurückgegeben.
Ein fehlschlagender Aufruf von urlopen('https://example.com') beweist die Egress-Abriegelung nicht; er zeigt lediglich, dass DNS blockiert ist. verify-sandbox.sh führt die vollständige Reihe von Prüfungen aus:
Das Skript prüft:
Gast- gegenüber Host-Kernel sowie, dass der Pod nicht neu gestartet wurde;
rohen TCP-Egress per IP ins Internet, zu IMDS (
169.254.169.254) und zum Cluster-DNS;Ingress von einem Wegwerf-Pod, der nicht der Router ist;
dass der Pfad über den Router funktioniert, der Prozess als uid 65534 läuft und kein ServiceAccount-Token eingebunden ist.
Es beendet sich mit einem Wert ungleich null, sobald etwas fehlschlägt.
Schritt 7: Ein Agent, der die Sandbox nutzt
Der Agent plant auf der vertrauenswürdigen Seite, und die Sandbox führt nur aus. Genau dafür existiert der Rest des Setups.
agent/agent.py läuft auf Ihrem Laptop und spricht über das OpenAI SDK mit einem Proxy, sodass jedes Tool-Calling-fähige Modell hinter dem Proxy funktioniert. Ich verwende unseren internen LiteLLM-Endpunkt; richten Sie ihn auf Ihren eigenen Proxy oder ein beliebiges anderes OpenAI-kompatibles Gateway. Der Agent stellt dem Modell vier Tools zur Verfügung: run_python, run_shell, write_file und read_file. Jeder Tool-Aufruf läuft über das Port-Forward und den Router in die Kata-VM.

Das Szenario proof fordert das Modell auf,
den SHA-256 der ersten 1000 Primzahlen zu berechnen (dafür muss es Code ausführen; es kann ihn nicht raten);
zu versuchen, aus der Sandbox heraus
https://example.comzu erreichen, und zu berichten, was passiert ist;die Kernel-Release-Version anzugeben.
Ein getesteter Lauf mit LITELLM_MODEL=gpt-6-luna war nach zwei Runden abgeschlossen:
Worauf Sie in der Ausgabe achten sollten:
Der Digest ist deterministisch. Der vom Modell geschriebene Code unterscheidet sich von Lauf zu Lauf, der SHA-256 darf es jedoch nicht – das beweist, dass das Modell tatsächlich Code ausgeführt hat, statt sich eine Antwort auszudenken.
Die Kernel-Release ist die des Kata-Gast-Kernels, nicht die des AL2023-Host-Kernels.
Die Internetanfrage schlägt fehl, und der Agent erledigt seine Aufgabe trotzdem, die Egress-Abriegelung stört den Agenten also nicht.
Der API-Schlüssel existierte ausschließlich auf dem Laptop. In der Sandbox gibt es nichts zu stehlen, und selbst wenn es etwas gäbe, gäbe es keinen Weg nach draußen.
Führen Sie ihn anschließend interaktiv aus:
Das Szenario breakout fordert das Modell ausdrücklich auf, auszubrechen (IMDS, ServiceAccount-Token, Kubernetes-API, Internet, Schreibzugriffe außerhalb von /tmp) und eignet sich damit gut als Live-Gegenstück zu verify-sandbox.sh. /approve on zeigt ein Human-in-the-Loop-Muster: Jeder Tool-Aufruf wartet auf Ihre Bestätigung, bevor er die Sandbox erreicht.
Für eine einmalige Aufgabe ohne REPL führen Sie uv run agent/agent.py "your task" aus. Meldet ein Tool-Aufruf sandbox unreachable, ist das Port-Forward abgebrochen.
Schritt 8: EKS-Cluster löschen und Kosten vermeiden
Die EBS-Prüfung in verify-cleanup.sh gilt regionsweit und zeigt möglicherweise nicht zugehörige Volumes an. Wechseln Sie anschließend mit kubectl config use-context <your-usual-context> wieder zu Ihrer gewohnten kubeconfig zurück.
Wenn Sie die Demo auf mehrere Sitzungen verteilen, skalieren Sie die Metal-Nodegroup auf null, statt den Cluster neu aufzubauen:
Wo Sandboxing sinnvoll ist
Der Executor in diesem Beitrag ist der kleinste nützliche Baustein. Dasselbe Muster (Lebenszyklus über Agent Sandbox, Isolation über Kata, Abriegelung über Richtlinien) funktioniert für:
Code-Interpreter-Backends, etwa für „Führe diese Analyse auf meiner CSV-Datei aus“ in einem Chat-Produkt. Jede Sitzung erhält ihre eigene VM, und Dateien berühren nie gemeinsam genutzte Infrastruktur.
Coding-Agenten mit persistenten Workspaces: eine Sandbox pro Aufgabe oder Pull Request, mit ausgechecktem Repository und installierten Abhängigkeiten. Sie wird in den Ruhezustand versetzt, während der Agent auf die CI wartet, und danach fortgesetzt.
Rollouts für Reinforcement Learning und Evaluierung mit Tausenden kurzlebiger, identischer Umgebungen. Warm Pools sind hier am wichtigsten.
Mandantenfähige Agentenplattformen als Teil einer internen Entwicklerplattform. Teams fordern Sandboxes per
SandboxClaimauf Basis von Vorlagen an, die das Platform Engineering definiert und in denen Runtime, Netzwerkrichtlinie und Ressourcenlimits fest verankert sind.Isolierte MCP-Server und Tools. Tool-Server von Drittanbietern sind Code, den Sie nicht selbst geschrieben haben, daher ist es sinnvoll, sie wie von Agenten generierten Code zu behandeln.

Was Sandboxing nicht löst
Eine VM-Grenze entscheidet nicht darüber,
was der Agent erreichen darf. Die Egress-Richtlinie ist eine eigene Kontrolle und wird schwieriger, sobald Sie Allowlists benötigen.
welche Zugangsdaten der Agent besitzt. Das beste Muster ist das hier verwendete: Geheimnisse bleiben auf der vertrauenswürdigen Seite, und die Sandbox erhält nur Code.
in wessen Namen der Agent handelt. Agentenidentität und Autorisierung gegenüber internen APIs sind weiterhin ein offenes Designproblem.
ob das Ergebnis korrekt ist. Isolation begrenzt den Schaden, validiert aber nicht die Ausgabe.
Agent Sandbox ist außerdem noch jung und entwickelt sich schnell (die Änderung des Router-Namespace zwischen Versionen ist ein Beispiel), daher sollten Sie Versionen festschreiben und bei Upgrades erneut testen.
Dasselbe gilt für die Performance. Diese Demo verwendet Dragonball, führt dafür aber keine Benchmarks durch. Messen Sie daher Kaltstart und Pods pro Node mit Ihrer eigenen Workload, bevor Sie eine Plattform darauf auslegen.
Fazit
Von Agenten generierter Code ist nicht vertrauenswürdiger Code, und ein Container mit gemeinsamem Kernel ist dafür keine ausreichend starke Grenze. Kata Containers liefert eine VM-Grenze hinter einer normalen Kubernetes-Schnittstelle, und Agent Sandbox ergänzt den Lebenszyklus, den Agenten-Workloads benötigen. Auf EKS wird daraus mit einer Bare-Metal-Nodegroup in etwa 35 Minuten ein reproduzierbares Setup.
Das Muster, das ich unabhängig vom Tooling beibehalten würde: Das Modell entscheidet auf der vertrauenswürdigen Seite, und nur die Sandbox führt aus – mit nichts darin, das sich zu stehlen lohnt, und ohne Weg nach draußen.
Teilen