#Egress Auth
Egress auth rules tell Sandbox0 when to apply outbound authentication for matching traffic.
This configuration is carried on the network surface as network.egress.credentialRules, but conceptually it belongs to the credential system:
credentialBindingsdefine what auth material exists.credentialRulesdefine where and when that material is used.trafficRulesstill decide whether the traffic itself is allowed.
Bindings are configured under the same network object everywhere:
- template
spec.network - sandbox claim
config.network - runtime update
PUT /api/v1/sandboxes/{id}/network
Binding Fields#
| Field | Required | Description |
|---|---|---|
ref | Yes | Stable local name matched by credentialRules[*].credentialRef |
sourceRef | Yes | Region-scoped credential source reference to resolve |
projection | Yes | How the source is shaped for runtime injection |
cachePolicy.ttl | No | Optional cache lifetime duration string such as 5m or 1h for resolved material |
Binding Example#
This binding projects a stored token into an Authorization header:
yamlcredentialBindings: - ref: gh-token sourceRef: github-source projection: type: http_headers httpHeaders: headers: - name: Authorization valueTemplate: "Bearer {{token}}"
In this example, {{token}} refers to the token key inside a static_headers source's values map. If the referenced key is missing, header rendering fails.
Rule Fields#
| Field | Required | Description |
|---|---|---|
credentialRef | Yes | Binding reference to resolve |
protocol | No | Supported values: http, https, grpc, tls, ssh, socks5, mqtt, redis |
domains | No | Domain match list |
ports | No | Port/protocol constraints |
httpMatch | No | HTTP request-level matcher for http, https, and grpc rules |
tlsMode | No | passthrough or terminate-reoriginate |
failurePolicy | No | fail-closed or fail-open |
rollout | No | enabled or disabled |
HTTPS Trust Material#
When a credential rule uses TLS interception such as protocol: https, protocol: grpc, or protocol: tls with tlsMode: terminate-reoriginate, Sandbox0 provides the netd MITM CA to sandbox containers and configures procd-managed processes to trust it automatically.
- File:
/var/run/sandbox0/netd/mitm-ca.crt - Env:
SANDBOX0_NETD_MITM_CA_FILE=/var/run/sandbox0/netd/mitm-ca.crt
At procd startup, Sandbox0 writes a combined CA bundle containing the image's system roots plus the netd MITM CA, then exports it through common TLS environment variables such as SSL_CERT_FILE, NODE_EXTRA_CA_CERTS, REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE, GIT_SSL_CAINFO, and AWS_CA_BUNDLE. Applications normally do not need to handle the MITM CA themselves.
Example Policy#
This policy allows access to the GitHub API, binds a token source, and injects an Authorization header for matching HTTPS requests:
yamlmode: block-all egress: trafficRules: - name: allow-github-api action: allow domains: - api.github.com ports: - port: 443 protocol: tcp credentialRules: - name: github-auth credentialRef: gh-token protocol: https domains: - api.github.com ports: - port: 443 protocol: tcp credentialBindings: - ref: gh-token sourceRef: github-source projection: type: http_headers httpHeaders: headers: - name: Authorization valueTemplate: "Bearer {{token}}"
Here, {{token}} is rendered from the token entry stored in the bound static_headers source. Keep the projection template keys aligned with the source contents.
HTTP Request Matching#
Use httpMatch when a credential should only be injected for specific API requests on a broader allowed destination. Non-matching requests still follow trafficRules, but do not resolve or inject the credential.
For protocol: https and protocol: grpc, request matching requires tlsMode: terminate-reoriginate.
When multiple credentialRules match the same destination, Sandbox0 keeps the destination-matching rules as candidates and evaluates their httpMatch blocks in declaration order after the HTTP request is visible. The first rule with a matching httpMatch is selected. A rule without httpMatch matches any remaining request, so place narrower path, header, method, or query rules before catch-all rules.
yamlmode: block-all egress: trafficRules: - name: allow-github-api action: allow domains: - api.github.com ports: - port: 443 protocol: tcp credentialRules: - name: github-write-auth credentialRef: gh-token protocol: https tlsMode: terminate-reoriginate domains: - api.github.com ports: - port: 443 protocol: tcp httpMatch: methods: - POST - PUT - PATCH - DELETE pathPrefixes: - /repos/ headers: - name: accept values: - application/vnd.github+json credentialBindings: - ref: gh-token sourceRef: github-source projection: type: http_headers httpHeaders: headers: - name: Authorization valueTemplate: "Bearer {{token}}"
You can use that ordering to inject different credentials for different paths on the same host:
yamlmode: block-all egress: trafficRules: - name: allow-github action: allow domains: - github.com ports: - port: 443 protocol: tcp credentialRules: - name: github-emu-auth credentialRef: github-emu protocol: https tlsMode: terminate-reoriginate domains: - github.com ports: - port: 443 protocol: tcp httpMatch: pathPrefixes: - /emu-org/ - name: github-cloud-auth credentialRef: github-cloud protocol: https tlsMode: terminate-reoriginate domains: - github.com ports: - port: 443 protocol: tcp httpMatch: pathPrefixes: - /cloud-org/
SSH Transparent Proxy#
SSH egress auth uses a transparent proxy model. The sandbox-side SSH client authenticates to netd with a fake public/private key pair, and netd authenticates to the upstream SSH server with the private key stored in a static_ssh_private_key credential source.
The upstream private key is never written into the sandbox. The sandbox only needs the fake private key that matches projection.sshProxy.sandboxPublicKeys.
yamlmode: block-all egress: trafficRules: - name: allow-git-ssh action: allow domains: - github.com ports: - port: 22 protocol: tcp appProtocols: - ssh credentialRules: - name: git-ssh-auth credentialRef: git-ssh protocol: ssh domains: - github.com ports: - port: 22 protocol: tcp credentialBindings: - ref: git-ssh sourceRef: github-ssh-key projection: type: ssh_proxy sshProxy: upstreamUsername: git sandboxPublicKeys: - ssh-ed25519 AAAA... sandbox-fake-key knownHosts: - github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...
For Git-over-SSH, use the normal Git SSH URL and configure Git or OpenSSH in the sandbox to use the fake private key. Netd terminates the sandbox SSH session, verifies the fake key, verifies the upstream host key against knownHosts, and re-originates the session with the stored upstream private key.
SSH does not carry a hostname in the protocol. When credentialRules[*].domains or hostname-based knownHosts entries are used for SSH, netd associates the SSH connection with the sandbox's recent DNS response for that destination IP. The association is per sandbox and expires with the DNS TTL. Direct IP connections, stale DNS entries, or DNS traffic that bypasses netd are treated as hostless SSH traffic.
Update Runtime Policy#
/api/v1/sandboxes/{id}/network
go_, err = sandbox.UpdateNetworkPolicy(ctx, apispec.SandboxNetworkPolicy{ Mode: apispec.SandboxNetworkPolicyModeBlockAll, Egress: apispec.NewOptNetworkEgressPolicy(apispec.NetworkEgressPolicy{ TrafficRules: []apispec.TrafficRule{ { Name: apispec.NewOptString("allow-github-api"), Action: apispec.TrafficRuleActionAllow, Domains: []string{"api.github.com"}, Ports: []apispec.PortSpec{ { Port: 443, Protocol: apispec.NewOptString("tcp"), }, }, }, }, CredentialRules: []apispec.EgressCredentialRule{ { Name: apispec.NewOptString("github-auth"), CredentialRef: "gh-token", Protocol: apispec.NewOptEgressAuthProtocol(apispec.EgressAuthProtocolHTTPS), Domains: []string{"api.github.com"}, Ports: []apispec.PortSpec{ { Port: 443, Protocol: apispec.NewOptString("tcp"), }, }, FailurePolicy: apispec.NewOptEgressAuthFailurePolicy(apispec.EgressAuthFailurePolicyFailClosed), }, }, }), CredentialBindings: []apispec.CredentialBinding{ { Ref: "gh-token", SourceRef: "github-source", Projection: apispec.ProjectionSpec{ Type: apispec.CredentialProjectionTypeHTTPHeaders, HttpHeaders: apispec.NewOptHTTPHeadersProjection(apispec.HTTPHeadersProjection{ Headers: []apispec.ProjectedHeader{ { Name: "Authorization", ValueTemplate: "Bearer {{token}}", }, }, }), }, }, }, }) if err != nil { log.Fatal(err) }
For supported protocols, auth material is resolved and injected by the egress path. The sandbox process does not need direct access to the raw credential source contents.
Next Steps#
Overview
Define reusable sandbox environments before creating or scaling sandboxes.
Custom Images
Build and reference custom container images for sandbox templates.