Conversation
The Kubernetes driver had no way to supply a CA bundle for the corporate egress proxy, so an `https://` proxy with a private CA, or a TLS-intercepting proxy, could not be used. Podman and VM already expose `proxy_ca_bundle`. Add `proxy_ca_bundle` to `[openshell.drivers.kubernetes]` as a path the gateway Pod reads. The gateway stages the PEM into the existing per-generation supervisor bootstrap Secret and passes `--upstream-proxy-ca-bundle` on the supervisor argv. That Secret is already immutable, owner-referenced and garbage-collected, and its volume mounts every key at /.openshell/supervisor with no items filter, so this needs no new object kind, volume, mount, or RBAC verb, and works in shared, managed and operator workspace modes. The bundle is deliberately read from the gateway's filesystem rather than referenced as an object in the sandbox namespace. It becomes a trust anchor for every upstream the sandbox reaches, so it must stay in the gateway's trust domain; the immutable staging Secret also keeps the anchor from changing underneath a running sandbox. Bound the staged bundle at 256 KiB. The shared reader's limit is exactly the apiserver's own Secret limit and the bootstrap Secret carries four other keys, so a bundle between the two would pass gateway startup and then fail every sandbox create with an opaque `data: Too long`. Delegate the URL, no_proxy, connect_by_hostname and ca_bundle rules to the shared validate_upstream_proxy_settings, keeping the Secret-specific credential block local: this driver accepts an explicit `proxy_auth_allow_insecure = false` without credentials, which the shared rules reject. This also fixes the acknowledgement being demanded for an `https://` proxy, where the credential travels inside the verified TLS session. Add auth_setting_label so the inline-credential diagnostic names the Secret keys instead of proxy_auth_file, which this driver rejects as an unknown key. Document that the bundle should carry only the CA that signs the proxy's certificate, or that an intercepting proxy re-signs upstream certificates with. Public roots already reach the sandbox through the supervisor image and its TLS stack, and the bundle is concatenated with that system store into a single boundary control frame, so a full merged trust bundle spends the frame budget on duplicated roots. The frame, not the apiserver Secret limit, is the tighter of the two ceilings in practice; raising the staging bound requires checking it. Closes NVIDIA#3443 Signed-off-by: Philippe Martin <phmartin@redhat.com>
feloy
requested review from
a team,
derekwaynecarr,
mrunalp and
sjenning
as code owners
September 18, 2026 06:49
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
proxy_ca_bundleto the Kubernetes compute driver, so sandboxes can egress through anhttps://corporate proxy with a private CA, or a TLS-intercepting proxy that re-signs upstream certificates. The bundle is read from the gateway Pod's filesystem and staged into the existing per-generation supervisor bootstrap Secret, which needs no new object kind, volume, mount, or RBAC verb. Also fixes the Kubernetes driver demandingproxy_auth_allow_insecureforhttps://proxies, where the credential already travels inside a verified TLS session.Related Issue
Closes #3443.
Changes
Driver
crates/openshell-driver-kubernetes/src/config.rs: newproxy_ca_bundlekey;validate_upstream_proxy_confignow delegates URL /no_proxy/connect_by_hostname/ca_bundlerules to the sharedvalidate_upstream_proxy_settings, keeping the Secret-specific credential block local; newMAX_STAGED_PROXY_CA_BUNDLE_BYTES(256 KiB).crates/openshell-driver-kubernetes/src/sandbox_runtime.rs:UPSTREAM_PROXY_CA_BUNDLE_KEY/_PATH;supervisor_bootstrap_secrettakes an optional bundle;supervisor_podemits--upstream-proxy-ca-bundle. No volume change — thebootstrapvolume already mounts the whole Secret at/.openshell/supervisorwith noitemsfilter.crates/openshell-driver-kubernetes/src/driver.rs:read_staged_upstream_proxy_ca_bundlehelper, aspawn_blockingpreflight innew()so a bad path fails gateway startup, and a per-generation read before any Service, Pod, or Secret is created.crates/openshell-driver-kubernetes/src/main.rs:--proxy-ca-bundle/OPENSHELL_UPSTREAM_PROXY_CA_BUNDLEfor the standalone driver binary.crates/openshell-core/src/driver_utils.rs:auth_setting_labelonUpstreamProxySettings, so the inline-credential diagnostic names the Secret keys instead ofproxy_auth_file— a key this driver rejects underdeny_unknown_fields. No behaviour change for the Podman or VM drivers.Helm
upstreamProxy.caBundle.{configMapName,key}, mounted into the gateway Pod through the shared workload template so it covers both Deployment and StatefulSet, renderingproxy_ca_bundleintogateway.toml.Docs
docs/reference/gateway-config.mdx,docs/reference/sandbox-compute-drivers.mdx(including an OpenShift recipe for copying the cluster proxy's trusted-CA ConfigMap),architecture/sandbox.md, the driver README, and thedebug-openshell-clusterskill, which asserted thathttps://proxies were unsupported.Design notes
The bundle is read from the gateway's own filesystem rather than referenced as a ConfigMap in the sandbox namespace. It becomes a trust anchor for every upstream the sandbox reaches, so it must stay in the gateway's trust domain; a ConfigMap in the workload namespace would widen that to anyone with write access there, and would be impossible to pre-provision in
managedoroperatorworkspace modes, where the gateway creates namespaces itself. The staging Secret isimmutable: true, so the anchor cannot change underneath a running sandbox.validate_upstream_proxy_settingsis adopted for most rules but not for credentials: this driver accepts an explicitproxy_auth_allow_insecure = falsewithout credentials, which the shared rules reject, so a blanket switch would break existing hand-writtengateway.tomlfiles. A regression test pins that case.The 256 KiB staging bound guards the apiserver Secret limit. Note that the sandbox boundary's 1 MiB control frame is the tighter ceiling in practice, so raising the bound requires checking it. Operators should supply only the CA that signs the proxy's certificate, not a full merged trust bundle.
Testing
openshell-core(26 passed),openshell-driver-kubernetes(241 passed)Tests added
config.rs—proxy_ca_bundleTOML round-trip, rejection withouthttps_proxy, empty-value rejection, credentials accepted without acknowledgement for anhttps://proxy and still rejected forhttp://, and the inline-credential diagnostic naming the Secret keys. The existing explicit-falseacknowledgement case is kept green as the regression guard for the validator switch.sandbox_runtime.rs— argument present when the bundle is staged and absent when it is not, no volume or mount introduced, and the bootstrap Secret staying immutable with the key present or absent.driver.rs— valid bundle read, fail-closed paths namingproxy_ca_bundle, and oversized-bundle rejection.driver_utils.rs— the new label in both default and overridden form.gateway_config_test.yamlcovers rendering and omittingproxy_ca_bundle; the newgateway_upstream_proxy_ca_test.yamlcovers the mount and volume across both workload kinds, a custom ConfigMap key projected onto the fixed mounted filename, and no volume when unconfigured.https-camode was added toe2e/rust/tests/kubernetes_corporate_proxy.rsande2e/with-kube-gateway.sh. The wrapper mints a CA and aCA:FALSElistener leaf, publishes the CA as a ConfigMap in the gateway's release namespace, and the test TLS-wraps the proxy listener. It compiles but has not been executed, because no Kubernetes cluster was available. It is the only coverage that proves the full chain — gateway read, bootstrap-Secret key, supervisor mount,--upstream-proxy-ca-bundleargument, TLS handshake — so it should be run before merge:The pre-existing
authenticatedmode is worth re-running too, since the sharedproxy_script()signature changed.Checklist
Documentation updated:
docs/reference/gateway-config.mdx,docs/reference/sandbox-compute-drivers.mdx,architecture/sandbox.md,crates/openshell-driver-kubernetes/README.md,deploy/helm/openshell/README.md,skills/debug-openshell-cluster/SKILL.md