Skip to main content
Configure a sandbox’s network stack: a first-match-wins egress/ingress policy, published ports, DNS interception, TLS interception, and secret-violation handling. Pass a Network as the network= kwarg to Sandbox.create(). See Networking for the conceptual overview and TLS Interception for proxy details.

Typical flow

from microsandbox import (
    Action,
    DestGroup,
    Destination,
    Network,
    NetworkPolicy,
    PortBinding,
    Protocol,
    Rule,
    Sandbox,
)

policy = NetworkPolicy(                             # 1. compose a policy
    default_egress=Action.DENY,
    rules=(
        *Rule.allow_dns(),
        Rule.allow(
            protocol=Protocol.TCP,
            port=443,
            destination=Destination.group(DestGroup.PUBLIC),
        ),
    ),
)

sb = await Sandbox.create(                          # 2. wire it into the sandbox
    "api",
    image="python",
    network=Network(
        policy=policy,
        ports=(PortBinding.tcp(8080, 80),),
    ),
)
The default policy denies egress except for an implicit allow-public rule, and allows ingress with no rules. See the defaults rationale for the asymmetry. Network, Rule, Destination, and PortBinding are all frozen dataclasses re-exported from microsandbox, each carrying class-method or static-method constructors for the common cases.

Network factory

Network is a frozen dataclass. The presets below return a Network for the common policy shapes; construct one directly for custom policies, ports, DNS, or TLS.

Network.none()

@classmethod
def none() -> Network
sb = await Sandbox.create("offline", image="python", network=Network.none())
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

Fully airgapped network configuration.

Network.public_only()

@classmethod
def public_only() -> Network
Block private address ranges and cloud metadata endpoints. Allow everything else. This is the default policy.

Returns

Public-only network configuration.

Network.allow_all()

@classmethod
def allow_all() -> Network
Unrestricted network access, including to private addresses and the host machine.

Returns

Unrestricted network configuration.

Rule factory

A NetworkPolicy is an ordered list of Rule values plus two per-direction defaults, evaluated first-match-wins per direction. The class methods below build rules; assemble them into NetworkPolicy(rules=(...)) and pass it as Network(policy=...).
from microsandbox import Action, Destination, NetworkPolicy, Protocol, Rule

policy = NetworkPolicy(
    default_egress=Action.DENY,
    default_ingress=Action.ALLOW,
    rules=(
        Rule.allow(protocol=Protocol.TCP, port=443, destination=Destination.ip("1.1.1.1")),
        Rule.deny(destination=Destination.domain("api.example.com")),
    ),
)

Rule order matters

The first matching rule wins, so a broad rule placed before a narrow one swallows it:
policy = NetworkPolicy(
    default_egress=Action.DENY,
    default_ingress=Action.ALLOW,
    rules=(
        Rule.allow(destination="10.0.0.0/8"),     # matches everything in 10.x
        Rule.deny(destination="10.0.0.5"),        # never reached
    ),
)
Put specific rules before general ones.

Rule.allow()

@classmethod
def allow(
    *,
    direction: Direction = Direction.EGRESS,
    protocol: Protocol | None = None,
    port: int | str | None = None,
    destination: str | NetworkDestination | None = None,
) -> Rule
from microsandbox import Destination, Protocol, Rule

r = Rule.allow(protocol=Protocol.TCP, port=443, destination=Destination.domain("api.example.com"))
Create a rule that permits matching traffic. All filters are keyword-only.

Parameters

directionDirection
Which evaluator considers the rule. Defaults to EGRESS.
Protocol filter.
portint | str | None
Single port (443) or range (“8000-9000”).
Target filter. Prefer the typed Destination helpers; string shorthand is also accepted.

Returns

An allow rule.

Rule.deny()

@classmethod
def deny(
    *,
    direction: Direction = Direction.EGRESS,
    protocol: Protocol | None = None,
    port: int | str | None = None,
    destination: str | NetworkDestination | None = None,
) -> Rule
Create a rule that blocks matching traffic. Same keyword-only filters as allow().

Parameters

directionDirection
Which evaluator considers the rule. Defaults to EGRESS.
Protocol filter.
portint | str | None
Single port or port range.
Target filter.

Returns

A deny rule.

Rule.allow_dns()

@classmethod
def allow_dns() -> tuple[Rule, Rule]
from microsandbox import Action, DestGroup, Destination, NetworkPolicy, Protocol, Rule

