Update network policy docs with clarifications and examples - #811
Update network policy docs with clarifications and examples#811Branden Bonaby (bbonaby) wants to merge 9 commits into
Conversation
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Pull request overview
Documents the proposed schema 0.8 network policy and migration from schema 0.7.
Changes:
- Defines egress, ingress, and proxy semantics.
- Adds schema migration guidance.
- Updates ProcessContainer examples and enforcement details.
Show a summary per file
| File | Description |
|---|---|
docs/sandbox-policy/v2/networking.md |
Expands schema 0.8 networking guidance. |
docs/sandbox-policy/v2/networking-0.7.0-vs-0.8.0.md |
Adds migration mappings and examples. |
docs/process-container/networking.md |
Updates ProcessContainer networking behavior. |
docs/process-container/examples/0.8.0-schema.md |
Adds a proxy configuration example. |
docs/examples.md |
Replaces legacy networking examples. |
Review details
Tip
Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Files reviewed: 5/5 changed files
- Comments generated: 6
- Review effort level: Balanced
44d6ef8 to
3b9a080
Compare
There was a problem hiding this comment.
Review details
Suppressed comments (4)
docs/sandbox-policy/0.8.0/networking/networking.md:76
- This gives
ingress.hostLoopbackbidirectional semantics, including sandbox-to-host proxy access, whileschema-updates.md:17and D2 below define it as host-loopback inbound control. That ambiguity determines whether an egress-deny sandbox may initiate connections to host services. Please define one direction for this field and make the migration table, D2, and proxy guidance consistent with it.
docs/sandbox-policy/0.8.0/networking/networking.md:339 - The documented Seatbelt mechanism cannot enforce the promised host-loopback-only boundary. Seatbelt shares the host network stack, and the current
(allow network-inbound (local ip))rule permits listening on any local interface; a sandbox binding0.0.0.0can therefore be reachable from LAN/WAN, contrary to lines 65-67 and D2. The 0.8 contract should either reject this ingress posture on Seatbelt or specify a source/interface-scoped enforcement mechanism before claiming support.
docs/sandbox-policy/0.8.0/networking/schema-updates.md:19 - This mapping is too broad: a 0.7
proxy.urlthat points to loopback does have a 0.8 equivalent inruntimeConfig.networkProxy; only remote proxy URLs are removed. As written, users migrating an existing loopback URL are told there is no replacement.
| `proxy.url` | No GA equivalent | Schema 0.8 accepts only HTTP/S loopback proxy URLs |
docs/linux-wsl-roadmap-june-2026.md:164
- These line citations no longer identify the ingress requirements: line 148 is the proxy URL, line 289 is the proxy enforcement row, and line 295 is only the implementation-doc link. Replace the fragile line-number list with links to the “Host Loopback and Inbound Policy” and D2 headings so this roadmap still points implementers to the stated contract.
| 14 | **(N2) Inbound control (`hostLoopback`)** | 🟡 Actionable | Already in place: `--unshare-net` inherently blocks inbound (no route). New work (proxy mode): GA requires ingress enforced via an iptables **INPUT** chain in the sandbox's **own network namespace** (`docs/sandbox-policy/0.8.0/networking/networking.md` L148/L212/L289/L295), scoped per-sandbox (D6). This **depends on N1** moving proxy mode off the shared host netns onto `--unshare-net` + a routed proxy (slirp4netns/veth, elevation required). Once Bwrap has a private netns, ingress runs there via the shared `NetworkIptablesManager` with a default **DROP** (same chain as LXC): `-i lo` ACCEPT (intra-container only), `ESTABLISHED,RELATED` ACCEPT. As on LXC, a bare `NEW -j ACCEPT` is **wrong** (it exposes the container IP over the veth); `hostLoopback: "allow"` requires a **host-loopback-bound DNAT/forward** with INPUT allowing `NEW` **only** for that path. A host-side INPUT chain on the shared netns is **not** the GA target: it can't be attributed to a single sandbox. **Dual-stack:** as on LXC, the `iptables` INPUT chain covers IPv4 only; a parallel `ip6tables`/`nftables` INPUT path is required for `::1`, otherwise IPv6 inbound escapes the default DROP. Shares the IPv6 tooling gap in Bwrap **item #19** and depends on it. | M |
- Files reviewed: 11/12 changed files
- Comments generated: 0 new
- Review effort level: Balanced
There was a problem hiding this comment.
Review details
Suppressed comments (5)
docs/sandbox-policy/0.8.0/networking/networking.md:67
- “All backends” is not true for the backends covered later in this document: the Isolation Session section states that it cannot filter or deny network access and that a contained process can listen on a localhost-reachable port. Scope this default stance to backends that enforce the GA network policy so consumers do not assume default-deny on unsupported containment backends.
sdk/node/README.md:436 - This relative link works in the repository, but this README is also the npm package README and
package.jsonpublishes onlyREADME.md,dist/,bin/, and the license. The referenced../../docstree is therefore absent from the package, leaving npm consumers with a broken link. Keep this as an absolute GitHub URL, as the other documentation links above are.
- [Sandbox policy 0.7.0](../../docs/sandbox-policy/0.7.0/policy.md) — policy specification
docs/sandbox-policy/0.8.0/networking/schema-updates.md:19
- This mapping is too broad: a 0.7
proxy.urlthat is already an HTTP/S loopback URL does have a GA equivalent inruntimeConfig.networkProxy; only remote/non-loopback URLs lose support. As written, the table contradicts the note in the same row and can lead users to discard a directly migratable configuration.
| `proxy.url` | No GA equivalent | Schema 0.8 accepts only HTTP/S loopback proxy URLs |
docs/process-container/networking.md:149
- This 0.8 tier description conflicts with
docs/process-container/os-version-support.md:54-60: schema 0.8 prefers the PSECCreateProcessSecurityEnvironmentcontract, temporarily falls back to legacy SBOXCreateProcessInSandbox, and then continues to AppContainer when neither is usable. Describing SBOX as the sole preferred Tier 1 path makes this planned 0.8 guide direct implementers toward the legacy contract; align the table with the documented PSEC/SBOX/AppContainer fallback order.
| On builds that expose the OS sandbox-creation API (`CreateProcessInSandbox`), the OS itself, in its own elevated context, applies the per-sandbox WFP filters and wires the WinHTTP proxy before the target process runs.<br><br>No MXC-side privileged component, no UAC. The filter lifetime is owned by the OS and bound to AppContainer. This is the preferred path and where new capabilities land first. | On builds without that API (Windows 23H2), model 1 uses per-sandbox WFP filters that MXC writes by elevating on each launch.<br><br>Downlevel supports cooperative proxy routing through environment variables, but it does not satisfy the model 2 enforcement guarantee. It does not provide per-container WinHTTP or scoped proxy-peer enforcement. |
docs/linux-wsl-roadmap-june-2026.md:164
- The retained line-number citations no longer support this inbound-policy claim after the networking document was expanded: current lines 148, 212, 289, and 295 point to the proxy example, IP-literal rationale, proxy enforcement, and an implementation link. Replace these brittle
L...references with the relevant heading anchor (for example, D2 / the backend ingress section) so the roadmap points readers to the actual requirement.
| 14 | **(N2) Inbound control (`hostLoopback`)** | 🟡 Actionable | Already in place: `--unshare-net` inherently blocks inbound (no route). New work (proxy mode): GA requires ingress enforced via an iptables **INPUT** chain in the sandbox's **own network namespace** (`docs/sandbox-policy/0.8.0/networking/networking.md` L148/L212/L289/L295), scoped per-sandbox (D6). This **depends on N1** moving proxy mode off the shared host netns onto `--unshare-net` + a routed proxy (slirp4netns/veth, elevation required). Once Bwrap has a private netns, ingress runs there via the shared `NetworkIptablesManager` with a default **DROP** (same chain as LXC): `-i lo` ACCEPT (intra-container only), `ESTABLISHED,RELATED` ACCEPT. As on LXC, a bare `NEW -j ACCEPT` is **wrong** (it exposes the container IP over the veth); `hostLoopback: "allow"` requires a **host-loopback-bound DNAT/forward** with INPUT allowing `NEW` **only** for that path. A host-side INPUT chain on the shared netns is **not** the GA target: it can't be attributed to a single sandbox. **Dual-stack:** as on LXC, the `iptables` INPUT chain covers IPv4 only; a parallel `ip6tables`/`nftables` INPUT path is required for `::1`, otherwise IPv6 inbound escapes the default DROP. Shares the IPv6 tooling gap in Bwrap **item #19** and depends on it. | M |
- Files reviewed: 11/12 changed files
- Comments generated: 0 new
- Review effort level: Balanced
There was a problem hiding this comment.
Review details
Suppressed comments (2)
docs/process-container/networking.md:54
- Omitting
allowedProxyPeeris insufficient for a non-AppContainer host proxy: the omitted network policy defaultsingress.hostLoopbackto deny (as documented below), so that proxy remains unreachable. Include the required host-loopback opt-in here so users do not produce a broken proxy configuration.
| Peer | Packaged app family or unpackaged AppContainer profile; omit for an unpackaged non-AppContainer proxy |
docs/process-container/networking.md:150
- This still labels the downlevel cooperative environment-variable path as Model 2, although Model 2 above guarantees that all direct egress is blocked. Because clients can ignore proxy variables, this also contradicts the fail-loud rule immediately below that fallback must preserve requested semantics. Model 2 must be unavailable/rejected on this path unless a proxy-only enforcement primitive exists.
| Prefer PSEC (`CreateProcessSecurityEnvironment`) when its complete export set and runtime support probe succeed. Fall back temporarily to SBOX (`CreateProcessInSandbox`) when PSEC is unavailable, then to AppContainer when neither BaseContainer contract is usable. | Neither PSEC nor SBOX (`CreateProcessInSandbox`) is available, so MXC uses the AppContainer fallback.<br><br>Until downlevel WFP support is implemented, model 1 provides coarse egress and ingress allow/deny postures only. Model 2 provides cooperative proxy routing through environment variables without proxy-only enforcement. |
- Files reviewed: 11/12 changed files
- Comments generated: 0 new
- Review effort level: Balanced
There was a problem hiding this comment.
Review details
Suppressed comments (3)
docs/sandbox-policy/0.8.0/networking/schema-updates.md:61
- This purported 0.7-to-0.8 translation silently narrows the legacy rule.
allowedHostspermits every port/protocol for this CIDR, while the 0.8 example permits only TCP/443. Omitportsto preserve behavior, or explicitly state that the example intentionally adds a new restriction.
"to": [ { "cidr": "140.82.112.0/20" } ],
"ports": [ { "protocol": "tcp", "port": 443 } ]
docs/sandbox-policy/0.8.0/networking/schema-updates.md:95
- The migration shown here is incomplete for the legacy
proxy.localhosthost-process case. With the omitted network block, schema 0.8 denies host loopback, while the ProcessContainer guidance requires eitheringress.hostLoopback: "allow"for a host proxy or an identity-scopedallowedProxyPeer. Document that required choice so readers do not migrate to an unreachable proxy.
The omitted 0.8 `network` block uses deny defaults.
docs/process-container/networking.md:79
- This condition also includes the unpackaged non-AppContainer mode below, where
runtimeConfig.networkProxyis set but MXC explicitly does not addprivateNetworkClientServer. Tie the capability toallowedProxyPeerso the two documented proxy modes do not contradict each other.
When `runtimeConfig.networkProxy` is set, MXC adds `privateNetworkClientServer`
for this path.
- Files reviewed: 11/12 changed files
- Comments generated: 0 new
- Review effort level: Balanced
There was a problem hiding this comment.
Review details
Suppressed comments (2)
docs/process-container/networking.md:130
- This contradicts the identity-scoped proxy contract above: lines 78–80 say that setting both
networkProxyandallowedProxyPeeraddsprivateNetworkClientServer, while this sentence says that capability is omitted wheneverhostLoopbackis allowed. A configuration containing all three fields therefore has two documented outcomes. Define the precedence and state it consistently.
The proxy endpoint is runtime metadata, not shared network policy. MXC resolves `allowedProxyPeer` when provided, adds
`privateNetworkClientServer` unless `ingress.hostLoopback` is `"allow"`, and configures the per-container WinHTTP proxy.
docs/process-container/networking.md:123
- This proxy-bypass guarantee is not true for every ProcessContainer path described by this document. The downlevel table at line 185 explicitly says proxy requests fall back to cooperative environment-variable routing and are not model 2 enforcement; in identity-scoped mode the added bidirectional private-network capability can permit direct private egress. Scope this statement to BaseContainer paths with OS enforcement and call out that the downlevel AppContainer fallback is cooperative only.
As a cooperative fallback, MXC also sets the standard proxy environment variables for libraries that use them. The OS
permits outbound traffic only to the configured loopback proxy address and port; direct or proxy-bypassing traffic is
blocked.
- Files reviewed: 11/12 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
6b5b53b to
b1bcfd7
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
There was a problem hiding this comment.
Review details
Suppressed comments (4)
docs/sandbox-policy/0.8.0/networking/networking.md:196
- This absolute guarantee conflicts with the Seatbelt caveat at line 208, which says the default
hostLoopback: denyprevents binding loopback listeners and therefore breaks intra-sandbox loopback servers. Explicitly qualify the guarantee for that backend.
docs/process-container/networking.md:77 - This unconditional claim conflicts with the AppContainer fallback documented below at lines 122–126: adding
privateNetworkClientServercan permit direct private-network egress when WFP is unavailable. Qualify the enforcement guarantee so callers do not mistake the fallback for proxy-only containment.
| Enforcement | Per-container WinHTTP proxy plus scoped loopback; all direct egress remains blocked |
docs/process-container/networking.md:204
- These rules contradict the compatibility behavior immediately above: line 190 says asymmetric private-network intent is accepted without independent enforcement, and lines 196–199 explicitly permit cooperative proxy and capability-coupling exceptions. State those exceptions here; otherwise this section simultaneously promises rejection and acceptance for the same request.
- Follow the PSEC, SBOX, and AppContainer fallback order only when the next path
can preserve the requested semantics.
- Reject the launch with a typed error when no available path can enforce the
request.
docs/process-container/examples/0.8.0-schema.md:15
- This is presented as a schema 0.8 configuration, but it omits the required
process.commandLine, so it will remain invalid even after the planned network fields are implemented. Include a process block or clearly label the JSON as a partial fragment.
"version": "0.8.0-alpha",
"containment": "processcontainer",
- Files reviewed: 11/12 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
There was a problem hiding this comment.
Review details
Suppressed comments (1)
docs/sandbox-policy/0.8.0/networking/schema-updates.md:28
- This describes the 0.7 wire field as a bidirectional private-network switch, but the immutable 0.7 schema defines
allowLocalNetworkas inbound bind/listen permission and says only Seatbelt honors it; ProcessContainer private-network access is separately represented byprocessContainer.capabilities(the SDK may populate both). Consequently, raw 0.7 configs cannot be migrated using this mapping as stated. Please distinguish the SDKSandboxPolicytranslation from the 0.7 wire-schema field, or revise the mapping to the actual wire semantics.
`allowLocalNetwork` does not have a one-to-one schema 0.8 replacement. In
schema 0.7 it combines private-network access behind one switch. In schema 0.8,
`egress` expresses outbound private-network access and `ingress.default`
expresses inbound private-network access. Backends derive their required
network capabilities from both directions.
- Files reviewed: 11/12 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 789939a6-ae1c-4fb7-9729-5988d3657e7b
There was a problem hiding this comment.
Review details
Suppressed comments (1)
docs/sandbox-policy/0.8.0/networking/networking.md:163
- The latter two alternatives omit the required HTTP/S scheme, so copying them does not produce a valid
networkProxyURL. Show a complete URL for every host form.
- Files reviewed: 11/12 changed files
- Comments generated: 0 new
- Review effort level: Balanced
📖 Description
Soon we'll update the 0.8.0 dev schema to use a directional network policy. The legacy
allowLocalNetworkfield combines private-network access behind one switch. Schema 0.8 separates that intent:egresscontrols outbound private-network access, whileingress.defaultcontrols inbound private-network access. On ProcessContainer, MXC derives the required AppContainer capabilities from both directions. Because Windows exposesprivateNetworkClientServeras bidirectional, private-network directionality remains coupled at the capability layer until inbound WFP narrowing is implemented. The remaining changes document the planned schema, explain the 0.7-to-0.8 differences, and show how existing configurations map to the new shape.🔗 References
🔍 Validation
✅ Checklist
Cargo.lock, thedependency-feed-checkcheck passes (see docs/pull-requests.md)📋 Issue Type
GitHub Actions runs the PR validation build automatically. The ADO pipeline
(
MXC-PR-Build) is the Azure version of the PR pipeline, kept in parity with the GitHubActions build; it runs on merge to
main, and Microsoft reviewers with write access can trigger iton a PR with
/azp run. See docs/pull-requests.md.If the
dependency-feed-checkcheck fails on a new dependency, the crate must be added tothe feed before the PR can pass. See docs/pull-requests.md
for the steps.
Microsoft Reviewers: Open in CodeFlow