docs/sdk/go/networking.mdx
Configure a sandbox's network stack: a first-match-wins egress/ingress policy, published ports, DNS interception, TLS interception, and secret-violation handling. See Networking for the conceptual overview and TLS Interception for proxy details.
The Go SDK exposes networking as a single NetworkConfig struct passed to WithNetwork. Common shapes come from the NetworkPolicy factory; custom firewalls are built by populating NetworkConfig.Rules directly.
import m "github.com/superradcompany/microsandbox/sdk/go"
// Preset — public internet only
sb, err := m.CreateSandbox(ctx, "worker",
m.WithImage("alpine"),
m.WithNetwork(m.NetworkPolicy.PublicOnly()),
)
// Or a custom first-match-wins firewall
sb, err = m.CreateSandbox(ctx, "ci-runner",
m.WithImage("python:3.12"),
m.WithNetwork(&m.NetworkConfig{
DefaultEgress: m.PolicyActionDeny,
DefaultIngress: m.PolicyActionAllow,
Rules: []m.PolicyRule{
{
Action: m.PolicyActionAllow,
Direction: m.PolicyDirectionEgress,
Destination: "api.example.com",
Protocol: m.PolicyProtocolTCP,
Port: "443",
},
},
}),
)
func WithNetwork(net *NetworkConfig) SandboxOption
Set the network configuration for the sandbox. Pass a preset from the NetworkPolicy factory, or a custom NetworkConfig value with your own rules, DNS, TLS, and port settings.
sb, err := m.CreateSandbox(ctx, "worker",
m.WithImage("alpine"),
m.WithNetwork(m.NetworkPolicy.PublicOnly()),
)
func WithPorts(ports map[uint16]uint16) SandboxOption
Make TCP services running in the sandbox reachable on localhost ports on the host. Each map entry exposes the guest port (value) on the host port (key), bound to 127.0.0.1. Called multiple times, the maps merge.
sb, err := m.CreateSandbox(ctx, "api",
m.WithImage("python:3.12"),
m.WithPorts(map[uint16]uint16{8080: 8080}),
)
func WithPortsUDP(ports map[uint16]uint16) SandboxOption
Make UDP services running in the sandbox reachable on localhost ports on the host. Each map entry exposes the guest port (value) on the host port (key), bound to 127.0.0.1. Called multiple times, the maps merge.
sb, err := m.CreateSandbox(ctx, "dns",
m.WithImage("alpine"),
m.WithPortsUDP(map[uint16]uint16{5353: 53}),
)
func WithPortBindings(bindings ...PortBinding) SandboxOption
Make services running in the sandbox reachable on explicit host addresses and ports. Use this when the default 127.0.0.1 bind is too restrictive, for example to expose a port on 0.0.0.0. Accepts one or more PortBinding values.
sb, err := m.CreateSandbox(ctx, "api",
m.WithImage("python:3.12"),
m.WithPortBindings(
m.PortBinding{Bind: "0.0.0.0", HostPort: 8001, GuestPort: 8001},
m.PortBinding{Bind: "127.0.0.1", HostPort: 5353, GuestPort: 53, Protocol: m.PortProtocolUDP},
),
)
Factory namespace returning common preset *NetworkConfig values. Access through the package-level NetworkPolicy value, for example m.NetworkPolicy.PublicOnly().
func (networkPolicyFactory) PublicOnly() *NetworkConfig
Allow only public internet traffic; RFC-1918 private ranges are blocked. This is the default when no network configuration is supplied.
<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#networkconfig">*NetworkConfig</a></div> <div className="msb-param-desc">Preset config with <code>Policy: "public-only"</code>.</div> </div> </div> <Accordion title="Example">m.WithNetwork(m.NetworkPolicy.PublicOnly())
func (networkPolicyFactory) None() *NetworkConfig
Block all network access. No network interface is created; the guest is fully offline. Exec and FS still work, since they use the host-guest channel rather than the network.
m.WithNetwork(m.NetworkPolicy.None())
func (networkPolicyFactory) AllowAll() *NetworkConfig
Permit all network traffic, including private addresses and the host machine.
<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#networkconfig">*NetworkConfig</a></div> <div className="msb-param-desc">Preset config with <code>Policy: "allow-all"</code>.</div> </div> </div> <Accordion title="Example">m.WithNetwork(m.NetworkPolicy.AllowAll())
func (networkPolicyFactory) NonLocal() *NetworkConfig
Allow public internet plus private/LAN egress; block loopback, link-local, and metadata.
<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><a className="msb-type" href="#networkconfig">*NetworkConfig</a></div> <div className="msb-param-desc">Preset config with <code>Policy: "non-local"</code>.</div> </div> </div> <Accordion title="Example">m.WithNetwork(m.NetworkPolicy.NonLocal())
Build a custom firewall by populating NetworkConfig.Rules. Rules are evaluated first-match-wins per direction; DefaultEgress and DefaultIngress set the fall-through action. A broad rule placed before a narrow one swallows it, so put specific rules first.
sb, err := m.CreateSandbox(ctx, "ci-runner",
m.WithImage("python:3.12"),
m.WithNetwork(&m.NetworkConfig{
DefaultEgress: m.PolicyActionDeny,
DefaultIngress: m.PolicyActionAllow,
Rules: []m.PolicyRule{
{Action: m.PolicyActionDeny, Destination: "10.0.0.5"}, // specific first
{Action: m.PolicyActionAllow, Destination: "10.0.0.0/8"}, // broad fallthrough
{
Action: m.PolicyActionAllow,
Direction: m.PolicyDirectionEgress,
Destination: ".internal",
Protocols: []m.PolicyProtocol{m.PolicyProtocolTCP},
Ports: []string{"8000-9000"},
},
},
}),
)
The full network stack configuration passed via WithNetwork.
| Field | Type | Description |
|---|---|---|
| Policy | NetworkPolicyPreset | Preset name. Mutually exclusive with custom rules for canned configs; set via NetworkPolicy. When set alongside Rules, preset rules come first and custom rules follow |
| Rules | []PolicyRule | Ordered custom rules (first match wins) |
| DefaultEgress | PolicyAction | Fall-through action for outbound when no rule matches. Defaults to "deny" |
| DefaultIngress | PolicyAction | Fall-through action for inbound when no rule matches. Defaults to "allow" |
| DenyDomains | []string | Exact domain names to refuse DNS resolution for |
| DenyDomainSuffixes | []string | Domain suffixes (e.g. .ads) to block, including the apex and any subdomain |
| DNS | *DNSConfig | In-VM DNS proxy settings |
| DNSRebindProtection | *bool | Legacy convenience for DNS.RebindProtection. When DNS is also set, the nested value wins |
| TLS | *TLSConfig | Transparent TLS interception proxy settings |
| Ports | map[uint16]uint16 | Host to guest TCP port mappings bound to 127.0.0.1 |
| PortBindings | []PortBinding | Host to guest mappings with explicit bind addresses |
| IPv4Pool | string | Pool used to derive per-sandbox /30 guest subnets. Defaults to 172.16.0.0/12 |
| IPv6Pool | string | Pool used to derive per-sandbox /64 guest prefixes. Defaults to fd42:6d73:62::/48 |
| MaxConnections | *uint | Cap on concurrent network connections from the sandbox |
| OnSecretViolation | ViolationAction | Sandbox-wide action when a secret is sent to a disallowed host. Per-secret overrides via SecretEntry.OnViolation |
| TrustHostCAs | *bool | Ship the host's extra CA bundles into the guest. Opt-in for corporate MITM proxies whose gateway CA is unknown to the guest's stock bundle |
A single firewall rule. Ingress rules carrying ICMP protocols are rejected at sandbox creation, since the host has no inbound ICMP path; use PolicyDirectionEgress for ICMP.
| Field | Type | Description |
|---|---|---|
| Action | PolicyAction | allow or deny |
| Direction | PolicyDirection | Direction this rule considers. PolicyDirectionAny matches in either |
| Destination | string | Target filter: a destination group, domain, domain suffix (prefixed with .), CIDR (10.0.0.0/8), exact IP, or "*" |
| Protocol | PolicyProtocol | Legacy single-protocol field. The empty string means any. Prefer Protocols when matching multiple |
| Protocols | []PolicyProtocol | Protocol set. Empty means any |
| Port | string | Single port ("443") or range ("8000-9000") |
| Ports | []string | Several port values at once |
In-VM DNS proxy configuration.
| Field | Type | Description |
|---|---|---|
| RebindProtection | *bool | Block DNS responses resolving to private IPs. Defaults to true when unset |
| Nameservers | []string | Upstream resolvers (e.g. "1.1.1.1:53"). Replaces /etc/resolv.conf when non-empty |
| QueryTimeoutMs | *uint64 | Per-DNS-query timeout in milliseconds |
Transparent HTTPS inspection proxy configuration.
| Field | Type | Description |
|---|---|---|
| Bypass | []string | Domain patterns (supports *.suffix) to skip MITM. Use for domains with certificate pinning |
| VerifyUpstream | *bool | Verify upstream server certificates. Defaults to true. Set false only for self-signed servers |
| InterceptedPorts | []uint16 | TCP ports where TLS is intercepted. Defaults to [443] |
| BlockQUIC | *bool | Block QUIC on intercepted ports to force TLS fallback |
| CACert | string | Path to a custom interception CA certificate PEM file |
| CAKey | string | Path to a custom interception CA private key PEM file |
| UpstreamCACerts | []string | Paths to additional CA bundles trusted for upstream verification |
sb, err := m.CreateSandbox(ctx, "inspect",
m.WithImage("python:3.12"),
m.WithNetwork(&m.NetworkConfig{
TLS: &m.TLSConfig{
Bypass: []string{"*.googleapis.com"},
InterceptedPorts: []uint16{443},
},
}),
)
A host-to-guest port mapping with an explicit host bind address. Protocol defaults to TCP when empty. Use Bind: "0.0.0.0" to expose the published port on all IPv4 interfaces.
| Field | Type | Description |
|---|---|---|
| Bind | string | Host IP address to bind, such as 127.0.0.1, 0.0.0.0, or :: |
| HostPort | uint16 | Port on the host |
| GuestPort | uint16 | Port inside the sandbox |
| Protocol | PortProtocol | PortProtocolTCP or PortProtocolUDP. Empty defaults to TCP |
Identifies the protocol for an exposed sandbox service.
| Constant | Value | Description |
|---|---|---|
PortProtocolTCP | "tcp" | TCP port mapping |
PortProtocolUDP | "udp" | UDP port mapping |
The action half of a PolicyRule.
| Constant | Value | Description |
|---|---|---|
PolicyActionAllow | "allow" | Permit the traffic |
PolicyActionDeny | "deny" | Drop the traffic silently |
The direction half of a PolicyRule. The Go SDK follows the Python naming (egress/ingress); the wire format carries these values.
| Constant | Value | Description |
|---|---|---|
PolicyDirectionEgress | "egress" | Traffic leaving the sandbox |
PolicyDirectionIngress | "ingress" | Traffic entering the sandbox |
PolicyDirectionAny | "any" | Rule applies in either direction |
The protocol half of a PolicyRule.
| Constant | Value | Description |
|---|---|---|
PolicyProtocolTCP | "tcp" | TCP traffic |
PolicyProtocolUDP | "udp" | UDP traffic |
PolicyProtocolICMPv4 | "icmpv4" | ICMPv4 traffic (egress only) |
PolicyProtocolICMPv6 | "icmpv6" | ICMPv6 traffic (egress only) |
Preset names accepted by NetworkConfig.Policy. Prefer the NetworkPolicy factory, which returns a preconfigured *NetworkConfig.
| Constant | Value | Description |
|---|---|---|
NetworkPolicyPresetNone | "none" | Fully airgapped |
NetworkPolicyPresetPublicOnly | "public-only" | Block private + metadata; allow everything else |
NetworkPolicyPresetAllowAll | "allow-all" | Unrestricted |
NetworkPolicyPresetNonLocal | "non-local" | Public + private/LAN egress; block loopback / link-local / metadata |
The Destination field on PolicyRule accepts these well-known group names alongside literal CIDRs and domains. A domain prefixed with . becomes a suffix match: .example.com matches api.example.com but not example.com.
| Value | Description |
|---|---|
"public" | 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 Reaching the host |
"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. The right group for "let the sandbox reach my host's localhost", not "loopback" |