policy = NetworkPolicy(
    default_egress=Action.DENY,
    rules=(
        *Rule.allow_dns(),
        Rule.allow(
            protocol=Protocol.TCP,
            port=443,
            destination=Destination.group(DestGroup.PUBLIC),
        ),
    ),
)
Allow plain DNS (UDP/53 and TCP/53) to the sandbox gateway, i.e. the in-process DNS forwarder. The standard one-liner for opening DNS under a deny-by-default policy. See DNS as egress for the underlying semantics. Returns the pair (udp_rule, tcp_rule) since this SDK’s Rule shape carries a single protocol; splat into NetworkPolicy.rules. DoT (TCP/853) is intentionally not included; add an explicit Rule.allow(destination=Destination.group(DestGroup.HOST), protocol=Protocol.TCP, port=853) if needed (and pair with TLS interception).

Returns

(udp_rule, tcp_rule) for DestGroup.HOST on port 53.

Destination factory

Factory namespace for typed network policy destinations. Typed destinations avoid string-shorthand ambiguity and match the TypeScript SDK shape. Each method returns a NetworkDestination.
from microsandbox import DestGroup, Destination

Destination.any()
Destination.ip("1.1.1.1")
Destination.cidr("10.0.0.0/8")
Destination.domain("api.example.com")
Destination.domain_suffix(".example.com")
Destination.group(DestGroup.LINK_LOCAL)
Bare IP strings such as "1.1.1.1" remain supported on Rule destinations and are parsed like Destination.ip("1.1.1.1"). Prefer the typed helper when the value is known to be an IP.

Destination.any()

@staticmethod
def any() -> NetworkDestination
Match any destination.

Destination.ip()

@staticmethod
def ip(ip: str) -> NetworkDestination
Match an exact IPv4 or IPv6 address. Stored as /32 for IPv4 or /128 for IPv6.

Parameters

ipstr
IPv4 or IPv6 address.

Destination.cidr()

@staticmethod
def cidr(cidr: str) -> NetworkDestination
Match a CIDR range.

Parameters

cidrstr
CIDR notation, e.g. “10.0.0.0/8”.

Destination.domain()

@staticmethod
def domain(domain: str) -> NetworkDestination
Match an exact domain. Domain strings are validated at sandbox creation; invalid names raise ValueError.

Parameters

domainstr
Fully qualified domain name.

Destination.domain_suffix()

@staticmethod
def domain_suffix(suffix: str) -> NetworkDestination
Match the apex domain and all subdomains.

Parameters

suffixstr
Domain suffix, e.g. “.example.com”.

Destination.group()

@staticmethod
def group(group: DestGroup | str) -> NetworkDestination
Match a well-known DestGroup address group.

Parameters

Group keyword.

PortBinding factory

PortBinding is a frozen dataclass for published ports that need an explicit host bind address or UDP. Prefer the protocol-specific constructors over building one by hand.
PortBinding.tcp(8001, 8001, bind="0.0.0.0")
PortBinding.udp(5353, 5353, bind="0.0.0.0")
Pass them to Network(ports=(...)). A plain dict[int, int] is also accepted for the common case, binding TCP to 127.0.0.1.

PortBinding.tcp()

@classmethod
def tcp(cls, host_port: int, guest_port: int, *, bind: str = "127.0.0.1") -> PortBinding
Publish a TCP port from the sandbox to the host.

Parameters

host_portint
Port on the host.
guest_portint
Port inside the sandbox.
bindstr
Host bind address. Defaults to 127.0.0.1; use 0.0.0.0 for all IPv4 interfaces.

Returns

A TCP port binding.

PortBinding.udp()

@classmethod
def udp(cls, host_port: int, guest_port: int, *, bind: str = "127.0.0.1") -> PortBinding
Publish a UDP port from the sandbox to the host.

Parameters

host_portint
Port on the host.
guest_portint
Port inside the sandbox.
bindstr
Host bind address. Defaults to 127.0.0.1.

Returns

A UDP port binding.

Types

Network

Used by Sandbox.create(network=…)

