Repository navigation
feat(gateway): verify an external gateway with a CA alone - #13909
Merged
Merged
Conversation
gateway.tls required ca, certificate and key together, and NemoClaw then presented the client pair. OpenShell gateways accept OIDC bearer clients without a client certificate, and OpenShell's SDK and CLI pin a CA without a client identity for them, so a token-authenticated gateway with a private CA could only be reached by replacing the process-wide roots with SSL_CERT_FILE. Make certificate and key optional, but together. With only a CA, the connection pins that CA and presents no client identity. The openshell_gateway data source applies the same rule to its tls_*_env inputs, and cached clients are keyed by the optional identity. Inference endpoints signed by a private CA stay a limit: the supervisor makes that TLS connection, and OpenShell's provider registrations take no CA. limits.md lists it with NVIDIA/OpenShell#3295, and inference.md names the supervisor image as the trust store.
Contributor
linux_arm64 / Build and test failed only on the time budget: bake::agent_builds_default_to_the_host_platform_and_reject_others and bake::amd64_builds_every_harness took 23 s each against 8 s; all 1,734 tests passed, and the same job passed on v1 15df7d0.
Contributor
Author
Authoring session — opening
|
rsliter
approved these changes
Oct 28, 2026
rsliter
left a comment
Collaborator
There was a problem hiding this comment.
Approved at 5ef9565. #13080 explicitly accepted CA-only TLS for external gateways and #13834 defines the narrow behavior and validation. The schema and provider reject partial client identities, and the live TLS fixture verifies bearer access with the configured CA plus wrong-CA refusal. Existing mutual TLS remains covered. The exact-head v1 build, lifecycle, live Docker/Kind, docs, and required policy checks pass. No scope expansion or actionable defect found.
cv
added a commit
that referenced
this pull request
Nov 11, 2026
…ms (#14413) The release notes now list every user-visible change on `v1` since the `v0.1.0-rc9` tag, including the breaking ones, and four example pages drop claims that later changes made false. ## Problem `docs/about/release-notes.md` listed three breaking changes and none of the features, fixes, and onboarding changes that reached `v1` after `v0.1.0-rc9`; it didn't name the configuration shapes the parser now rejects or the intent record version `v0.1.0-rc9` writes. Some example claims went stale: - `examples/spark/README.md` said the pinned OpenShell has the Podman TLS initialization blocker, NVIDIA/OpenShell#3427; its fix merged before OpenShell 0.1.0, and `v1` pins 0.1.7. - `examples/station/README.md` and `examples/gtc-dc/README.md` required exactly one visible GPU on the host; since #13929, `container.gpuDevices` lets a service on a host with more GPUs request one. - `examples/hcl/travel-team` said Fabric's Deep Agents adapter can't turn reasoning off, NVIDIA/NeMo-Fabric#433; NVIDIA/NeMo-Fabric#439 fixed that, and the pinned catalog's Deep Agents `reasoning_effort` accepts `none`. - The travel team cited #13313 for the booking key its service doesn't receive, but #13313 closed when `openshell_api` landed. ## Change - `docs/about/release-notes.md` gains "Changes Since v0.1.0-rc9", grouped by area, from the commits in `v0.1.0-rc9..origin/v1`; where a later commit changed an earlier one, the entry describes the current code, and changes added and removed after the tag aren't listed: - Agents and interfaces: #14037, #14038, #14269, #13981, #14024, #14186, #14052, #14385, #13971, #13858, #13947, #14039, #14042, #14044, #14343. - Inference: #13929, #14391, #14396, #14398, #14400, #13963, #13912, #13964, #14388, #14390, #14397. - Gateways and Kubernetes: #13909, #13970, #13922 (an existing namespace, refused at plan by #13756, is now bound; cluster-wide reads dropped), #14014, #14169, #13921. - Plan, apply, and diagnostics: #14224, #13756, #14141, #14133, #14135, #13775, #13744, #13701. - Onboarding: #13693, #13695, #13741, #13757, #13851, #13978, #14228, #14233, #14334, #14336. - Examples and builds: #14166, #14184, #14188, #14191, #14192, #14200, #13889, #14267, #14312, #14315, #14355, b30e9b4, #13781, #13813, #14246, and the pins in `versions.json` and `image/fabric/Dockerfile`. - Its breaking changes since the tag: - the intent record moving from 15, which `v0.1.0-rc9` writes, through 16 (#14266), 17 (#14343), 18 (#13929), 19 (#14391) and 20 (#14394); - name-keyed `sandboxes` and `inferenceProviders` (#13703, #13705); - a recipe `compatibility.gpu` outside every hardware profile (#13912); - model tuning the adapter doesn't accept (#14111), and Hermes's `max_tokens` losing its default (#14296); - `skills.paths` resolution (#14296); - endpoint and `networkCIDR` validation (#13847, #14081); - the HCL `gateway_values` attribute (#14014), and Kubernetes ownership receipts from before #13922 and #14014. The two earlier items stay, under their own heading. - `examples/spark/README.md` replaces the closed OpenShell#3427 blocker with the Podman and remote-model limits in `docs/resources/limits.md`. - `examples/station/README.md` and `examples/gtc-dc/README.md` require one GPU visible in the model container, and point to `container.gpuDevices` for a host with more. - `examples/hcl/travel-team/README.md` and `WALKTHROUGH.md` drop the NeMo-Fabric#433 limitation, and the travel team's booking-key statements link #14417 instead of #13313. Not listed, because both changes landed after the tag: Deep Agents Code (#14043, #14250), `compatibility.gpuCount` (#14391, #14394), and the "Creating infrastructure state" progress step (#14169, #14248). Checked and left unchanged: the root `README.md`, `crates/nemoclaw-onboarding/README.md`, `crates/nemoclaw-cli/assets/README.md`, `internal-docs/README.md`, the other example READMEs, and every example YAML header comment. The GPU autoscaling README and `load.sh` read the JSON fields `OperationResult` serializes, and NVIDIA/OpenShell#4287 is fixed only after the pinned 0.1.7. The two pre-tag release-note items still match the schema and SDK. `docs/README.md` is left to #14412, which retires the stale field reference snapshot it describes. Not verified: whether Hermes sends the booking key's placeholder to MCP servers; #14417 tracks the live check. ## Beyond CI Each relative link and anchor in the changed files resolves to an existing file and heading.
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.
Failure
gateway.tlsrequiredca,certificateandkeytogether, and NemoClaw then presented the client pair (#13834). OpenShell gateways accept OIDC bearer clients without a client certificate, and OpenShell's SDK and CLI pin a CA with no client identity for them. So the only way to reach a token-authenticated external gateway with a private CA wasSSL_CERT_FILE, which replaces the system roots for NemoClaw and every provider it starts.Separately, an inference endpoint signed by a private CA can't be trusted at all. The sandbox supervisor makes that TLS connection, and OpenShell's provider registrations at the pinned v0.1.5 take no CA. The docs didn't name the supervisor image as the trust store, and
limits.mdlinked a docs page instead of an issue.Decision
flowchart LR TLS["gateway.tls"] --> CA["ca alone:<br/>pin the CA, no client identity"] TLS --> Pair["ca + certificate + key:<br/>mutual TLS, as before"] TLS -.-> Partial["certificate or key alone,<br/>or no ca: rejected"] Inference["Private-CA inference endpoint"] -.-> Limit["limits.md: #13834,<br/>NVIDIA/OpenShell#3295"]cais required;certificateandkeyare optional but must appear together (dependentRequired).TlsFilescarries an optionalIdentityFiles. With only a CA, the channel trusts that CA instead of the system roots and presents no client certificate.openshell_gatewaydata source: itstls_*_envinputs follow the same rule. Compile emitstls_certificate_envandtls_key_envonly for a pair, and cached clients are keyed by the optional identity.usage.md,provider.mdandsecurity.mddescribe CA-only TLS.inference.mdnames the supervisor image as the store that must trust an inference endpoint's CA.limits.mdlists private-CA inference endpoints with [TLS] Record private-CA inference endpoints as a limit, and accept an external gateway's CA alone #13834 and feat: trust additional destination CAs for sandbox egress TLS OpenShell#3295.Validation
Each new test failed against the code before its change, for the stated reason, and now passes:
config_schema::external_gateway_tls_takes_a_ca_alone_or_with_a_client_certificate_and_key: the parser and schema rejected a CA alone. It also checks thatcawith onlycertificateor onlykey, andcertificatewithkeybut noca, are rejected.tls::a_ca_alone_verifies_the_gateway_without_a_client_certificate: against a fixture gateway that requests no client certificate, the connection was refused withAuthentication. It now creates the workspace, and a CA from another authority fails with "the gateway's TLS server certificate is not signed by the configured certificate authority".client::tests::tls_references_name_a_ca_alone_or_with_a_certificate_and_key: the data source reported "Incomplete TLS credential references" for a CA alone; partial pairs still fail.Checks:
schema --check,docs --check, andcargo clippy --workspace --all-targets -D warningspass.cargo cipassed locally onv1876b44f15, and again after mergingv115df7d09b: fmt, clippy, build, 1,734 unit tests, schema, bundle, and 156 lifecycle tests.docs/limits.md).For #13834; PRs into
v1don't close issues, so it needs closing by hand after merge. Part of #13837.