How to Configure CubeEgress Domain Allowlists and Egress Security Policies in CubeSandbox
CubeSandbox implements a two-layer egress control system where CubeVS handles L3/L4 CIDR filtering and CubeEgress enforces L7 domain-based rules, requiring explicit deny_out rules when using domain allowlists to pass validation.
TencentCloud/CubeSandbox protects outbound traffic through a sophisticated architecture that separates IP-level filtering from application-layer policy enforcement. Configuring CubeEgress domain allowlists and egress security policies allows you to restrict sandbox environments to specific external APIs while safely injecting credentials and maintaining comprehensive audit trails.
Understanding the Two-Layer Egress Architecture
CubeSandbox employs a dual-layer approach to secure outbound connections:
- Layer 3/4 (CubeVS): An eBPF-based data plane that manages raw IP routing, NAT, and CIDR-based egress filtering through
allow_outanddeny_outlists. - Layer 7 (CubeEgress): An OpenResty/NGINX proxy that intercepts HTTP/HTTPS traffic redirected from CubeVS, applies per-domain or per-path rules, injects credentials, and writes audit logs.
Configuring Domain Allowlists (allow_out)
The allow_out configuration accepts both IPv4 CIDR strings and DNS names (e.g., api.openai.com or *.example.com). When a rule's match contains an SNI, Host, or Scheme referencing a domain, CubeSandbox automatically adds that domain to allow_out, ensuring the underlying eBPF layer permits the traffic.
Validation Requirements
According to the validation logic in sdk/go/policy.go (lines 60-71), domain-based allowlists only validate when paired with a deny-all configuration. The validateAllowOutDomainsRequireDenyAll function enforces that either all other egress is denied (default "deny-all" mode) or 0.0.0.0/0 is explicitly placed in deny_out. If violated, the API returns a 400 error with the message defined in allowOutDomainRequiresDenyAll.
Defining Egress Security Policies (L7 Rules)
L7 rules consist of match conditions and actions defined in sdk/go/policy.go. The Match struct supports optional SNI, Host, Method, Path, and Scheme fields—all fields are AND-ed, while Method accepts multiple values (OR-ed). The Action struct specifies Allow (with optional Inject objects) or explicit denial (Allow: false), plus an optional Audit string for logging labels.
// Match holds rule match conditions.
type Match struct {
SNI string `json:"sni,omitempty"`
Host string `json:"host,omitempty"`
Method []string `json:"method,omitempty"`
Path string `json:"path,omitempty"`
Scheme string `json:"scheme,omitempty"`
}
// Inject injects a credential header on an allowed HTTPS request.
type Inject struct {
Header string `json:"header"`
Secret string `json:"secret"`
Format string `json:"format,omitempty"`
}
// Action is a rule action.
type Action struct {
Allow bool `json:"allow"`
Inject []Inject `json:"inject,omitempty"`
Audit string `json:"audit,omitempty"`
}
// Rule is one L7 egress rule.
type Rule struct {
Name string `json:"name"`
Match Match `json:"match"`
Action Action `json:"action"`
}
When Action.Allow is true, CubeEgress forwards the request and injects any headers defined in Inject. If false, it returns HTTP 403 before the request leaves the cluster.
Policy Propagation Flow
Configuration flows through the system as follows:
- Sandbox creation: The user passes a
networkblock (allow_out,deny_out,rules) via the API or SDK. - CubeMaster: Stores the configuration and pushes it to the network-agent.
- network-agent: Converts the high-level policy into a
cubeegress.PolicyInputpayload and callsPutPolicy. See the implementation innetwork-agent/internal/service/cubeegress_push.go(lines 13-73). - CubeVS: Installs CIDR allow/deny lists. For every DNS query matching a domain in
allow_out, CubeVS learns resolved IPs and adds them to the CIDR list automatically. - CubeEgress: Receives the policy via its admin API, compiles the Lua rule set, and filters HTTP/HTTPS traffic redirected from CubeVS via the TPROXY iptables chain.
Implementation Examples
Go SDK Configuration
import (
"github.com/TencentCloud/CubeSandbox/sdk/go"
)
func createSandbox() (*cubesandbox.Sandbox, error) {
cfg := &cubesandbox.CubeNetworkConfig{
// Allow only the OpenAI API domain; everything else is denied.
AllowOut: []string{"api.openai.com"},
DenyOut: []string{"0.0.0.0/0"}, // required when domains are used
Rules: []cubesandbox.Rule{
{
Name: "OpenAI credential injection",
Match: cubesandbox.Match{
SNI: "api.openai.com",
},
Action: cubesandbox.Action{
Allow: true,
Inject: []cubesandbox.Inject{
{
Header: "Authorization",
Secret: "sk-xxxxxxxxxxxxxxxxxxxx",
// ${SECRET} will be substituted with the secret value.
},
},
Audit: "openai-call",
},
},
},
}
// `Create` also accepts `AllowInternetAccess: false` to start from a deny‑all state.
return client.Sandbox.Create(
cubesandbox.SandboxCreateOpts{
Network: cfg,
AllowInternetAccess: false,
})
}
The validation in policy.go guarantees this call succeeds; if DenyOut is omitted, the API returns a 400 error.
Python SDK Configuration
from cubesandbox import CubeSandbox
cs = CubeSandbox()
sandbox = cs.sandbox.create(
allow_internet_access=False,
network={
"allow_out": ["api.openai.com"],
"deny_out": ["0.0.0.0/0"],
"rules": [
{
"name": "OpenAI credential injection",
"match": {"sni": "api.openai.com"},
"action": {
"allow": True,
"inject": [{"header": "Authorization",
"secret": "sk-xxxxxxxxxxxxxxxxxxxx"}],
"audit": "openai-call"
}
}
],
},
)
Retrieving Active Policies
// Assuming `client` is a configured network‑agent client.
pol, err := client.Egress.GetPolicy(context.Background(), sandboxIP)
if err != nil {
log.Fatalf("failed to fetch policy: %v", err)
}
fmt.Printf("Current CubeEgress policy: %+v\n", pol)
The returned JSON mirrors the policy.go structure and represents the exact payload CubeEgress uses internally.
Safety Checks and Constraints
CubeSandbox enforces strict validation to prevent misconfigurations:
- Domain-only allowlists require deny-all: Enforced by
validateAllowOutDomainsRequireDenyAllto ensure domains are not accidentally whitelisted while other traffic is permitted. - Wildcard restrictions: Only the
*.prefix is allowed (e.g.,*.example.com). TheisDomainAllowOutTargetfunction rejects any other*placement in the string. - Credential isolation: Secrets are stored only in CubeMaster and injected by CubeEgress just before the outbound request leaves the host, never exposing credentials to sandbox code.
Summary
- CubeSandbox uses CubeVS for L3/L4 CIDR filtering and CubeEgress for L7 domain and path-based rules.
- Domain allowlists (
allow_out) require explicitdeny_out: ["0.0.0.0/0"]to pass validation enforced insdk/go/policy.go. - L7 rules support matching on
SNI,Host,Method,Path, andScheme, with actions for allowing, denying, or injecting credentials via theInjectstruct. - Policies propagate from the SDK through CubeMaster to the network-agent, which pushes them to CubeEgress via the admin API defined in
network-agent/internal/service/cubeegress_push.go. - Wildcard domains must use the
*.prefix format, and credential injection occurs securely at the proxy layer without exposing secrets to sandbox code.
Frequently Asked Questions
What is the difference between CubeVS and CubeEgress?
CubeVS operates at the network layer (L3/L4) using eBPF to filter traffic based on IP CIDRs and manage NAT, while CubeEgress operates at the application layer (L7) as an OpenResty/NGINX proxy that inspects HTTP/HTTPS requests, enforces domain policies, injects headers, and generates audit logs. CubeVS handles the initial allow/deny decisions for IP traffic, while CubeEgress applies fine-grained rules to HTTP-specific attributes like SNI and Host headers.
Why do I need to set deny_out to 0.0.0.0/0 when using domain allowlists?
The validation logic in sdk/go/policy.go (lines 60-71) requires this configuration to prevent security gaps. Domain-based allowlists only make sense in a "deny-all" mode where all other traffic is explicitly blocked. Without 0.0.0.0/0 in deny_out, the API returns a 400 error with the message allowOutDomainRequiresDenyAll, ensuring that domain whitelisting does not accidentally coexist with permissive network access.
How does credential injection work in CubeEgress?
When a request matches a rule with Action.Allow: true and contains Inject objects, CubeEgress adds the specified headers to the outbound request just before it leaves the host. The secret values are stored in CubeMaster and never exposed to the sandbox code; only the proxy performs the injection using the format specified in the Inject struct's Header and Format fields.
Can I use wildcards in domain allowlists?
Yes, but only with the *. prefix format (e.g., *.example.com). The isDomainAllowOutTarget function validates that wildcards appear only at the beginning of the domain string. Any other placement of * in the string is rejected during validation, ensuring that wildcard matching remains predictable and secure.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →