Skip to content

Commit 358906a

Browse files
committed
docs(extensibility): add supervisor middleware guide
Signed-off-by: Piotr Mlocek <pmlocek@nvidia.com>
1 parent 7b5cba4 commit 358906a

5 files changed

Lines changed: 150 additions & 13 deletions

File tree

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
---
2+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
title: "Supervisor Middleware"
5+
sidebar-title: "Supervisor Middleware"
6+
description: "Configure and operate built-in and operator-run middleware for sandbox HTTP requests."
7+
keywords: "Generative AI, Cybersecurity, AI Agents, Supervisor Middleware, Extensibility, Request Filtering"
8+
---
9+
10+
Supervisor middleware adds ordered request-processing stages to allowed HTTP egress. Middleware runs after network and L7 policy admit a request and before OpenShell injects provider credentials. A stage can allow or deny the request, replace its body, add approved headers, and report audit-safe findings.
11+
12+
Middleware selection is independent of the network policy rule that admitted the request. OpenShell matches middleware by destination host, so the same middleware applies consistently across broad, specific, user-authored, and provider-derived network policies.
13+
14+
## Request Flow
15+
16+
For each inspected HTTP request, the supervisor:
17+
18+
1. Evaluates network and L7 policy.
19+
2. Selects middleware whose host selectors match the admitted destination.
20+
3. Buffers the request body using the smallest body limit in the selected chain.
21+
4. Runs matching middleware in policy declaration order.
22+
5. Applies allowed transformations, injects provider credentials, and forwards the request.
23+
24+
Middleware receives the request before credential injection. Operator-run services cannot inspect OpenShell-managed credentials.
25+
26+
## Choose a Middleware Type
27+
28+
| Type | Registration | Body limit | Deployment |
29+
| --- | --- | --- | --- |
30+
| Built-in | None | Defined by OpenShell | Runs inside the supervisor |
31+
| Operator-run service | Required in gateway TOML | Set by the operator, up to the service capability | Runs as a separate service reachable by the gateway and supervisors |
32+
33+
`openshell/secrets` is the built-in middleware currently available. It identifies common secret patterns in UTF-8 request bodies and replaces matched values before the request leaves the sandbox.
34+
35+
Operator-run services expose one or more binding IDs. Policies reference a binding ID, such as `example/content-guard`, rather than the gateway registration name.
36+
37+
## Register a Middleware Service
38+
39+
Start an operator-run service before starting the gateway, then add a registration to the local gateway TOML:
40+
41+
```toml
42+
[[openshell.gateway.middleware]]
43+
name = "local-content-guard"
44+
endpoint = "http://host.openshell.internal:50051"
45+
allow_insecure = true
46+
max_body_bytes = 262144
47+
```
48+
49+
| Field | Description |
50+
| --- | --- |
51+
| `name` | Operator-facing registration name used in diagnostics. Policies do not reference this value. |
52+
| `endpoint` | Service address reachable from both the gateway and sandbox supervisors. |
53+
| `allow_insecure` | Required acknowledgement for the currently supported plaintext endpoint. |
54+
| `max_body_bytes` | Operator limit applied to every binding exposed by the service. |
55+
56+
The gateway connects to every registered service and verifies its capabilities before accepting traffic. Gateway startup fails when a service is unavailable, reports an invalid capability, or exposes a binding ID already owned by another service. Operator-run services cannot claim the reserved `openshell/` namespace.
57+
58+
Registration is static. Restart the gateway after adding, removing, or changing a service. See [Gateway Configuration](/reference/gateway-config#supervisor-middleware-services) for the complete gateway TOML context.
59+
60+
## Apply Middleware with Policy
61+
62+
Add middleware configs to the top-level `network_middlewares` list:
63+
64+
```yaml
65+
network_middlewares:
66+
- name: redact-secrets
67+
middleware: openshell/secrets
68+
config:
69+
secrets: redact
70+
on_error: fail_closed
71+
endpoints:
72+
include: ["*.example.com"]
73+
exclude: ["trusted.example.com"]
74+
```
75+
76+
Each config has a policy-local `name`, a built-in or operator-provided binding ID in `middleware`, implementation-owned `config`, failure behavior, and host selectors.
77+
78+
`include` selects destination hosts. `exclude` takes precedence and removes hosts from that selection. Matching is case-insensitive and uses the same exact-host and DNS glob behavior as network policy endpoints.
79+
80+
Matching configs run once each in top-level declaration order. Different config names may reference the same binding and run as separate stages. Config names must be unique.
81+
82+
See [Policy Schema](/reference/policy-schema#network-middleware) for the complete field reference.
83+
84+
## Configure Failure Behavior
85+
86+
`on_error` controls what happens when middleware is unavailable, rejects its configuration, returns an invalid result, or exceeds a body limit.
87+
88+
| Value | Behavior |
89+
| --- | --- |
90+
| `fail_closed` | Denies the request when the middleware stage fails. This is the default. |
91+
| `fail_open` | Skips the failed stage and continues the request through the remaining chain. |
92+
93+
Use `fail_open` only when bypassing the middleware preserves the intended security policy. OpenShell emits a detection finding when a failed stage is bypassed.
94+
95+
An explicit deny decision always stops the chain and denies the request, regardless of `on_error`.
96+
97+
## Set Body Limits
98+
99+
Every middleware binding declares the largest request or replacement body it supports.
100+
101+
- Built-in middleware uses its OpenShell-defined limit.
102+
- Each operator-run registration sets `max_body_bytes` no higher than the service capability.
103+
- A selected chain buffers using its smallest stage limit.
104+
- The same per-stage limit applies to request bodies and replacement bodies.
105+
106+
The gateway rejects a registration whose operator limit exceeds the service capability instead of silently clamping it. At request time, exceeding a selected stage's limit is a middleware failure and follows that config's `on_error` behavior.
107+
108+
## Operate Middleware Services
109+
110+
Plan startup and updates around these boundaries:
111+
112+
- Start registered services before the gateway. The gateway validates every registration during startup.
113+
- Keep service endpoints reachable from both the gateway and sandbox supervisors. The supervisors call operator-run services directly on the request path.
114+
- Restart the gateway after changing registrations.
115+
- Keep required services available before creating or updating policies. The gateway validates implementation-owned config before persisting a policy.
116+
- Treat `fail_open` as an explicit availability-over-enforcement decision.
117+
118+
When the effective sandbox configuration changes, a running supervisor validates the new service registry before installing it. If the reload fails, the supervisor keeps its last-known-good registry and emits a configuration failure event.
119+
120+
## Observe Middleware
121+
122+
Middleware activity is emitted through OpenShell's OCSF logging:
123+
124+
- Each invocation records its policy-local middleware name, binding, decision, transformation state, and failure state.
125+
- A bypass under `fail_open` emits a detection finding.
126+
- A required stage that fails closed emits a high-severity detection finding.
127+
- Findings include the service-provided type and label plus aggregate counts. Middleware services should keep those fields audit-safe and omit request content or matched values.
128+
- Registry reload success and failure are emitted as configuration state changes.
129+
130+
See [Logging](/observability/logging) for log access and [OCSF JSON Export](/observability/ocsf-json-export) for structured export.
131+
132+
## Current Limitations
133+
134+
- Middleware applies only to HTTP requests parsed by the supervisor.
135+
- The supported operation and phase are `HttpRequest/pre_credentials`.
136+
- Selection uses destination host include and exclude patterns.
137+
- Required middleware cannot cover `tls: skip` endpoints because OpenShell cannot inspect that traffic.
138+
- Operator-run services currently use explicitly enabled plaintext `http://` endpoints.
139+
- TLS, service authentication, health checks, and runtime registration are not available.
140+
141+
For a runnable operator workflow, see the [content guard example](https://github.com/NVIDIA/OpenShell/tree/main/examples/supervisor-middleware-content-guard).

docs/index.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ navigation:
1919
title: "Manage OpenShell"
2020
- folder: providers
2121
title: "Providers"
22+
- folder: extensibility
23+
title: "Extensibility"
2224
- folder: observability
2325
title: "Observability"
2426
- folder: kubernetes

docs/reference/gateway-config.mdx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,6 @@ Local Docker, Podman, and VM gateways can also set `[openshell.gateway.mtls_auth
150150

151151
## Supervisor Middleware Services
152152

153-
<Warning title="Research Preview Feature">
154-
Supervisor middleware is a research preview. Its policy and service contracts may change without compatibility guarantees. Use it only to prototype and evaluate middleware integrations.
155-
</Warning>
156-
157153
Register operator-run supervisor middleware services with one or more `[[openshell.gateway.middleware]]` entries. Registration is static and operator-owned; changing it requires restarting the gateway.
158154

159155
```toml
@@ -172,6 +168,8 @@ The gateway connects to every registered service and validates `Describe` before
172168

173169
The service endpoint must use plaintext `http://`, and `allow_insecure = true` is required as an explicit acknowledgement that inspected request content is sent without transport encryption or peer authentication. TLS, authentication, health checks, and runtime registration are not supported. The endpoint must be reachable from both the gateway and sandbox supervisors; use `host.openshell.internal` or another shared address when both runtimes resolve it.
174170

171+
See [Supervisor Middleware](/extensibility/supervisor-middleware) for selection, failure, body-limit, and operational guidance.
172+
175173
`image_pull_policy` is intentionally not a shared gateway key. Kubernetes and Docker use `Always`, `IfNotPresent`, or `Never`. Podman uses `always`, `missing`, `never`, or `newer`. Set it inside the relevant driver table.
176174

177175
## Driver References

docs/reference/policy-schema.mdx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -472,10 +472,6 @@ Identifies an executable that is permitted to use the associated endpoints.
472472

473473
## Network Middleware
474474

475-
<Warning title="Research Preview Feature">
476-
Supervisor middleware is a research preview. Its policy and service contracts may change without compatibility guarantees. Use it only to prototype and evaluate middleware integrations.
477-
</Warning>
478-
479475
**Category:** Dynamic
480476

481477
An ordered list of middleware configs selected after network and L7 policy admit an HTTP request. Middleware selection is independent of the network policy entry that admitted the request. Every matching config runs once in list order before provider credential injection.
@@ -502,6 +498,8 @@ network_middlewares:
502498

503499
Host selectors use the same case-insensitive exact and DNS glob semantics as network endpoints. Middleware runs only on HTTP requests the supervisor parses. A selector that can require middleware on a `tls: skip` endpoint is rejected because OpenShell cannot inspect that traffic.
504500

501+
See [Supervisor Middleware](/extensibility/supervisor-middleware) for registration, failure behavior, body limits, and operational guidance.
502+
505503
## Full Example
506504

507505
The following policy grants read-only GitHub API access and npm registry access:

docs/sandboxes/policies.mdx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,6 @@ Raw streams are connection-scoped and outside L7 live-reload guarantees. This in
7272

7373
## Supervisor Middleware
7474

75-
<Warning title="Research Preview Feature">
76-
Supervisor middleware is a research preview. Its policy and service contracts may change without compatibility guarantees. Use it only to prototype and evaluate middleware integrations.
77-
</Warning>
78-
7975
Supervisor middleware can inspect, deny, or replace admitted HTTP request bodies before provider credentials are injected. Middleware selection is independent of the `network_policies` rule that admitted the request: each `network_middlewares` entry matches the destination host through `endpoints.include` and `endpoints.exclude`.
8076

8177
```yaml
@@ -92,10 +88,12 @@ network_middlewares:
9288
9389
Matching entries run once each in top-level declaration order. Config names must be unique. Different config names may use the same implementation and run as distinct stages. `exclude` takes precedence over `include`.
9490

95-
`openshell/secrets` is built into the supervisor. Operator-provided binding IDs must be registered before a policy can reference them; see [Supervisor Middleware Services](/reference/gateway-config#supervisor-middleware-services). The gateway calls the implementation's `ValidateConfig` before accepting the policy.
91+
`openshell/secrets` is built into the supervisor. Operator-provided binding IDs must be registered before a policy can reference them. The gateway validates implementation-owned config before accepting the policy.
9692

9793
`on_error` defaults to `fail_closed`. Use `fail_open` only when skipping a failed middleware is acceptable. Middleware applies only to HTTP traffic the supervisor can parse and inspect; policy validation rejects a required selector that can cover a `tls: skip` endpoint.
9894

95+
See [Supervisor Middleware](/extensibility/supervisor-middleware) for registration, chain ordering, body limits, failure behavior, and operations.
96+
9997
## Baseline Filesystem Paths
10098

10199
When a sandbox runs in proxy mode (the default), OpenShell automatically adds baseline filesystem paths required for the sandbox child process to function: `/usr`, `/lib`, `/etc`, `/var/log` (read-only) and `/sandbox`, `/tmp` (read-write). Paths like `/app` are included in the baseline set but are only added if they exist in the container image.

0 commit comments

Comments
 (0)