Skip to content

AI-1667: proxy broker uses Daytona's IP allow list - #1122

Merged
kanat merged 5 commits into
acceleratefrom
connectors/sandbox-proxy-cidr
Oct 22, 2026
Merged

kanat merged 5 commits into
acceleratefrom
connectors/sandbox-proxy-cidr

Conversation

@kanat

@kanat kanat commented Oct 22, 2026 •

Copy link
Copy Markdown

Linear: AI-1667 (parent AI-1572)

Why

With code_sandbox.broker: proxy, a sandbox call to a granted host (GitHub) fails on staging. Daytona's domain allow list brings in its netleash, which ends TLS itself and refuses the proxy's certificate for a granted host: 502 in the sandbox, tls: bad certificate in the router log (staging E2E, 2026-10-22 00:29Z). A live probe (2026-10-22 01:02–01:08Z) shows that Daytona's network allow list alone (<ip>/32) limits all TCP and UDP to that address, passes TLS as it is (real certificates), and injects no proxy or CA env. Daytona refuses a domain list and a network list together (400 mutually exclusive). So the sandbox now reaches our proxy by its IP and nothing else.

How it works

sequenceDiagram
    participant Router as Router (session, run_code)
    participant Daytona as Daytona API
    participant Sandbox as Sandbox code
    participant Proxy as Router egress proxy (IPv4:8091)
    participant GitHub as api.github.com
    Router->>Daytona: create sandbox, NetworkAllowList = proxy IP/32, no DomainAllowList, no OutboundProxyUrl
    Router->>Daytona: every command and CodeRun with env HTTPS_PROXY = http://sbx:credential@IP:8091 and the CA vars
    Sandbox->>Proxy: CONNECT api.github.com:443 with Proxy-Authorization (no DNS in the sandbox)
    Proxy->>Proxy: record by credential, grant check
    Proxy-->>Sandbox: TLS with a certificate from the router CA
    Sandbox->>Proxy: GET /user, Authorization Bearer va_ph_...
    Proxy->>GitHub: GET /user, Authorization Bearer token (resolved now)
    GitHub-->>Proxy: 200
    Proxy-->>Sandbox: 200, token turned back into the placeholder
    Sandbox->>Proxy: CONNECT pypi.org:443 (allowed domain)
    Proxy->>Sandbox: blind tunnel, no token (unchanged from #1113)
Loading
Before (#1113) After
Daytona create DomainAllowList = grants' hosts + allowed domains, OutboundProxyUrl = proxy with credential NetworkAllowList = <proxy IPv4>/32, nothing else
Who holds the proxy credential netleash every command and run's env (HTTPS_PROXY etc.)
CA bundle netleash ca.crt, else image roots image roots (Debian 13: /etc/ssl/certs/ca-certificates.crt) + router CA
proxy_public_url http://host:port http://<public IPv4>:port; host name, IPv6, a non-public address, a bad port or a path/query/fragment stops the router at start
broker: daytona unchanged (control test, probe of base 4588e62)

Rule → test

Rule Code Test
Behind the proxy, Daytona gets NetworkAllowList = proxy /32, no domain list, no OutboundProxyUrl, no NetworkBlockAll daytona.go params, domains daytona.TestProxySuite/TestTheSandboxReachesTheProxyAlone, TestAGrantTheBrokerLeavesOutHasNoEnvVar; the config's network_allow_list (10.0.0.0/8) is dropped behind the proxy (case in the first test); session.TestSandboxGrantsSuite/TestTheProxyBrokerSendsTheSandboxThroughTheProxy
Every run and command gets HTTPS_PROXY/HTTP_PROXY/lower case = proxy with credential, NO_PROXY/no_proxy = loopback egress/broker.go Prepare egress.TestBrokerSuite/TestEveryRunGoesThroughTheProxyAndTrustsTheCA; every proxy test builds its client from RunEnv["HTTPS_PROXY"]
Bundle from the image's roots; netleash ca.crt never trusted egress/broker.go bundle egress.TestBrokerSuite/TestTheBundleHoldsTheSandboxsRootsAndTheCA
proxy_public_url is http://<public IPv4>:port: no host name, IPv6, IPv4-mapped IPv6, 0.0.0.0, loopback, RFC 1918, link-local (169.254.169.254), broadcast; port 1-65535; no path, query, fragment config.ProxyURL (config.go), used by Validate and egress.NewBroker config.TestConfigSuite/TestTheProxyBrokersProxyIsAnIPv4Address, TestTheProxyBrokerNeedsTheProxysURLAndCA; egress.TestBrokerSuite/TestAProxyURLItCannotUseIsRefused
broker: daytona sends Daytona what it did before unchanged daytona.TestSecretsSuite/TestDaytonasBrokerSendsDaytonaWhatItDidBefore (extended: {}, network: true, network_allow_list, expected bodies from base 4588e62)

Each rule was mutation-checked (20 mutations, all killed).

Known limits

  • The sandbox's proxy credential is in the env of every command and run, so sandbox code can read it and send it to a granted host or an allowed domain. It is a proxy credential, never a token: per sandbox, with a TTL, and it reaches only the sandbox's grants and allowed domains (accepted by Kanat, 2026-10-22). Daytona is no longer given it at create.
  • The sandbox has no DNS. A client that ignores the proxy env vars (a raw socket, a DNS lookup) reaches nothing.
  • Unverified until the staging E2E after merge: that per-run HTTPS_PROXY reaches our proxy in a network-list-only sandbox end to end, and that GitHub then answers 200. Root changing routes to get around the network list: unverified.

Docs: acceleration/internal/sandbox/egress/AGENTS.md, .claude/skills/connectors/SKILL.md, acceleration/README.md.

🤖 Generated with Claude Code

…ow list (AI-1667)

Under a domain allow list Daytona's netleash ends TLS itself and refuses
the proxy's certificate for a granted host, so GitHub failed on staging.
With broker proxy the sandbox now gets NetworkAllowList = <proxy IP>/32,
no domain list and no OutboundProxyUrl; every run's env names the proxy
with the sandbox's credential. proxy_public_url must be an IPv4 address.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kanat and others added 4 commits October 21, 2026 22:20
…behind the proxy; say what the sandbox still reaches

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@kanat
kanat marked this pull request as ready for review October 22, 2026 03:01
@kanat
kanat merged commit 48e6a18 into accelerate Oct 22, 2026
7 checks passed
@kanat
kanat deleted the connectors/sandbox-proxy-cidr branch October 22, 2026 03:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant