Egress-locked Managed Agent worker
Run a self-hosted Claude Managed Agent whose tool calls execute inside a sandbox that can reach your private services but cannot exfiltrate to the public internet. Anthropic keeps the agent orchestration; you own the execution boundary — its filesystem, its network, and its logs.
This is the security posture every self-hosted-sandbox integration leads with. The CreateOS piece that makes it enforceable is the per-sandbox egress allowlist: rules are applied in-kernel on the host and cannot be bypassed from inside the sandbox.
Full source:
examples/49-egress-locked-agent-worker. For the same worker without the egress lock, see examples 36 and 37 in the Examples index.
Prerequisites
- Managed Agents beta access on your Anthropic organization.
- A self-hosted environment and its environment key (prefix
sk-ant-oat01-…). The environment key is generated in the Anthropic Console — there is no API for it — and is the only Anthropic credential that enters the sandbox. Your organization key stays on the host. - CreateOS credentials (
CREATEOS_SANDBOX_BASE_URL,CREATEOS_SANDBOX_API_KEY).
The example's README walks through obtaining each value.
The pattern: provision open, then lock
Ordering is the whole trick. The worker CLI has to be fetched from the public internet, so the sandbox starts with open egress; you lock it down only once everything the sandbox legitimately needs is already inside.
Lock egress after installing the worker and starting your internal service, but before the agent session runs any tool call. Rules apply live, in-kernel, with no restart, so there is no window where the tightened policy is not yet in force.
-
Create one persistent sandbox with open egress.
-
Install the
antworker CLI (needs public egress — still open here). -
Start an internal-only service on loopback (
127.0.0.1) — a stand-in for your private API or database, never exposed to the internet. -
Lock egress to a one-host allowlist:
TypeScript1await sandbox.setEgress(["api.anthropic.com"]);From here the sandbox can reach only Anthropic (worker traffic) and loopback (the private service). Every other destination is dropped.
-
Start the worker (
ant beta:worker poll) and bind a Managed Agent session to the self-hosted environment. -
Run the session. The agent's tool call curls the private service (succeeds) and curls a public host (blocked), writing both results to a file.
-
Verify from the host by reading the file back and re-reading the enforced allowlist with
sandbox.getEgress().
What the proof looks like
TEXT1── /workspace/report.txt ──2## private internal service (expect a JSON record):3{"service":"internal-inventory","sku":"ACME-42","stock":128,"note":"reachable only from inside your environment"}4## public internet exfil attempt (expect blocked):5BLOCKED by egress (curl exit 35)6── enforced egress allowlist ── ["api.anthropic.com"]
The private record came back; the public host was dropped. Note that DNS still
resolves under the lock — only the connection is filtered — so a blocked
destination fails as a silent connection error (curl exit 35), not a
name-resolution error.
Egress rule forms
setEgress takes an array of allowlist rules. There is no denylist token: to
block one destination you list every destination you do want.
| Form | Example | Effect |
|---|---|---|
host | api.anthropic.com | Allow all ports to that host. |
host:port | github.com:443 | Allow only that port. |
*.host | *.internal.example | Wildcard subdomain match. |
cidr | 10.0.0.0/8 | Allow a private range (e.g. an overlay network). |
An empty list, null, or ["*"] allows all outbound traffic. See the
Egress REST reference for the complete
grammar and the GET/PUT endpoints behind getEgress / setEgress.
Related
- Examples index — examples 36 and 37 are the same self-hosted worker without the egress lock.
- Egress — the allowlist API in full.
- Run on your own infrastructure — for moving the sandboxes themselves onto your own hardware.