feat(sandbox,podman): trust corporate CA for https:// proxies and intercepted TLS - #2512
feat(sandbox,podman): trust corporate CA for https:// proxies and intercepted TLS#2512feloy wants to merge 1 commit into
Conversation
|
Rather than make a change for just podman, can you explore having parity across all compute drivers, or note why its not possible before we merge this? |
My idea would be to implement by pieces as small as possible. The first part (#2245) is connection to proxy with http only and Podman only. This PR is connection to proxy with https and certificate, for Podman only. The follow-up PRs would be the full stack (http+https) for each other driver. For Docker, it should be very similar, but I still didn't investigate what would be needed for others drivers. |
|
Just a quick note to say I tested this PR and it worked in my environment. This got things working with my proxy that does SSL interception. It may be useful to separate the host path and gateway container paths so they don't need to match. For example, something like: With the current setup, I had to be careful to make sure the host and container paths to ca-bundle.pem matched. Otherwise sandbox creation fails when the gateway tries to validate the (single) path specified by proxy_ca_bundle (a host path). |
@kevin-pedretti thanks for testing this PR. I don't think this change is necessary: |
…ercepted TLS The corporate proxy chaining only accepted plain http:// proxy URLs, so operators whose forward proxy terminates TLS with a private corporate CA had no way to reach it, and TLS-intercepting proxies (mitmproxy, squid ssl-bump) that re-sign tunneled server certificates broke every upstream handshake after CONNECT. The supervisor now accepts https:// proxy URLs: it wraps the connection to the proxy in TLS before the CONNECT handshake, verifying the proxy certificate against the built-in Mozilla roots, the system CA bundle, and an optional operator corporate CA bundle. The upstream dial returns a Plain/Tls stream enum consumed generically by the relay paths. The corporate CA is delivered as a driver-supplied command-line argument (--upstream-proxy-ca-bundle), never an environment variable, matching the hardened proxy-config model where a sandbox image cannot influence the operator's egress boundary. It is folded into the sandbox combined trust bundle (write_ca_files) and the L7 upstream verification store (build_upstream_client_config) at startup, so intercepted upstream handshakes succeed and sandbox workloads trust the re-signed certificates. Configuration is fail-closed: a CA bundle set without a proxy, or an unreadable or certificate-free file, is fatal rather than silently weakening the trust boundary. The shared parse_upstream_proxy_url validator accepts https:// (recording the scheme so the driver and supervisor agree), keeping the explicit-port requirement. The Podman driver gains a proxy_ca_bundle operator setting (TOML, --sandbox-proxy-ca-bundle, OPENSHELL_SANDBOX_PROXY_CA_BUNDLE) that bind-mounts the host PEM read-only into the sandbox (a CA certificate is not secret) and points --upstream-proxy-ca-bundle at it, with a create-time readability check. The standalone dev gateway task passes OPENSHELL_SANDBOX_PROXY_CA_BUNDLE through to the generated podman config, so a local gateway can be pointed at a TLS-intercepting proxy without hand-editing the regenerated TOML. Refs NVIDIA#1792 Signed-off-by: Philippe Martin <phmartin@redhat.com>
Summary
Adds support for
https://corporate egress proxies and for trusting an operator-provided corporate CA bundle, so sandboxes can reach a forward proxy that terminates TLS with a private CA and can operate behind a TLS-intercepting proxy (mitmproxy, squidssl-bump) that re-signs tunneled server certificates. The feature is delivered through the hardened, driver-supplied argument model — never environment variables — and is fail-closed.Related Issue
Refs #1792
Changes
openshell-core):parse_upstream_proxy_urlnow acceptshttps://(recording the scheme via a newUpstreamProxyAddr.secure), keeping the explicit-port requirement; adds thePROXY_CA_MOUNT_PATHcontainer mount constant.openshell-supervisor-network):ProxyEndpointgains a TLS client config; for anhttps://proxy the connection to the proxy is wrapped in TLS (verifying the proxy certificate) before the CONNECT handshake.PrefixedStreamnow wraps aPlain/TlsUpstreamStreamenum so the relay paths consume either transport transparently.build_upstream_client_config;tls_connect_upstreamwas already generic, sol7/tls.rsis unchanged.run.rsfolds the corporate CA into the sandbox combined trust bundle (write_ca_files) and the L7 upstream verification store, so intercepted upstream handshakes succeed and sandbox workloads trust the re-signed certificates.--upstream-proxy-ca-bundlesupervisor argument (noenv =); new Podman driverproxy_ca_bundlesetting (TOML key,--sandbox-proxy-ca-bundle,OPENSHELL_SANDBOX_PROXY_CA_BUNDLE). The driver validates the pairing (a CA bundle requires a proxy URL), bind-mounts the host PEM read-only into the sandbox (a CA certificate is not secret, so a plain bind mount rather than a driver secret), and performs a create-time readability check.tasks/scripts/gateway.sh) passesOPENSHELL_SANDBOX_PROXY_CA_BUNDLEthrough to the generated Podman config, so a local gateway can be pointed at a TLS-intercepting proxy without hand-editing the regenerated TOML.docs/reference/gateway-config.mdx, the Podman driverREADME.md, and thearchitecture/sandbox.mdtrust-model section.Testing
mise run pre-commitpasseshttp/https, socks rejected), TLS-wrapped CONNECT against a fake TLS proxy (trusted-CA success and untrusted-cert rejection), fail-closed CA-bundle validation, and Podman driver config validation + bind-mount/argv assertions.podman_corporate_proxycase drives anhttps://proxy end to end: the fake proxy self-signs, exposes its CA, and that CA is fed back viaproxy_ca_bundle. (Runs only in the Podman e2e job.)https://proxy with its CA supplied viaproxy_ca_bundle. This exercises both halves in one run: the TLS-wrapped CONNECT to the proxy listener, and the upstream certificate that mitmproxy re-signs with the same CA.Checklist