How CubeSandbox Implements Per-Instance DNS Configuration and Network Isolation

CubeSandbox achieves per-instance DNS configuration and network isolation by combining TAP-based network namespaces, eBPF policy maps, and CoreDNS sidecars that consume the DNSConfig protobuf definitions from the Cubebox API.

CubeSandbox, TencentCloud's container sandbox runtime, provides granular control over DNS resolution and network boundaries for each sandbox instance. Understanding how the platform configures DNS configuration and network isolation per instance requires examining the interplay between the Cubelet API definitions, the network-agent's TAP device management, and the eBPF-based policy enforcement in CubeVS.

Per-Sandbox DNS Configuration via DNSConfig

API Schema and Protobuf Definitions

The foundation of per-instance DNS control lies in the DNSConfig message defined in Cubelet/api/services/cubebox/v1/cubebox.proto and mirrored in CubeMaster/api/services/cubebox/v1/cubebox.proto. This schema includes the dns_config field (containing a list of nameserver IPs) that is copied into the sandbox's network-namespace configuration during creation.

Default Nameservers and Fallback Behavior

When custom DNS servers are not specified, CubeSandbox falls back to the values defined in Cubelet/dynamicconf/conf.yaml. This configuration file provides the guest container default DNS settings, which are overridden when a template specifies dns_config.servers.

SDK and Web Interface Exposures

Both the Python and Go SDKs surface this capability to developers. In the Python SDK (sdk/python/cubesandbox/_template.py), the dns parameter accepts a list of server addresses. The Go SDK (sdk/go/template.go) similarly exposes a DNS field in TemplateOptions. The web interface also exposes these fields in web/src/pages/Templates.tsx and web/src/lib/templateConfig.ts, mapping UI inputs to the same dns_config payload structure.

Network Isolation Architecture

TAP Device Lifecycle and Namespace Isolation

Each sandbox receives a dedicated TAP interface created by the network-agent. The network-agent/internal/service/tap_lifecycle.go file handles the creation, preparation, and pooling of these devices. The TAP is placed inside the sandbox's network namespace, isolating traffic at the interface level. The buildRecoveredState function manages the IP, MAC, and MTU assignment for each TAP device.

eBPF Policy Enforcement for DNS Traffic

CubeVS enforces network policies through eBPF maps that include DNS-specific controls. The dns_allow map stores learned domain names in an inner-trie structure, populated from allow_out rules or L7 host/SNI matches. Per-sandbox policy flags stored in ifindex_to_mvmmeta[].dns_policy_flags and the dns_learning_enabled flag govern DNS behavior for each instance. Additional maps including allow_out_v2 and deny_out hold IP/CIDR allow-lists for broader network policy enforcement. Documentation in docs/zh/guide/network-policy.md details these map structures.

CoreDNS Sidecar Integration

DNS queries from within the sandbox namespace are routed to a host-side CoreDNS instance via the cube-sandbox-dns.service. The network-agent injects the per-instance DNS configuration into the CoreDNS Corefile, ensuring that UDP/TCP port 53 traffic is resolved according to the sandbox-specific upstream servers rather than the host's resolver.

Implementing Custom DNS and Network Policies

The following examples demonstrate how to configure per-instance DNS using the CubeSandbox SDKs.

Python SDK – Creating a sandbox with custom DNS:

from cubesandbox import Template

tpl = Template(
    name="my-app",
    image="registry.cn-beijing.aliyuncs.com/cube/example:latest",
    dns=["8.8.8.8", "1.1.1.1"],          # Per-sandbox DNS

    allow_out=["0.0.0.0/0"],            # Optional network policy

)

sandbox_id = tpl.create()
print(f"Sandbox {sandbox_id} running with DNS {tpl.dns}")

Go SDK – Setting DNS in the low-level request:

opts := cubesandbox.TemplateOptions{
    Image: "docker.io/library/nginx:latest",
    DNS:   []string{"8.8.8.8", "1.1.1.1"},
}
payload := map[string]any{}
payload["dns"] = opts.DNS

Inspecting the generated network state:

state := buildRecoveredState(tap, dev, mappings, cfg)
fmt.Printf("Sandbox %s IP %s DNS %v\n",
    state.persistedState.SandboxID,
    state.persistedState.SandboxIP,
    cfg.DNSConfig.Servers)   // Drawn from the DNSConfig field

Summary

  • CubeSandbox defines per-instance DNS through the DNSConfig protobuf field in cubebox.proto, exposed via REST and SDKs.
  • Network isolation relies on dedicated TAP devices created in tap_lifecycle.go, placed in isolated network namespaces.
  • eBPF maps (dns_allow, ifindex_to_mvmmeta) enforce DNS policies and prevent cross-sandbox leakage.
  • CoreDNS sidecars on the host handle resolution using the instance-specific upstream configuration.

Frequently Asked Questions

Where is the DNS configuration defined in CubeSandbox's API?

The DNS configuration is defined in the DNSConfig message within Cubelet/api/services/cubebox/v1/cubebox.proto and CubeMaster/api/services/cubebox/v1/cubebox.proto. This protobuf definition includes a servers field that accepts a list of IP addresses for upstream DNS resolution.

How does CubeSandbox prevent DNS leakage between sandbox instances?

CubeSandbox isolates DNS traffic through a combination of network namespaces and eBPF policy enforcement. Each sandbox runs in its own network namespace with a dedicated TAP device, while eBPF maps (dns_allow, dns_policy_flags) enforce per-instance domain allow-lists and learning policies that prevent unauthorized DNS resolution across instance boundaries.

What happens if I don't specify custom DNS servers when creating a sandbox?

If no custom DNS servers are provided, CubeSandbox falls back to the default nameservers defined in Cubelet/dynamicconf/conf.yaml. These defaults can be overridden at the template level, but if left unspecified, the system uses the host-configured guest container DNS settings.

Which component is responsible for creating the network interfaces for each sandbox?

The network-agent component, specifically the code in network-agent/internal/service/tap_lifecycle.go, manages the lifecycle of TAP devices. It creates, prepares, and assigns these interfaces to individual sandbox network namespaces, handling IP address allocation and MAC address generation through the buildRecoveredState function.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →