Update network policy docs with clarifications and examples - #811
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: 2449dac1-feb7-4da5-a249-9df137cc5360
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360
There was a problem hiding this comment.
Review details
Suppressed comments (2)
docs/sandbox-policy/0.8.0/networking/networking.md:331
- For the enforcing ProcessContainer model-2 path, private-network access cannot simply “follow
ingress.default.” The PR defines an additional per-container WFP rule that limits client egress to the configured proxy address and port;ingress.defaultonly supplies the required bidirectional capability. Without documenting that restriction here, this backend table contradicts both the proxy-only model above and the stated PR contract.
docs/process-container/networking.md:91 - This explicitly leaves other private-network egress available in model 2, but the PR contract says model 2 installs per-container WFP enforcement that permits client egress only to the configured proxy address and port.
privateNetworkClientServermust be granted as a capability gate, but WFP must still block every other private destination; otherwise raw-socket clients retain a non-proxy egress path. Update this section’s enforcement table and surrounding statements consistently.
MXC also sets the standard proxy environment variables for libraries that use cooperative proxying. Direct internet
traffic that bypasses the proxy is blocked. Other private-network traffic remains available because model 2 requires
the bidirectional private-network capability.
- 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: 2449dac1-feb7-4da5-a249-9df137cc5360
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360
There was a problem hiding this comment.
Review details
Suppressed comments (2)
docs/sandbox-policy/0.8.0/networking/networking.md:174
- The model-2 example omits
network, soingress.hostLoopbackdefaults todeny; however, this document defines that value as blocking container-to-host loopback, while the Seatbelt model-2 proxy is explicitly a host-loopback endpoint. The example therefore both selects and forbids the proxy connection. Define whetherruntimeConfig.networkProxycreates a narrow exception tohostLoopback, or requirehostLoopback: "allow"on backends whose proxy remains on host loopback and update the examples accordingly.
docs/process-container/networking.md:24 - The absence of
internetClientblocks public internet access, but it is not the complete containment boundary onceingress.default: "allow"grantsprivateNetworkClientServer: direct private-network egress must also be constrained by the WFP filters described below. Stating that the capability alone is the boundary understates the model-2 guarantee and conflicts with lines 74–77.
the loopback endpoint for runtimes that use proxy environment variables rather than WinHTTP. `NO_PROXY` is a bypass
list and does not carry the proxy endpoint. The containment boundary is the absence of direct internet capability.
Private-network traffic remains available in both directions when `ingress.default` is `"allow"`.
- 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: 2449dac1-feb7-4da5-a249-9df137cc5360
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2449dac1-feb7-4da5-a249-9df137cc5360
There was a problem hiding this comment.
Review details
Suppressed comments (4)
docs/process-container/examples/0.8.0-schema.md:14
- This is presented as a ProcessContainer configuration, but it omits the required
process.commandLine; one-shot parsing rejects it with'process' section is required(config_parser.rs:772-810). Include a placeholder process block so the example is structurally usable once schema 0.8 support lands.
"containment": "processcontainer",
docs/sandbox-policy/0.8.0/networking/networking.md:185
- This wording implies transparent forwarding of HTTP(S), although the routing mechanism above is cooperative and non-cooperating clients are blocked. Clarify that split here as well.
docs/sandbox-policy/0.8.0/networking/schema-updates.md:99 - This says HTTP(S) traffic is forwarded, but model 2 only configures cooperating clients to use the proxy; clients that ignore the proxy settings are blocked rather than transparently forwarded (see
networking.md:56-61). State both outcomes explicitly so the migration guide does not overpromise transparent proxying.
The omitted 0.8 `network` block uses deny defaults. When `runtimeConfig.networkProxy` is present, direct egress rules
do not apply because egressible HTTP(S) traffic is forwarded to the proxy.
docs/process-container/examples/0.8.0-schema.md:9
- This definition excludes packaged proxies that do not use AppContainer isolation, contradicting the shared contract in
networking.md, which says any packaged proxy uses its Package Family Name. Define the two accepted identity forms independently of whether an installed package uses AppContainer isolation.
This issue also appears on line 14 of the same file.
`allowedProxyPeer` identifies the packaged or unpackaged AppContainer that hosts the proxy.
- 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: 2449dac1-feb7-4da5-a249-9df137cc5360
There was a problem hiding this comment.
Review details
Suppressed comments (2)
docs/sandbox-policy/0.8.0/networking/networking.md:349
- This row incorrectly ties a deny default to omitting
internetClient. Model 1 above supportsegress.default: "deny"with explicit public-network allow rules, which requiresinternetClient; only model 2/3 omit it. Distinguish the WFP default-deny baseline from capability selection.
docs/sandbox-policy/0.8.0/networking/schema-updates.md:78 - This overgeneralizes schema 0.7 enforcement: proxy environment variables are cooperative on the Unix/WSLc paths, while ProcessContainer can configure WinHTTP. Since this section is mapping wire shapes rather than backend behavior, describe where the endpoint is stored instead.
Schema 0.7 uses cooperative proxy variables:
- Files reviewed: 11/12 changed files
- Comments generated: 0 new
- Review effort level: Balanced
| is resolved up front by `BaseContainerRunner::is_usable_for_request()` so tier | ||
| selection never picks a T1 that cannot launch the requested policy. | ||
| checks the transitional legacy SBOX FlatBuffer contract through CPIS. This is | ||
| a 25H2+ capability. Usability is resolved up front by |
Anis Mohammed Khaja Mohideen (kanismohammed)
left a comment
There was a problem hiding this comment.
![]()
📖 Description
Defines the planned schema 0.8 networking contract and aligns the ProcessContainer and Linux/WSL documentation.
egress,ingress, bidirectionalhostLoopback, and runtime proxy semantics.Documentation only; parser, SDK, schema generation, and backend implementation remain follow-up work.
🔗 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