Commit c4b500a
authored
feat(helm): cert-manager external issuer + OpenShift passthrough Route (#2468)
* fix(core): trust public root CAs alongside the sandbox mTLS CA
The supervisor gRPC client only trusted the CA configured via
OPENSHELL_TLS_CA, since tonic ClientTlsConfig starts with an empty root
store unless with_native_roots()/with_webpki_roots() is also enabled.
Deployments where the gateway server certificate is issued by a public CA
(e.g. cert-manager against an ACME issuer) caused every supervisor
connection to fail the TLS handshake with "UnknownCA", since the sandbox
mTLS CA and the server cert issuer were no longer the same.
Enable both native and webpki roots in addition to the configured CA.
tonic root store is a union of all configured sources, so this does not
weaken verification for existing self-signed deployments. webpki-roots
(compiled in) is enabled alongside native-roots since the supervisor
binary may run in minimal sandbox images without a populated system CA
bundle.
Signed-off-by: Jesse Jaggars <jjaggars@redhat.com>
* feat(helm): support external cert-manager issuers and OpenShift Route passthrough
Add certManager.serverIssuerRef/clientIssuerRef so the gateway and mTLS
client certificates can be issued by a real Issuer/ClusterIssuer (e.g.
ACME) instead of only the chart built-in self-signed CA.
Add openshiftRoute template for exposing the gateway via a TLS
passthrough Route so the gateway keeps terminating its own TLS/mTLS.
The server Certificate excludes internal-only SANs (cluster-local,
localhost, loopback) when an external issuer is configured, since ACME
issuers reject those per CA/Browser Forum baseline requirements. A
template-time fail guard catches the misconfiguration at helm install
time rather than asynchronously at cert-manager issuance time.
Includes Helm unittest coverage for both issuerRef overrides and Route
rendering, plus a CI values overlay for lint coverage.
Signed-off-by: Jesse Jaggars <jjaggars@redhat.com>
* docs: document cert-manager external issuer and OpenShift Route
Update managing-certificates.mdx with the serverIssuerRef workflow and
install-time validation behavior. Add a production section to the
OpenShift guide covering passthrough Route with a real certificate.
Regenerate Helm README for new certManager and openshiftRoute values.
Sync debug-openshell-cluster skill with new troubleshooting steps for
ACME issuance failures and supervisor UnknownCA from mismatched CAs.
Signed-off-by: Jesse Jaggars <jjaggars@redhat.com>
* fix(helm,core): address PR review feedback on cert-manager external issuer
Addresses all five blocking review items from #2468:
1. Remove .with_native_roots() from supervisor gRPC client -- the
supervisor runs inside the user-selected sandbox image, so the
image CA bundle is not operator-controlled. Keep .with_webpki_roots()
(compiled-in, not user-controlled) alongside the configured CA.
2. Fail at render time when serverIssuerRef.name is set but
clientCaFromServerTlsSecret is still true. Add negative Helm test.
3. Remove clientIssuerRef -- changing only clientIssuerRef breaks both
directions because trust bundles are not modeled separately. Change
serverIssuerRef.kind default from ClusterIssuer to Issuer.
4. Add server.oidc.issuer and server.oidc.audience to the documented
OpenShift production Helm command. Add Access Control prerequisite.
5. Fail at render time when openshiftRoute.enabled and disableTls are
both true. Add negative Helm test.
Signed-off-by: Jesse Jaggars <jjaggars@redhat.com>
* fix(drivers): strip GATEWAY_TLS_SERVER_NAME from Docker and Podman env
Signed-off-by: Jesse Jaggars <jjaggars@redhat.com>
* fix(helm,drivers): guard default clientCaSecretName and add env-strip tests
Signed-off-by: Jesse Jaggars <jjaggars@redhat.com>
* feat(tls): SNI-based dual certificate for internal and external server TLS
Split the gateway server certificate into two: an internal cert issued by
the chart's own CA (for supervisor connections via cluster-local SANs) and
an external cert issued by an operator-configured Issuer such as ACME/Let's
Encrypt (for CLI and Route access via public SANs).
The gateway uses SNI-based certificate selection: connections whose SNI
hostname matches external_server_names receive the external cert; all
others (including those with no SNI) receive the internal cert.
Security improvement: remove .with_webpki_roots() from the supervisor
gRPC client so supervisors trust only the chart CA, closing a MITM vector
via publicly-trusted certificates in user-supplied container images.
Key changes:
- Add DualCertResolver with SNI-based cert selection and full test coverage
- Add external_cert_path, external_key_path, external_server_names to TlsConfig
- Validate partial external cert config (error on cert-without-key or vice versa)
- Validate empty external_server_names when external cert is configured
- Split cert-manager templates into internal + external Certificate resources
- Add Helm guards for misconfigured external issuer (empty serverDnsNames,
internal-only SANs with external issuer, conflicting clientCaFromServerTlsSecret)
- Update gateway-config.mdx, managing-certificates.mdx, openshift.mdx docs
- Update debug-openshell-cluster skill for dual-cert troubleshooting
Signed-off-by: Pi Agent <agent@openshell.local>
* fix(drivers): strip GATEWAY_TLS_SERVER_NAME in VM driver and correct comments
Add the same GATEWAY_TLS_SERVER_NAME environment stripping to the VM
compute driver that Docker, Podman, and Kubernetes drivers already
perform. Without this, a sandbox user on the VM driver could override
the TLS server name the supervisor verifies.
Fix stale comments in Docker and Podman drivers that referenced
'with WebPKI roots trusted' — WebPKI roots are explicitly not trusted
after the tls-webpki-roots removal.
Use tls-ring instead of bare channel for tonic in openshell-core so the
TLS API (ClientTlsConfig, Endpoint::tls_config) is available without
pulling in any root certificate store.
Signed-off-by: Pi Agent <agent@openshell.local>
* fix(tls,helm): wildcard SNI matching and Route host validation
Add RFC 6125 single-level wildcard matching to DualCertResolver so
external_server_names entries like *.example.com correctly match SNI
hostnames like gw.example.com. Previously only exact matches worked,
silently falling back to the internal cert for wildcard configurations.
Add a Helm fail guard in route.yaml that rejects openshiftRoute.host
values not listed in certManager.serverDnsNames when an external issuer
is configured — catches cert/route hostname mismatches at install time
instead of at TLS connect time.
Quote the host field in route.yaml for robustness.
Signed-off-by: Pi Agent <agent@openshell.local>
* fix(helm): address blocking review items — client-CA guard, wildcard Route, serverIssuerRef gate
1. Remove the obsolete guard rejecting serverIssuerRef + clientCaFromServerTlsSecret=true.
The internal server certificate is always signed by the chart CA (the same
CA that signs the client cert), so clientCaFromServerTlsSecret=true is
correct — its filtered ca.crt is exactly the right trust anchor. The old
workaround (mounting openshell-ca-tls directly) unnecessarily exposed the
CA private key to the gateway container. Remove the client-CA overrides
from docs, CI overlay, and production examples.
2. Route host validation now supports wildcard certificates per RFC 6125:
single-level wildcards like *.example.com match gateway.example.com but
not deep.sub.example.com. Require an explicit openshiftRoute.host when
an external issuer is configured — without one, OpenShift generates a
hostname absent from serverDnsNames.
3. Reject serverIssuerRef.name when certManager.enabled is false — the
external certificate, its Secret mount, and the gateway TLS config all
require cert-manager to be enabled.
Validated on ROSA (dev.dyee.p3) with branch-built images:
- Fresh install with letsencrypt-prod ClusterIssuer
- SNI dual-cert: external hostname served Let's Encrypt cert
- Supervisor mTLS via internal cert path: ConnectSupervisor accepted
- Client CA volume: filtered ca.crt from internal server secret (no key)
- CLI connected via Route + OIDC
Helm tests: 81 pass across 7 suites.
Signed-off-by: Jesse Jaggars <jjaggars@redhat.com>
---------
Signed-off-by: Jesse Jaggars <jjaggars@redhat.com>
Signed-off-by: Pi Agent <agent@openshell.local>1 parent c549823 commit c4b500a
28 files changed
Lines changed: 1269 additions & 22 deletions
File tree
- .agents/skills/debug-openshell-cluster
- crates
- openshell-core
- src
- openshell-driver-docker/src
- openshell-driver-podman/src
- openshell-driver-vm/src
- openshell-server
- src
- tests
- deploy/helm/openshell
- ci
- templates
- tests
- docs
- kubernetes
- reference
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
284 | 284 | | |
285 | 285 | | |
286 | 286 | | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
287 | 333 | | |
288 | 334 | | |
289 | 335 | | |
| |||
469 | 515 | | |
470 | 516 | | |
471 | 517 | | |
| 518 | + | |
| 519 | + | |
472 | 520 | | |
473 | 521 | | |
474 | 522 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
18 | | - | |
| 18 | + | |
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
547 | 547 | | |
548 | 548 | | |
549 | 549 | | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
550 | 568 | | |
551 | 569 | | |
552 | 570 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
167 | 167 | | |
168 | 168 | | |
169 | 169 | | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
170 | 181 | | |
171 | 182 | | |
172 | 183 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2453 | 2453 | | |
2454 | 2454 | | |
2455 | 2455 | | |
| 2456 | + | |
| 2457 | + | |
| 2458 | + | |
| 2459 | + | |
| 2460 | + | |
2456 | 2461 | | |
2457 | 2462 | | |
2458 | 2463 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
595 | 595 | | |
596 | 596 | | |
597 | 597 | | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
598 | 618 | | |
599 | 619 | | |
600 | 620 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
483 | 483 | | |
484 | 484 | | |
485 | 485 | | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
486 | 491 | | |
487 | 492 | | |
488 | 493 | | |
| |||
1413 | 1418 | | |
1414 | 1419 | | |
1415 | 1420 | | |
| 1421 | + | |
| 1422 | + | |
| 1423 | + | |
| 1424 | + | |
| 1425 | + | |
| 1426 | + | |
| 1427 | + | |
| 1428 | + | |
| 1429 | + | |
| 1430 | + | |
| 1431 | + | |
| 1432 | + | |
| 1433 | + | |
| 1434 | + | |
| 1435 | + | |
| 1436 | + | |
| 1437 | + | |
| 1438 | + | |
1416 | 1439 | | |
1417 | 1440 | | |
1418 | 1441 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4447 | 4447 | | |
4448 | 4448 | | |
4449 | 4449 | | |
| 4450 | + | |
| 4451 | + | |
| 4452 | + | |
| 4453 | + | |
| 4454 | + | |
4450 | 4455 | | |
4451 | 4456 | | |
4452 | 4457 | | |
| |||
6961 | 6966 | | |
6962 | 6967 | | |
6963 | 6968 | | |
| 6969 | + | |
| 6970 | + | |
| 6971 | + | |
| 6972 | + | |
| 6973 | + | |
| 6974 | + | |
| 6975 | + | |
| 6976 | + | |
| 6977 | + | |
| 6978 | + | |
| 6979 | + | |
| 6980 | + | |
| 6981 | + | |
| 6982 | + | |
| 6983 | + | |
| 6984 | + | |
| 6985 | + | |
| 6986 | + | |
| 6987 | + | |
| 6988 | + | |
| 6989 | + | |
| 6990 | + | |
| 6991 | + | |
| 6992 | + | |
| 6993 | + | |
| 6994 | + | |
| 6995 | + | |
| 6996 | + | |
| 6997 | + | |
| 6998 | + | |
6964 | 6999 | | |
6965 | 7000 | | |
6966 | 7001 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
294 | 294 | | |
295 | 295 | | |
296 | 296 | | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
297 | 310 | | |
298 | 311 | | |
299 | 312 | | |
300 | 313 | | |
301 | 314 | | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
302 | 318 | | |
303 | 319 | | |
304 | 320 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
564 | 564 | | |
565 | 565 | | |
566 | 566 | | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
567 | 570 | | |
568 | 571 | | |
569 | 572 | | |
| |||
1145 | 1148 | | |
1146 | 1149 | | |
1147 | 1150 | | |
| 1151 | + | |
| 1152 | + | |
| 1153 | + | |
1148 | 1154 | | |
1149 | 1155 | | |
1150 | 1156 | | |
| |||
0 commit comments