Doku: fremde Laufzeiten und Egress-Proxy - Umsetzung, Befunde, Einrichtung (#712)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d37fe91b37
commit
036d56ff04
@@ -317,6 +317,62 @@ Beispiel: Claude Sonnet, typischer Run (5000 in, 1000 out):
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 5a. Fremde Laufzeit: ein Agent in Claude Code (#712)
|
||||||
|
|
||||||
|
Ein Agent kann statt in unserer Engine in **Claude Code** arbeiten (gedacht für die
|
||||||
|
Entwicklungsabteilung) oder in einem **Befehl**. Er läuft dann in der Sandbox auf einer
|
||||||
|
Kopie seines Arbeitsbereichs. Was er ändert, liegt danach als Vorschlag unter
|
||||||
|
`Agents/Agent-<id>/proposals/<lauf>/` und wird **nicht** übernommen. Taskboard und Kollegen
|
||||||
|
erreicht er nur über den MCP-Server der Instanz. Hintergrund: Organisation-Konzept,
|
||||||
|
Abschnitt 7a.
|
||||||
|
|
||||||
|
**Voraussetzungen (nur Linux):**
|
||||||
|
|
||||||
|
1. `bubblewrap` ist installiert (`apt install bubblewrap`). Die Karte „Laufzeit“ in der
|
||||||
|
Agentenansicht meldet „Die Sandbox ist bereit“. Ohne Sandbox laufen fremde Laufzeiten
|
||||||
|
gar nicht, sie fallen auch nicht auf die native Engine zurück.
|
||||||
|
2. Claude Code ist für den Benutzer installiert, unter dem die Instanz läuft. Mit dem
|
||||||
|
nativen Installer liegt es unter `~/.local/bin/claude` und wird dort gefunden. Bei einer
|
||||||
|
npm-Installation kommen das Programm und Node in `claudeCode.executable` bzw.
|
||||||
|
`claudeCode.readOnlyPaths` der `instance.json`.
|
||||||
|
3. Das Konto (Karte „Laufzeit“ → „Bearbeiten“, gilt für die ganze Instanz):
|
||||||
|
- **API-Schlüssel (Voreinstellung):** am besten ein eigener Schlüssel in einem
|
||||||
|
Anthropic-Workspace mit Ausgabengrenze. Der Schlüssel ist im Lauf für Claude Code
|
||||||
|
lesbar, denn es muss ihn benutzen.
|
||||||
|
- **Abo:** ein Token aus `claude setup-token`, erzeugt auf einem Rechner, an dem du
|
||||||
|
angemeldet bist. Das Abo teilt sein Kontingent mit deiner eigenen Nutzung, und ob es
|
||||||
|
ein Agentensystem betreiben darf, regeln seine Bedingungen.
|
||||||
|
|
||||||
|
**Der Agent** (Karte „Laufzeit“ oder `AgentSettings.json`):
|
||||||
|
|
||||||
|
```json
|
||||||
|
"runtime": {
|
||||||
|
"kind": "claude-code",
|
||||||
|
"allowedTools": ["Read", "Edit", "Write", "Glob", "Grep", "mcp__clawd"],
|
||||||
|
"maxTurns": 30,
|
||||||
|
"timeoutMinutes": 30,
|
||||||
|
"egress": ["pypi.org", "files.pythonhosted.org"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `allowedTools` leer lassen heißt: die obige Voreinstellung. `Bash` erlaubt die Shell
|
||||||
|
**in der Sandbox**. WebFetch und WebSearch sind immer verboten.
|
||||||
|
- `egress` nennt Hosts, die der Lauf zusätzlich zur API erreichen darf. Es gilt nur HTTPS
|
||||||
|
und nur an öffentliche Adressen.
|
||||||
|
- `model` des Agenten wird an Claude Code weitergegeben (`anthropic/claude-sonnet-5` wird
|
||||||
|
zu `claude-sonnet-5`). Ein Modell eines anderen Anbieters wird ignoriert; dann gilt die
|
||||||
|
Voreinstellung von Claude Code.
|
||||||
|
|
||||||
|
Beim Befehl (`"kind": "command"`, dazu `command` und `arguments`) kommt die Nachricht über
|
||||||
|
stdin, und was der Befehl ausgibt, ist das Ergebnis. Den MCP-Server erreicht er mit
|
||||||
|
`$CLAWD_HELPER --mcp-bridge --socket $CLAWD_MCP_SOCKET`; das Token liegt in
|
||||||
|
`$CLAWD_MCP_TOKEN_FILE`.
|
||||||
|
|
||||||
|
**Verbrauch:** Jeder Lauf steht in `RunUsage` mit Laufzeit und Token. Auf dem Abo kostet
|
||||||
|
er 0 $ und ist als Abo-Lauf markiert, verbraucht aber Kontingent.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 6. Kritische Analyse: Ist die Idee umsetzbar?
|
## 6. Kritische Analyse: Ist die Idee umsetzbar?
|
||||||
|
|
||||||
Vor dem Aufbau einer Instanz systematisch prüfen:
|
Vor dem Aufbau einer Instanz systematisch prüfen:
|
||||||
|
|||||||
@@ -828,6 +828,62 @@ verbraucht.
|
|||||||
beide Anmeldewege gebaut, Abo und API-Schlüssel, und die Entscheidung bleibt eine
|
beide Anmeldewege gebaut, Abo und API-Schlüssel, und die Entscheidung bleibt eine
|
||||||
Frage der Konfiguration statt eine des Umbaus.
|
Frage der Konfiguration statt eine des Umbaus.
|
||||||
|
|
||||||
|
### Umsetzung (2026-09-25, #712)
|
||||||
|
|
||||||
|
Gebaut sind `native`, `claude-code` und `command`. `codex` und `http` sind nicht gebaut
|
||||||
|
(„nach Bedarf“); die Einstellung lehnt sie ab, statt sie still als native laufen zu lassen.
|
||||||
|
Ein Agent bekommt seine Laufzeit in der Agentenansicht (Karte „Laufzeit“) oder als
|
||||||
|
`runtime` in `AgentSettings.json`. Das Claude-Code-Konto gilt für die ganze Instanz
|
||||||
|
(`claudeCode` in `instance.json`, Schlüssel verschlüsselt wie der OpenRouter-Schlüssel).
|
||||||
|
|
||||||
|
- **Ohne Sandbox kein Lauf.** Ein fremder Lauf fällt nie auf die native Engine zurück,
|
||||||
|
auch nicht ohne Runner. Deren Modell und Kosten wären nicht die konfigurierten.
|
||||||
|
- **Eigener Arbeitsplatz ist eine Kopie.** Der Lauf arbeitet auf einer Kopie des
|
||||||
|
Arbeitsbereichs, höchstens 20 000 Dateien und 512 MB. Was sich darin ändert, wird zum
|
||||||
|
Vorschlag unter `proposals/<lauf>/`: `proposal.json` und die geänderten Dateien.
|
||||||
|
Übernommen wird nichts; das ist die Sache der Lieferkette (#695). Gelesen werden nur
|
||||||
|
reguläre Dateien. Ein symbolischer Link, den der Lauf hinterlässt, könnte außerhalb der
|
||||||
|
Sandbox auf einen Schlüssel zeigen, eine benannte Pipe würde den Leser für immer
|
||||||
|
blockieren. Beide werden nur als „ignoriert“ genannt.
|
||||||
|
- **Netz nur über den Proxy.** Die Sandbox behält ihr eigenes Netz ohne alles außer
|
||||||
|
Loopback. Claude Code erreicht `api.anthropic.com` über einen HTTPS-Proxy im
|
||||||
|
Hauptprozess, dazu die Hosts, die der Agent einträgt. Der Proxy ist gleich mit gebaut
|
||||||
|
(#655, Security-Konzept 5.2). Updates und Telemetrie von Claude Code sind abgeschaltet.
|
||||||
|
- **Nur unsere Einstellungen gelten.** `--setting-sources user` liest nur die Einstellungen,
|
||||||
|
die vor jedem Lauf ins Home der Laufzeit geschrieben werden, `--strict-mcp-config` nur
|
||||||
|
unseren MCP-Server. Eine `.claude/settings.json` oder `.mcp.json` in der Kopie gewährt
|
||||||
|
also nichts. Hooks sind aus. Was ein Lauf im Home hinterlässt und den nächsten anweisen
|
||||||
|
könnte (Agents, Commands, Skills, `CLAUDE.md`), wird vor dem Start entfernt.
|
||||||
|
Anmeldestand und Verlauf bleiben.
|
||||||
|
- **Freigabelisten:** `--allowedTools` (Voreinstellung: Read, Edit, Write, Glob, Grep und
|
||||||
|
`mcp__clawd`) und `--max-turns`. WebFetch und WebSearch sind immer verboten: Das Web
|
||||||
|
läuft über unsere Werkzeuge, nicht an ihnen vorbei. `--dangerously-skip-permissions`
|
||||||
|
gibt es nicht, auch nicht als Werkzeugname verkleidet.
|
||||||
|
- **Der Rückweg:** Die Anwendung selbst ist in der Sandbox die MCP-Brücke
|
||||||
|
(`--mcp-bridge --socket /run/mcp.sock`). Der MCP-Socket ist eingebunden, das
|
||||||
|
Lauf-Token liegt in einer 0600-Datei und endet mit dem Lauf.
|
||||||
|
- **Schlüssel nie auf der Befehlszeile.** Die Anwendung ist in der Sandbox auch der Starter
|
||||||
|
(`--sandbox-launch`). Er liest den Schlüssel aus einer eingebundenen Datei und setzt ihn
|
||||||
|
in die Umgebung des Programms. Er leitet außerdem den Proxy-Port der Sandbox an den
|
||||||
|
Proxy-Socket weiter.
|
||||||
|
- **Verbrauch:** `RunUsage` hat die Spalten `Runtime` und `OnSubscription`. Ein Lauf auf
|
||||||
|
dem Abo kostet 0 $ und trägt seine Token; mit API-Schlüssel gilt der gemeldete Betrag
|
||||||
|
(`total_cost_usd`). Die Anzeige als Kontingentverbrauch ist Sache von #699.
|
||||||
|
- **Chat:** Eine fremde Laufzeit hat keinen Gesprächsverlauf, der weitergeführt würde. Jede
|
||||||
|
Nachricht ist ein eigener Lauf; der Chat zeigt trotzdem beide Seiten.
|
||||||
|
|
||||||
|
Geprüft unter Linux auf der Test-VM, in der echten Sandbox: Schlüssel stehen in keiner
|
||||||
|
Befehlszeile, ein gelisteter Host ist erreichbar, ein anderer nicht, am Proxy vorbei gibt
|
||||||
|
es kein Netz, der Loopback der Instanz ist nicht der der Sandbox. Ein Programm in der
|
||||||
|
Sandbox erreicht den MCP-Server als sein Agent. Der ganze Claude-Code-Weg ist mit einem
|
||||||
|
Stellvertreter für `claude` geprüft, weil das echte Claude Code auf der Test-VM nicht
|
||||||
|
laufen darf. **Offen:** der Lauf mit dem echten Claude Code und einem echten Schlüssel.
|
||||||
|
Das macht der Mensch einmal von Hand.
|
||||||
|
|
||||||
|
Nicht gebaut: eine Speichergrenze für fremde Laufzeiten. Eine JavaScript-Laufzeit
|
||||||
|
reserviert Adressraum in Gigabyte-Blöcken und startet unter keiner sinnvollen `ulimit -v`.
|
||||||
|
Eine echte Grenze bräuchte cgroups.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8 — Kontrolle: eine Leitung delegiert nicht nur
|
## 8 — Kontrolle: eine Leitung delegiert nicht nur
|
||||||
|
|||||||
@@ -197,6 +197,30 @@ Manifest** (Abschnitt 7), und die Freigabe des Skripts umfasst diese Ziele. Durc
|
|||||||
wird es vom Egress-Proxy: nur die deklarierten Domains, nur HTTPS, jeder Abruf im Audit.
|
wird es vom Egress-Proxy: nur die deklarierten Domains, nur HTTPS, jeder Abruf im Audit.
|
||||||
Ein Skript, das etwas anderes erreichen will, scheitert und erzeugt einen Befund.
|
Ein Skript, das etwas anderes erreichen will, scheitert und erzeugt einen Befund.
|
||||||
|
|
||||||
|
*Der Egress-Proxy ist gebaut (2026-09-25, mit #712), die Anbindung an Skript-Manifeste
|
||||||
|
noch nicht (#655, #695).* So umgesetzt:
|
||||||
|
|
||||||
|
- **Die Sandbox teilt nie das Netz des Hosts.** Mit geteiltem Netz sähe sie alles, was der
|
||||||
|
Host auf Loopback anbietet, darunter den Port der Weboberfläche und eine Datenbank. Sie
|
||||||
|
sähe außerdem abstrakte Unix-Sockets wie ein X11-Display, denn die gehören zum
|
||||||
|
Netz-Namensraum, nicht zum Dateisystem. Die Sandbox behält ihr Netz mit nur Loopback. Ein
|
||||||
|
Starter in der Sandbox (die Anwendung mit `--sandbox-launch`) lauscht dort auf
|
||||||
|
`127.0.0.1:3128` und reicht jede Verbindung an einen Unix-Socket weiter. Der Socket ist
|
||||||
|
eingebunden, dahinter steht der Proxy im Hauptprozess.
|
||||||
|
- **Nur `CONNECT host:port`**, also ein TLS-Tunnel. Klartext-HTTP wird abgewiesen. Der Host
|
||||||
|
muss auf der Liste stehen (`host`, `host:port`, `*.domain` nur für Subdomains).
|
||||||
|
Adressliterale stehen nie auf der Liste.
|
||||||
|
- **Namen löst der Proxy auf, nicht die Sandbox.** Löst ein gelisteter Name auch nur
|
||||||
|
teilweise auf eine nicht-öffentliche Adresse auf, wird er ganz abgewiesen. Das betrifft
|
||||||
|
Loopback, private Netze, CGNAT, Link-Local (Metadaten-Dienste), Multicast und
|
||||||
|
IPv6-Hüllen wie 6to4 und NAT64. So kommt kein DNS-Rebinding auf die Instanz.
|
||||||
|
- Jede Verbindung und jede Abweisung steht im Log. Im Audit steht sie noch nicht, das kommt
|
||||||
|
mit den Manifesten.
|
||||||
|
|
||||||
|
Geprüft unter Linux in der echten Sandbox (`SandboxLaunchTests`): Ein gelisteter Host
|
||||||
|
antwortet, ein anderer bekommt 403, `--noproxy` findet kein Netz, und ein Dienst auf dem
|
||||||
|
Loopback des Hosts ist nicht erreichbar.
|
||||||
|
|
||||||
## 6 — Befunde und Quarantäne
|
## 6 — Befunde und Quarantäne
|
||||||
|
|
||||||
### 6.1 Zwei Stufen
|
### 6.1 Zwei Stufen
|
||||||
|
|||||||
Reference in New Issue
Block a user