docs/sdk/python/networking.mdx
See Networking for conceptual overview and TLS Interception for TLS proxy details.
Frozen dataclass for sandbox network configuration. Use the class method presets for common cases, or construct directly with custom options.
Network(
policy: str | NetworkPolicy | None = None,
ports: Mapping[int, int] = {},
deny_domains: tuple[str, ...] = (),
deny_domain_suffixes: tuple[str, ...] = (),
dns: DnsConfig | None = None,
tls: TlsConfig | None = None,
max_connections: int | None = None,
trust_host_cas: bool | None = None,
)
| Field | Type | Default | Description |
|---|---|---|---|
| policy | str | NetworkPolicy | None | None | Preset name or custom NetworkPolicy |
| ports | Mapping[int, int] | {} | Port mappings from host to guest |
| deny_domains | tuple[str, ...] | () | Deny egress to these exact domains. Each entry adds a deny Domain("...") policy rule that fires at DNS resolution (REFUSED), TLS first-flight (SNI), and TCP egress (cache fallback). Prepended onto the policy so it takes precedence over later allow rules |
| deny_domain_suffixes | tuple[str, ...] | () | Deny egress to all subdomains of these suffixes. Adds deny DomainSuffix("...") rules; same enforcement layers as deny_domains |
| dns | DnsConfig | None | None | DNS interception configuration |
| tls | TlsConfig | None | None | TLS interception configuration |
| max_connections | int | None | None | Maximum concurrent connections |
| trust_host_cas | bool | None | False | Ship the host's trusted root CAs into the guest at boot so outbound TLS works behind corporate MITM proxies (Warp Zero Trust, Zscaler, etc.). Opt-in |
Frozen dataclass for DNS interception settings.
DnsConfig(
rebind_protection: bool = True,
nameservers: tuple[str, ...] = (),
query_timeout_ms: int | None = None,
)
| Field | Type | Default | Description |
|---|---|---|---|
| rebind_protection | bool | True | Block DNS responses resolving to private IPs |
| nameservers | tuple[str, ...] | () | Nameservers (IP, IP:PORT, HOST, or HOST:PORT). Overrides the host's /etc/resolv.conf when set. Hostnames are resolved once at startup via the host's OS resolver |
| query_timeout_ms | int | None | None | Per-DNS-query timeout in milliseconds (default: 5000) |
@classmethod
def none() -> Network
Deny all traffic. No network interface is created -- the guest is fully offline. exec and fs still work since they use the host-guest channel, not the network.
Returns
| Type | Description |
|---|---|
Network | Fully airgapped network configuration |
@classmethod
def public_only() -> Network
Block private address ranges and cloud metadata endpoints. Allow everything else. This is the default policy.
Returns
| Type | Description |
|---|---|
Network | Public-only network configuration |
@classmethod
def allow_all() -> Network
Unrestricted network access, including to private addresses and the host machine.
Returns
| Type | Description |
|---|---|
Network | Unrestricted network configuration |
Frozen dataclass for a custom network policy. Two per-direction defaults plus an ordered list of rules evaluated first-match-wins per direction.
NetworkPolicy(
default_egress: Action = Action.DENY,
default_ingress: Action = Action.ALLOW,
rules: tuple[Rule, ...] = (),
)
| Field | Type | Default | Description |
|---|---|---|---|
| default_egress | Action | Action.DENY | Action when no egress-applicable rule matches |
| default_ingress | Action | Action.ALLOW | Action when no ingress-applicable rule matches |
| rules | tuple[Rule, ...] | () | Rules evaluated first-match-wins per direction |
The defaults are asymmetric to preserve today's behavior: egress falls through to deny (today's public_only reachability when paired with the implicit allow public rule), ingress falls through to allow (today's unfiltered published-port behavior). See the defaults rationale.
Frozen dataclass for a single network policy rule.
Rule(
action: Action,
direction: Direction = Direction.EGRESS,
destination: str | None = None,
protocol: Protocol | None = None,
port: int | str | None = None,
)
| Field | Type | Default | Description |
|---|---|---|---|
| action | Action | - | What to do when this rule matches |
| direction | Direction | Direction.EGRESS | Which evaluator considers this rule. Direction.ANY matches in either direction |
| destination | str | None | None | Target filter: a DestGroup value, domain, CIDR range, domain suffix (prefixed with "."), or "*" for any. Domain and suffix strings are validated at sandbox creation; invalid names raise ValueError. |
| protocol | Protocol | None | None | Protocol filter |
| port | int | str | None | None | Single port (443) or range ("8000-9000") |
Ingress rules carrying ICMP protocols are rejected at sandbox creation: publisher.rs has no inbound ICMP path, so the rule would be dead code. Use Direction.EGRESS for ICMP allow/deny.
@classmethod
def allow(
*,
direction: Direction = Direction.EGRESS,
protocol: Protocol | None = None,
port: int | str | None = None,
destination: str | None = None,
) -> Rule
Create a rule that permits matching traffic.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| direction | Direction | Direction.EGRESS | Traffic direction |
| protocol | Protocol | None | None | Protocol filter |
| port | int | str | None | None | Port or port range |
| destination | str | None | None | Destination filter |
Returns
| Type | Description |
|---|---|
Rule | An allow rule |
@classmethod
def deny(
*,
direction: Direction = Direction.EGRESS,
protocol: Protocol | None = None,
port: int | str | None = None,
destination: str | None = None,
) -> Rule
Create a rule that blocks matching traffic.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| direction | Direction | Direction.EGRESS | Traffic direction |
| protocol | Protocol | None | None | Protocol filter |
| port | int | str | None | None | Port or port range |
| destination | str | None | None | Destination filter |
Returns
| Type | Description |
|---|---|
Rule | A deny rule |
Frozen dataclass for TLS interception settings within Network.
TlsConfig(
bypass: tuple[str, ...] = (),
verify_upstream: bool = True,
intercepted_ports: tuple[int, ...] = (443,),
block_quic: bool = False,
ca_cert: str | None = None,
ca_key: str | None = None,
ca_cn: str | None = None,
)
| Field | Type | Default | Description |
|---|---|---|---|
| bypass | tuple[str, ...] | () | Domains to skip interception. Use for domains with certificate pinning. |
| verify_upstream | bool | True | Verify upstream server certificates. Set to False only for self-signed servers. |
| intercepted_ports | tuple[int, ...] | (443,) | TCP ports where TLS interception is active |
| block_quic | bool | False | Block QUIC/HTTP3 (UDP) on intercepted ports, forcing TCP/TLS fallback |
| ca_cert | str | None | None | Path to a custom interception CA certificate PEM file |
| ca_key | str | None | None | Path to a custom interception CA private key PEM file |
| ca_cn | str | None | None | Common name for the generated interception CA |
String enum (StrEnum) for policy actions.
| Value | Description |
|---|---|
"allow" | Permit the traffic |
"deny" | Drop the traffic silently |
String enum for traffic direction.
| Value | Description |
|---|---|
"egress" | Traffic leaving the sandbox |
"ingress" | Traffic entering the sandbox (via published ports) |
"any" | Rule applies in either direction |
String enum for network protocols in policy rules.
| Value | Description |
|---|---|
"tcp" | TCP traffic |
"udp" | UDP traffic |
"icmpv4" | ICMPv4 traffic |
"icmpv6" | ICMPv6 traffic |
String enum for port-level protocol selection.
| Value | Description |
|---|---|
"tcp" | TCP port |
"udp" | UDP port |
String enum for well-known destination groups used in Rule.destination.
| Value | Description |
|---|---|
"public" | Complement of the named categories — every address not in any other group |
"private" | Private/RFC 1918 addresses + ULA + CGN (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 100.64.0.0/10, fc00::/7) |
"loopback" | Loopback addresses (127.0.0.0/8, ::1) — the guest's own loopback, not the host. See the loopback-vs-host watch-out |
"link-local" | Link-local addresses (169.254.0.0/16, fe80::/10) excluding metadata |
"metadata" | Cloud metadata endpoints (169.254.169.254) |
"multicast" | Multicast addresses (224.0.0.0/4, ff00::/8) |
"host" | The host machine, reached via host.microsandbox.internal. This is the right group for "let the sandbox reach my host's localhost" — not "loopback" |