Skip to content
LogoLogo

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. Use the per-sandbox egress allowlist to restrict workload destinations. CreateOS enforces it outside the sandbox. Hostname rules cover HTTP/HTTPS; use IP/CIDR rules for other ports and account for platform networking allowances.

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 without a restart. Allow time for hostname policy updates to propagate, and verify the required access restrictions before starting the agent's work.

  1. Create one persistent sandbox with open egress.

  2. Install the ant worker CLI (needs public egress, still open here).

  3. 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.

  4. Lock egress to a one-host allowlist:

    await 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.

  5. Start the worker (ant beta:worker poll) and bind a Managed Agent session to the self-hosted environment.

  6. 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.

  7. Verify from the host by reading the file back and re-reading the enforced allowlist with sandbox.getEgress().

What the proof looks like

── /workspace/report.txt ──
## private internal service (expect a JSON record):
{"service":"internal-inventory","sku":"ACME-42","stock":128,"note":"reachable only from inside your environment"}
## public internet exfil attempt (expect blocked):
BLOCKED by egress (curl exit 35)
── 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.

FormExampleEffect
hostapi.anthropic.comAllow HTTP/HTTPS on TCP 80 and 443.
host:portgithub.com:443Restrict hostname access to TCP 80 or 443. Use IP/CIDR rules for other ports.
*.host*.internal.exampleWildcard subdomain match.
cidr10.0.0.0/8Allow 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.