Back to Microsandbox

Overview

docs/networking/overview.mdx

0.5.45.1 KB
Original Source

All sandbox traffic flows through a host-controlled networking stack. From inside the VM it looks like a normal network interface; from the host side, every packet is checked against policy before it leaves.

Defaults

By default, sandboxes can reach the public internet but cannot reach private networks, loopback, link-local addresses, or cloud metadata endpoints. Inbound traffic is only reachable through published ports.

To turn networking off entirely:

<CodeGroup> ```rust Rust let sb = Sandbox::builder("isolated") .image("python") .network(|n| n.enabled(false)) .create() .await?; ```
typescript
await using sb = await Sandbox.builder("isolated")
    .image("python")
    .disableNetwork()
    .create();
python
from microsandbox import Network, Sandbox

sb = await Sandbox.create("isolated", image="python", network=Network.none())
go
sb, err := m.CreateSandbox(ctx, "isolated",
    m.WithImage("python"),
    m.WithNetwork(m.NetworkPolicy.None()),
)
bash
msb create python --name isolated --no-net
</CodeGroup>

Custom policies

A policy has two defaults and an ordered list of rules. The first matching rule wins.

text
default_egress  : allow | deny
default_ingress : allow | deny
rules           : first match wins

For example, this creates a deny-by-default sandbox that can make HTTPS requests to the public internet and DNS requests through the host gateway:

<CodeGroup> ```rust Rust let policy = NetworkPolicy::builder() .default_deny() .egress(|e| e.tcp().port(443).allow_public()) .egress(|e| e.udp().tcp().port(53).allow_host()) .build()?;

let sb = Sandbox::builder("secure-agent") .image("alpine") .network(|n| n.policy(policy)) .create() .await?;


```typescript TypeScript
import { NetworkPolicy, Sandbox } from "microsandbox";

await using sb = await Sandbox.builder("secure-agent")
    .image("alpine")
    .network((n) => n.policy(
        NetworkPolicy.builder()
            .defaultDeny()
            .egress((e) => e.tcp().port(443).allowPublic())
            .egress((e) => e.udp().tcp().port(53).allowHost())
            .build(),
    ))
    .create();
python
from microsandbox import Network, Sandbox

sb = await Sandbox.create(
    "secure-agent",
    image="alpine",
    network={
        "policy": {
            "default_egress": "deny",
            "rules": [
                {"action": "allow", "direction": "egress", "destination": "public", "protocol": "tcp", "port": "443"},
                {"action": "allow", "direction": "egress", "destination": "host", "protocol": "udp", "port": "53"},
            ],
        },
    },
)
go
sb, err := m.CreateSandbox(ctx, "secure-agent",
    m.WithImage("alpine"),
    m.WithNetwork(&m.NetworkConfig{
        DefaultEgress: m.PolicyActionDeny,
        Rules: []m.PolicyRule{
            {Action: m.PolicyActionAllow, Direction: m.PolicyDirectionEgress, Destination: "public", Protocol: m.PolicyProtocolTCP, Port: "443"},
            {Action: m.PolicyActionAllow, Direction: m.PolicyDirectionEgress, Destination: "host", Protocol: m.PolicyProtocolUDP, Port: "53"},
        },
    }),
)
bash
msb create alpine --name secure-agent \
  --net-default-egress deny \
  --net-rule "allow@public:tcp:443,allow@host:udp:53"
</CodeGroup>

Rules can target groups like public, private, and host, or specific IPs, CIDRs, domains, and port ranges. See the CLI reference or your language's SDK networking reference for exact syntax.

Port mapping

Publish a guest port when a service inside the sandbox should be reachable from the host. Published ports bind to 127.0.0.1 by default.

<CodeGroup> ```rust Rust let sb = Sandbox::builder("api") .image("python") .port(8080, 80) .create() .await?; ```
typescript
await using sb = await Sandbox.builder("api")
    .image("python")
    .port(8080, 80)
    .create();
python
from microsandbox import PortBinding, Sandbox

sb = await Sandbox.create("api", image="python", ports=[PortBinding.tcp(8080, 80)])
go
sb, err := m.CreateSandbox(ctx, "api",
    m.WithImage("python"),
    m.WithPorts(map[uint16]uint16{8080: 80}),
)
bash
msb create python --name api -p 8080:80
</CodeGroup>

Use an explicit bind address, such as 0.0.0.0, only when you intentionally want to listen beyond localhost.

Reaching the host

From inside the sandbox, host.microsandbox.internal resolves to the host machine. The default policy denies host access, so allow the host group when a sandbox needs to call a dev server, database, or other local service.

bash
msb create python --name dev-agent \
  --net-rule "allow@public,allow@host"

loopback means the sandbox's own 127.0.0.1, not your laptop's localhost. Use host for host.microsandbox.internal.

Next

  • DNS: domain blocking, pinned nameservers, query timeouts
  • TLS interception: HTTPS inspection with an auto-generated CA
  • Security model: SSRF, rebinding, and metadata protection