Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d8a0f07
docs: document ProcessContainer proxy deployment
bbonaby Aug 11, 2026
17adc4c
docs: document packaged full-trust proxy
bbonaby Aug 11, 2026
022ae9b
docs: constrain packaged proxy listener
bbonaby Aug 12, 2026
d050d78
docs: make packaged proxy example complete
bbonaby Aug 12, 2026
4e0561a
docs: clarify proxy listener ownership
bbonaby Aug 12, 2026
5e20241
Harden proxy firewall manifest guidance
bbonaby Aug 13, 2026
ecd20fd
Restore non-AppContainer proxy paths
bbonaby Aug 13, 2026
89a3edc
Restore non-AppContainer proxy example
bbonaby Aug 13, 2026
2634b5d
Clarify host-loopback proxy limitation
bbonaby Aug 13, 2026
c87fa2e
Clarify ProcessContainer proxy actors
bbonaby Aug 13, 2026
e9fb9ff
Align proxy paths with bidirectional loopback
bbonaby Aug 13, 2026
0601b1d
Key proxy binding by package identity
bbonaby Aug 13, 2026
40802d8
Document lowest-enforcement proxy option
bbonaby Aug 13, 2026
a1e2f6d
Rank proxy deployment enforcement
bbonaby Aug 13, 2026
25eccf2
Wrap proxy profile documentation link
bbonaby Aug 13, 2026
1f9d51f
Make deployment guidance additive
bbonaby Aug 13, 2026
cd504ab
Clarify proxy deployment enforcement
bbonaby Aug 13, 2026
cc300e4
Clarify dynamic proxy port support
bbonaby Aug 13, 2026
335f05e
Keep proxy firewall guidance caller-owned
bbonaby Aug 13, 2026
26dbce2
Clarify proxy endpoint and loopback scope
bbonaby Aug 13, 2026
1e0d9a4
Scope identity-less proxy firewall rule
bbonaby Aug 13, 2026
f1563a2
Order manifest capabilities canonically
bbonaby Aug 13, 2026
8c681f7
Align proxy peer eligibility wording
bbonaby Aug 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 83 additions & 4 deletions docs/process-container/examples/0.8.0-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,89 @@ Package identity can scope a packaged proxy whether or not that proxy uses AppCo
| Field | Value |
|---|---|
| `runtimeConfig.networkProxy` | HTTP/S loopback URL with an explicit port |
| `processContainer.network.allowedProxyPeer` | Package family name or AppContainer profile name |
| `processContainer.network.allowedProxyPeer` | Installed Package Family Name or AppContainer profile name |

ProcessContainer requires `ingress.default: "allow"` for private-network communication with an identity-scoped proxy.
Windows implements this with the bidirectional `privateNetworkClientServer` capability, so the setting also permits
private-network server traffic. `egress.default: "deny"` continues to block direct internet traffic.
Windows implements this on the MXC client with the bidirectional `privateNetworkClientServer` capability, so the
setting also permits private-network server traffic. `egress.default: "deny"` continues to block direct internet
traffic.

See [Process Container Networking Configuration](../networking.md) for Windows enforcement details.
Valid endpoints use `localhost`, `127.0.0.1`, or `[::1]` with an explicit
port. The proxy-specific `network` block above is required for an identity-scoped ProcessContainer proxy and is
omitted for the identity-less host-loopback deployment.

