|
| 1 | +<!-- |
| 2 | +SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. |
| 3 | +SPDX-License-Identifier: Apache-2.0 |
| 4 | +--> |
| 5 | + |
| 6 | +# Sandbox application proxy |
| 7 | + |
| 8 | +`openshell-sandbox-proxy` is an optional consumer of the gateway service discovery |
| 9 | +API. It selects the exact discovered hostname from TLS SNI and forwards TLS bytes |
| 10 | +to the owning supervisor's app listener. Application certificates and private |
| 11 | +keys remain at supervisors. HTTP, WebSockets, application authentication, and |
| 12 | +sandbox policy remain enforced by the existing listener and application. |
| 13 | + |
| 14 | +```shell |
| 15 | +openshell-sandbox-proxy \ |
| 16 | + --gateway-endpoint https://gateway.example.com \ |
| 17 | + --workspace default \ |
| 18 | + --gateway-ca /run/discovery/ca.crt \ |
| 19 | + --discovery-token-file /run/discovery/token \ |
| 20 | + --listen-address 0.0.0.0:8443 |
| 21 | +``` |
| 22 | + |
| 23 | +Use an identity already authorized for the selected workspace. Client mTLS can |
| 24 | +use `--discovery-client-cert` and `--discovery-client-key`. Credentials and CA |
| 25 | +files reload on reconnect. This version supports the explicit-workspace API; |
| 26 | +discovery-only platform machine grants and all-workspaces aggregation are |
| 27 | +separate work (#4668). It does not require operator credentials. Plaintext |
| 28 | +credential-free loopback development requires `--allow-insecure-gateway`. |
| 29 | + |
| 30 | +A snapshot initializes the cache and bounded watches replace it. Reconnects |
| 31 | +relist; transient errors retain routes only until their published expiry. |
| 32 | +Authorization/configuration/data-integrity failures clear the cache. Monotonic |
| 33 | +local deadlines are derived from absolute expiries and capped at fifteen seconds; |
| 34 | +operators must synchronize gateway and proxy clocks. Snapshot revisions are |
| 35 | +opaque and installation versions identify replacement independently of renewal. |
| 36 | + |
| 37 | +Only exact, current routes can dial a backend. A route withdrawal, installation |
| 38 | +replacement, or expiry closes affected TCP streams; renewal preserves them. |
| 39 | +There is no gateway payload fallback, wildcard route fallback, or caller-selected |
| 40 | +backend. Limits are 4,096 cached routes, 1,024 concurrent connections, 64 per |
| 41 | +hostname, a 64 KiB ClientHello, and five-second hello/connect/setup deadlines. |
| 42 | +Each relay uses Tokio's bounded bidirectional copy buffers. ClientHello parsing |
| 43 | +is dependency-owned rustls protocol parsing, not a first-party cryptographic |
| 44 | +operation. Authenticated discovery transport uses the shared SDK/crypto facade. |
| 45 | + |
| 46 | +The health listener defaults to port 9091: `/healthz` is process liveness, |
| 47 | +`/readyz` reflects discovery availability, and `/metrics` exposes connection |
| 48 | +counts. During transient discovery failures readiness fails while existing |
| 49 | +unexpired connections can continue. Expiry still closes streams independently |
| 50 | +of the discovery connection. Multiple replicas keep independent caches and need |
| 51 | +no Kubernetes ownership or leader election. |
| 52 | + |
| 53 | +Build with `mise run docker:build:sandbox-proxy`. The standalone Helm chart at |
| 54 | +`deploy/helm/openshell-sandbox-proxy` mounts only discovery identity/trust Secrets; |
| 55 | +it needs no Kubernetes API permissions. Configure NetworkPolicy to allow the |
| 56 | +proxy to reach the gateway API and discovered supervisor app endpoints, and |
| 57 | +restrict supervisor ingress where edge authentication is required. The proxy |
| 58 | +never authenticates application users using its discovery identity. |
| 59 | + |
| 60 | +For Gateway API TLS passthrough, attach a TLSRoute to a Gateway listener in |
| 61 | +`Passthrough` mode and target the proxy Service on port 443. Application TLS |
| 62 | +terminates at the supervisor. An HTTPRoute requires a separate edge termination |
| 63 | +and backend-TLS contract. A controller can instead consume the same discovery |
| 64 | +API and reconcile exact-host routes directly to supervisor endpoints; it does |
| 65 | +not need this proxy. |
| 66 | + |
| 67 | +## Verification |
| 68 | + |
| 69 | +```shell |
| 70 | +cargo test -p openshell-sandbox-proxy |
| 71 | +cargo clippy -p openshell-sandbox-proxy --all-targets -- -D warnings |
| 72 | +helm lint deploy/helm/openshell-sandbox-proxy \ |
| 73 | + --set gatewayEndpoint=https://gateway.example.com --set workspace=default |
| 74 | +``` |
| 75 | + |
| 76 | +Initial live support follows the advertisement implementation: dedicated |
| 77 | +Kubernetes supervisors. Shared publication remains withheld until HA ownership |
| 78 | +term/member mapping is integrated. Hashed multi-gateway hostnames also require |
| 79 | +the common listener/discovery hostname integration; the proxy consumes returned |
| 80 | +hostnames and never reconstructs them. |
0 commit comments