Frozen dataclass for sandbox network configuration. Use a class-method preset for the common cases, or construct directly with custom options.
Network(
    policy: str | NetworkPolicy | None = None,
    ports: Mapping[int, int] | Sequence[PortBinding] = {},
    deny_domains: tuple[str, ...] = (),
    deny_domain_suffixes: tuple[str, ...] = (),
    dns: DnsConfig | None = None,
    tls: TlsConfig | None = None,
    ipv4_pool: str | None = None,
    ipv6_pool: str | None = None,
    max_connections: int | None = None,
    on_secret_violation: ViolationAction | ViolationPolicy = ViolationAction.BLOCK_AND_LOG,
)
FieldTypeDefaultDescription
policystr | NetworkPolicy | NoneNonePreset name ("none", "public_only", "allow_all") or a custom NetworkPolicy
portsMapping[int, int] | Sequence[PortBinding]{}Port mappings from host to guest. Mapping form binds TCP to 127.0.0.1; PortBinding can set an explicit bind address or UDP
deny_domainstuple[str, ...]()Deny egress to these exact domains. Each entry adds a deny Domain("...") policy rule that fires at DNS resolution (NXDOMAIN), TLS first-flight (SNI), and TCP egress (cache fallback). Prepended onto the policy so it takes precedence over later allow rules
deny_domain_suffixestuple[str, ...]()Deny egress to all subdomains of these suffixes. Adds deny DomainSuffix("...") rules; same enforcement layers as deny_domains
dnsDnsConfig | NoneNoneDNS interception configuration
tlsTlsConfig | NoneNoneTLS interception configuration
ipv4_poolstr | NoneNoneIPv4 pool used for per-sandbox /30 guest subnets. Defaults to 172.16.0.0/12
ipv6_poolstr | NoneNoneIPv6 pool used for per-sandbox /64 guest prefixes. Defaults to fd42:6d73:62::/48
max_connectionsint | NoneNoneMaximum concurrent connections
on_secret_violationViolationAction|ViolationPolicyBLOCK_AND_LOGSandbox-wide action when a secret placeholder reaches a disallowed host
Class methodReturnsDescription
none()NetworkDeny all traffic, no interface
public_only()NetworkPublic destinations only (default)
allow_all()NetworkUnrestricted access

NetworkPolicy

Used by Network(policy=…)

Frozen dataclass: an ordered list of Rule values plus two per-direction defaults, evaluated first-match-wins. The defaults are asymmetric to preserve today’s behavior: egress falls through to deny (public_only reachability when paired with the implicit allow-public rule); ingress falls through to allow (unfiltered published-port behavior).
NetworkPolicy(
    default_egress: Action = Action.DENY,
    default_ingress: Action = Action.ALLOW,
    rules: tuple[Rule, ...] = (),
)
FieldTypeDefaultDescription
default_egressActionDENYAction when no egress-applicable rule matches
default_ingressActionALLOWAction when no ingress-applicable rule matches
rulestuple[Rule, ...]()Rules evaluated first-match-wins per direction

Rule

Used by NetworkPolicy(rules=…)

Frozen dataclass for a single network policy rule. Prefer the Rule.allow() / Rule.deny() class methods over the positional constructor.
Rule(
    action: Action,
    direction: Direction = Direction.EGRESS,
    destination: str | NetworkDestination | None = None,
    protocol: Protocol | None = None,
    port: int | str | None = None,
)
FieldTypeDefaultDescription
actionAction-What to do when this rule matches
directionDirectionEGRESSWhich evaluator considers this rule. Direction.ANY matches in either direction
destinationstr | NetworkDestination | NoneNoneTarget filter. Prefer typed Destination helpers; string shorthand also works (DestGroup values, exact IPs, domains, CIDR ranges, domain suffixes prefixed with ".", or "*" for any). Domain and suffix strings are validated at sandbox creation; invalid names raise ValueError
protocolProtocol | NoneNoneProtocol filter
portint | str | NoneNoneSingle port (443) or range ("8000-9000")
Ingress rules carrying ICMP protocols are rejected at sandbox creation; the host has no inbound ICMP path. Use Direction.EGRESS for ICMP allow/deny.
Class methodReturnsDescription
allow(…)RulePermit matching traffic
deny(…)RuleBlock matching traffic
allow_dns()tuple[Rule, Rule]Open plain DNS to the gateway

Destination

Returns NetworkDestination · used by Rule.allow() / Rule.deny()

Factory namespace (static methods) producing typed NetworkDestination values.
MethodReturnsDescription
any()NetworkDestinationMatch any destination
ip(ip)NetworkDestinationMatch an exact IPv4 or IPv6 address (/32 or /128)
cidr(cidr)NetworkDestinationMatch a CIDR range
domain(domain)NetworkDestinationMatch an exact domain
domain_suffix(suffix)NetworkDestinationMatch the apex domain and all subdomains
group(group)NetworkDestinationMatch a DestGroup value

NetworkDestination

Produced by Destination helpers

Frozen dataclass produced by Destination helpers.
NetworkDestination(
    kind: Literal["any", "ip", "cidr", "domain", "domain_suffix", "group"],
    value: str | None = None,
)
FieldTypeDefaultDescription
kindLiteral["any", "ip", "cidr", "domain", "domain_suffix", "group"]-Destination variant
valuestr | NoneNoneVariant value, omitted for Destination.any()

