|
| 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). |
0 commit comments