The proxy must already be running and listening on the loopback address and
port configured by `runtimeConfig.networkProxy`. See the canonical
[proxy deployment requirements](../networking.md#proxy-deployment-choices) for endpoint validation and listener
binding. A packaged AppContainer proxy needs `privateNetworkClientServer`, `internetClient` for external destinations,
and inbound firewall authorization.

### Minimal packaged AppContainer proxy manifest

```xml
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
xmlns:desktop2="http://schemas.microsoft.com/appx/manifest/desktop/windows10/2"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap uap10 desktop2 rescap">
<Identity Name="Contoso.AgentProxy" Publisher="CN=Contoso" Version="1.0.0.0" ProcessorArchitecture="x64" />
<Properties>
<DisplayName>Agent Proxy</DisplayName>
<PublisherDisplayName>Contoso</PublisherDisplayName>
<Logo>Assets\Logo.png</Logo>
</Properties>
<Resources>
<Resource Language="en-us" />
</Resources>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.26100.0" />
</Dependencies>
<Capabilities>
<Capability Name="internetClient" />
<Capability Name="privateNetworkClientServer" />
<rescap:Capability Name="runFullTrust" />
</Capabilities>
Comment thread
Copilot marked this conversation as resolved.
<Extensions>
<desktop2:Extension Category="windows.firewallRules">
<desktop2:FirewallRules Executable="proxy.exe">
<desktop2:Rule Direction="in" IPProtocol="TCP" Profile="all"
LocalPortMin="8080" LocalPortMax="8080" />
</desktop2:FirewallRules>
</desktop2:Extension>
</Extensions>
<Applications>
<Application Id="Proxy" Executable="proxy.exe"
uap10:RuntimeBehavior="packagedClassicApp" uap10:TrustLevel="appContainer">
<uap:VisualElements DisplayName="Agent Proxy"
Description="HTTP proxy for contained workloads" BackgroundColor="transparent"
Square150x150Logo="Assets\Logo.png" Square44x44Logo="Assets\Logo.png"
AppListEntry="none" />
</Application>
</Applications>
</Package>
```

See the Microsoft Learn
[package manifest schema reference](https://learn.microsoft.com/uwp/schemas/appxpackage/uapmanifestschema/schema-root)
for package identity, signing, assets, and application metadata.
`runFullTrust` is required by the firewall extension;
`TrustLevel="appContainer"` still runs the proxy in an AppContainer.

The manifest example uses port 8080. The proxy developer must ensure that its inbound firewall rule covers the port
supplied to MXC in `runtimeConfig.networkProxy`.

After installing the package, retrieve its exact Package Family Name:

```powershell
Get-AppxPackage -Name Contoso.AgentProxy |
Select-Object -ExpandProperty PackageFamilyName
```

Use that value verbatim for `allowedProxyPeer` for any packaged proxy. For an unpackaged AppContainer proxy, use its
AppContainer profile name instead.

See [Proxy identity and firewall authorization](../networking.md#proxy-identity-and-firewall-authorization)
for Windows enforcement and firewall details.
91 changes: 91 additions & 0 deletions docs/process-container/networking.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,69 @@ communication must set `ingress.default` to `"allow"` and accept that Windows en
server behavior. On an enforcing BaseContainer path, per-container WFP permits the MXC client container to connect only
to the configured loopback address and port and blocks direct public and private destinations.

#### Proxy deployment choices

Model 2 involves two separate processes:

- **MXC client container:** the BaseContainer created by MXC, which runs the caller's workload and initiates HTTP/S
connections to the proxy.
- **Proxy process:** a caller-created process that is already running outside the MXC client container. It may be
packaged or unpackaged, with or without AppContainer isolation.

MXC must reject a `runtimeConfig.networkProxy` endpoint that is not loopback. The caller must configure the proxy to
bind only the exact loopback address and port supplied to MXC.

| External proxy | `allowedProxyPeer` | MXC client policy | Additional proxy identity |
|---|---|---|---|
| Packaged proxy | Package Family Name | `default: "allow"`; `hostLoopback: "deny"` | Package identity |
| Unpackaged AppContainer | Profile | `default: "allow"`; `hostLoopback: "deny"` | AppContainer profile |
| Unpackaged non-AppContainer | Omit | `default: "allow"`; `hostLoopback: "allow"` | None |

All deployments retain the base Model 2 client policy. `allowedProxyPeer` adds proxy identity binding on top of the
common WFP endpoint enforcement. The proxy endpoint is the loopback address and port in
`runtimeConfig.networkProxy`. The packaged row covers both AppContainer and non-AppContainer proxies because their
client policy and package identity are the same; the enforcement table below separates their additional protections.

`ingress.hostLoopback` is bidirectional. `allowedProxyPeer` authorizes a package family or AppContainer profile without
opening general host-loopback access, so identity-scoped paths keep `hostLoopback: "deny"`. Only an unpackaged
non-AppContainer proxy lacks an accepted peer identity and requires `hostLoopback: "allow"`. That authorizes both
host-loopback directions, but Model 2 WFP still restricts client-container egress to the configured proxy endpoint.
Host-loopback clients can reach listeners in the MXC client container.

#### Identity-scoped proxy

Use the canonical [ProcessContainer schema 0.8 configuration](examples/0.8.0-schema.md), which shows
`runtimeConfig.networkProxy`, `processContainer.network.allowedProxyPeer`, and their relationship in one place.
Use the installed Package Family Name for a packaged proxy, regardless of whether it has AppContainer isolation. Use
the AppContainer profile name for an unpackaged AppContainer proxy.

#### Unpackaged non-AppContainer proxy

An unpackaged non-AppContainer proxy has no package family or AppContainer profile identity:

```jsonc
{
"network": {
"egress": { "default": "deny" },
"ingress": {
"default": "allow",
"hostLoopback": "allow"
}
},
"runtimeConfig": {
"networkProxy": "http://127.0.0.1:8080"
}
// No processContainer.network.allowedProxyPeer.
}
```

MXC grants the client container `privateNetworkClientServer` through `ingress.default: "allow"`, just as it does for an
identity-scoped proxy. The difference is that MXC identifies this proxy only by the configured endpoint and enables
bidirectional host-loopback access. This is the lowest-enforcement deployment option because common WFP endpoint
scoping remains, but Windows cannot verify which host process owns that endpoint. It is intended primarily for
development and debugging and requires an installer- or administrator-owned firewall rule scoped to the proxy
executable and configured port.

#### HTTP client guidance

Code inside the ProcessContainer should use WinHTTP or an HTTP library that queries the system for proxy information.
Expand All @@ -95,13 +158,41 @@ apply when `runtimeConfig.networkProxy` is present.
The proxy endpoint is runtime metadata, not shared network policy. MXC configures the per-container WinHTTP proxy,
applies WFP endpoint scoping, and grants the private-network capability selected by `ingress.default`.

The identity-scoped and host-loopback paths are mutually exclusive. When `allowedProxyPeer` is present, MXC resolves
the package family or AppContainer profile and grants the private-network capability selected by `ingress.default`.
When it is omitted, MXC uses the configured proxy endpoint without peer identity binding and requires bidirectional
host-loopback access. MXC configures the per-container WinHTTP proxy for either path.

The caller must:

- create and authorize the proxy;
- start it before the BaseContainer;
- keep it alive until the client exits; and
- leave egress deny-default with no direct allow or deny rules.

#### Proxy identity and firewall authorization

The WFP loopback-address-and-port restriction described above applies to every row. The table compares the additional
OS enforcement provided for the external proxy. A packaged AppContainer proxy provides the best enforcement. The two
middle rows provide different protections and are not ordered relative to each other.

| Proxy deployment | `allowedProxyPeer` | Additional OS enforcement |
|---|---|---|
| Packaged AppContainer | Package family name | **Best:** AppContainer isolation, package identity, package firewall |
| Unpackaged AppContainer | AppContainer profile name | AppContainer isolation and administrator firewall rule |
| Packaged non-AppContainer | Package family name | Package identity and package firewall; no AppContainer isolation |
| Unpackaged non-AppContainer | Omit | **Least:** no proxy identity or isolation; administrator firewall |

The scoped peer rule and `privateNetworkClientServer` do not bypass Windows
Firewall's block-inbound-to-non-allowed-apps policy. A packaged AppContainer proxy uses the package-owned firewall
declaration shown in the [schema 0.8 examples](examples/0.8.0-schema.md); its application entry uses
`uap10:RuntimeBehavior="packagedClassicApp"` with `uap10:TrustLevel="appContainer"`. An unpackaged AppContainer proxy
requires its installer or administrator to own an equivalent rule scoped to the AppContainer profile SID, proxy
executable, and configured port.
See
[CreateAppContainerProfile](https://learn.microsoft.com/windows/win32/api/userenv/nf-userenv-createappcontainerprofile)
for unpackaged profile creation.

### Model 3: externally blocked (most restrictive)

- **Capabilities:** none; no host or peer loopback exemptions.
Expand Down
Loading