PortBinding

Used by Network(ports=…)

Frozen dataclass for a published host-to-guest port with an optional host bind address. Prefer the PortBinding.tcp() / PortBinding.udp() class methods.
PortBinding(
    host_port: int,
    guest_port: int,
    bind: str = "127.0.0.1",
    protocol: PortProtocol = PortProtocol.TCP,
)
FieldTypeDefaultDescription
host_portint-Port on the host
guest_portint-Port inside the sandbox
bindstr"127.0.0.1"Host address to bind. Use 0.0.0.0 for all IPv4 interfaces
protocolPortProtocolTCPPublished port protocol
Class methodReturnsDescription
tcp(host_port, guest_port, *, bind)PortBindingA TCP port binding
udp(host_port, guest_port, *, bind)PortBindingA UDP port binding

DnsConfig

Used by Network(dns=…)

Frozen dataclass for DNS interception settings. The value type of Network.dns; import it from microsandbox.types.
DnsConfig(
    rebind_protection: bool = True,
    nameservers: tuple[str, ...] = (),
    query_timeout_ms: int | None = None,
)
FieldTypeDefaultDescription
rebind_protectionboolTrueBlock DNS responses resolving to private IPs
nameserverstuple[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_msint | NoneNonePer-DNS-query timeout in milliseconds. Defaults to 5000

TlsConfig

Used by Network(tls=…)

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,
    upstream_ca_certs: tuple[str, ...] = (),
    scoped_upstream_ca_certs: tuple[ScopedUpstreamCACert, ...] = (),
    scoped_verify_upstream: tuple[ScopedVerifyUpstream, ...] = (),
    ca_cert: str | None = None,
    ca_key: str | None = None,
    ca_cn: str | None = None,
)
FieldTypeDefaultDescription
bypasstuple[str, ...]()Domains to skip interception. Use for domains with certificate pinning
verify_upstreamboolTrueVerify upstream server certificates. Set to False only for self-signed servers
intercepted_portstuple[int, ...](443,)TCP ports where TLS interception is active
block_quicboolFalseBlock QUIC/HTTP3 (UDP) on intercepted ports, forcing TCP/TLS fallback
upstream_ca_certstuple[str, ...]()Paths to additional CA bundles trusted for every upstream host
scoped_upstream_ca_certstuple[ScopedUpstreamCACert, ...]()Host-pattern-scoped CA bundles trusted only for matching upstream hosts
scoped_verify_upstreamtuple[ScopedVerifyUpstream, ...]()Host-pattern-scoped upstream certificate verification overrides
ca_certstr | NoneNonePath to a custom interception CA certificate PEM file
ca_keystr | NoneNonePath to a custom interception CA private key PEM file
ca_cnstr | NoneNoneCommon name for the generated interception CA

ScopedUpstreamCACert

dataclass

Used by TlsConfig(scoped_upstream_ca_certs=…)

A CA bundle trusted only for upstream hosts matching a pattern.
ScopedUpstreamCACert(
    pattern: str,
    path: str,
)
FieldTypeDescription
patternstrExact host or *.suffix wildcard
pathstrCA bundle path trusted for matching upstream hosts

ScopedVerifyUpstream

dataclass

Used by TlsConfig(scoped_verify_upstream=…)

A per-host override for upstream certificate verification.
ScopedVerifyUpstream(
    pattern: str,
    verify: bool,
)
FieldTypeDescription
patternstrExact host or *.suffix wildcard
verifyboolWhether to verify certificates for matching upstream hosts

Action

Used by NetworkPolicy · Rule

String enum (StrEnum) for policy actions, so the string values are accepted directly.
ValueDescription
"allow"Permit the traffic
"deny"Drop the traffic silently

Direction

Used by Rule

String enum for traffic direction.
ValueDescription
"egress"Traffic leaving the sandbox
"ingress"Traffic entering the sandbox (via published ports)
"any"Rule applies in either direction

Protocol

Used by Rule

String enum for network protocols in policy rules.
ValueDescription
"tcp"TCP traffic
"udp"UDP traffic
"icmpv4"ICMPv4 traffic
"icmpv6"ICMPv6 traffic

PortProtocol

Used by PortBinding

String enum for port-level protocol selection.
ValueDescription
"tcp"TCP port
"udp"UDP port

DestGroup

Used by Destination.group()

String enum for well-known destination groups used in Destination.group() or string-shorthand Rule.destination.
ValueDescription
"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"