diff --git a/deploy/helm/openshell/templates/_helpers.tpl b/deploy/helm/openshell/templates/_helpers.tpl index 3d9f2f3e0b..c0a7140a5a 100644 --- a/deploy/helm/openshell/templates/_helpers.tpl +++ b/deploy/helm/openshell/templates/_helpers.tpl @@ -274,6 +274,11 @@ Validate chart values that Helm would otherwise accept silently. {{- if and (eq $workloadKind "statefulset") (gt $replicaCount 1) (not (get $workload "allowMultiReplicaStatefulSet" | default false)) -}} {{- fail "replicaCount > 1 with workload.kind=statefulset requires workload.allowMultiReplicaStatefulSet=true; use workload.kind=deployment for external database-backed multi-replica gateways." -}} {{- end -}} +{{- $adminRole := .Values.server.oidc.adminRole | default "" -}} +{{- $userRole := .Values.server.oidc.userRole | default "" -}} +{{- if and .Values.server.oidc.issuer (or (and $adminRole (not $userRole)) (and $userRole (not $adminRole))) -}} +{{- fail "server.oidc.adminRole and server.oidc.userRole must both be set or both be empty." -}} +{{- end -}} {{- $workspaceMode := .Values.server.drivers.kubernetes.workspaceMode | default "shared" -}} {{- if not (has $workspaceMode (list "shared" "managed" "operator")) -}} {{- fail "server.drivers.kubernetes.workspaceMode must be one of: shared, managed, operator." -}} diff --git a/deploy/helm/openshell/templates/gateway-config.yaml b/deploy/helm/openshell/templates/gateway-config.yaml index 083748aee3..c63cc26edc 100644 --- a/deploy/helm/openshell/templates/gateway-config.yaml +++ b/deploy/helm/openshell/templates/gateway-config.yaml @@ -136,12 +136,8 @@ data: {{- if .Values.server.oidc.rolesClaim }} roles_claim = {{ .Values.server.oidc.rolesClaim | quote }} {{- end }} - {{- if .Values.server.oidc.adminRole }} admin_role = {{ .Values.server.oidc.adminRole | quote }} - {{- end }} - {{- if .Values.server.oidc.userRole }} user_role = {{ .Values.server.oidc.userRole | quote }} - {{- end }} {{- if .Values.server.oidc.scopesClaim }} scopes_claim = {{ .Values.server.oidc.scopesClaim | quote }} {{- end }} diff --git a/deploy/helm/openshell/tests/oidc_role_validation_test.yaml b/deploy/helm/openshell/tests/oidc_role_validation_test.yaml new file mode 100644 index 0000000000..dfff832f95 --- /dev/null +++ b/deploy/helm/openshell/tests/oidc_role_validation_test.yaml @@ -0,0 +1,52 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +suite: OIDC role validation +templates: + - templates/gateway-config.yaml + - templates/statefulset.yaml + +tests: + - it: rejects an admin role without a user role + template: templates/statefulset.yaml + set: + server.oidc.issuer: https://issuer.example.com + server.oidc.adminRole: openshell-admin + asserts: + - failedTemplate: + errorPattern: "server.oidc.adminRole and server.oidc.userRole must both be set or both be empty" + + - it: rejects a user role without an admin role + template: templates/statefulset.yaml + set: + server.oidc.issuer: https://issuer.example.com + server.oidc.userRole: openshell-user + asserts: + - failedTemplate: + errorPattern: "server.oidc.adminRole and server.oidc.userRole must both be set or both be empty" + + - it: renders both roles when RBAC mode is configured + template: templates/gateway-config.yaml + set: + server.oidc.issuer: https://issuer.example.com + server.oidc.adminRole: openshell-admin + server.oidc.userRole: openshell-user + asserts: + - matchRegex: + path: data["gateway.toml"] + pattern: '(?m)^admin_role\s*=\s*"openshell-admin"$' + - matchRegex: + path: data["gateway.toml"] + pattern: '(?m)^user_role\s*=\s*"openshell-user"$' + + - it: renders empty roles for authentication-only mode + template: templates/gateway-config.yaml + set: + server.oidc.issuer: https://issuer.example.com + asserts: + - matchRegex: + path: data["gateway.toml"] + pattern: '(?m)^admin_role\s*=\s*""$' + - matchRegex: + path: data["gateway.toml"] + pattern: '(?m)^user_role\s*=\s*""$' diff --git a/docs/reference/gateway-config.mdx b/docs/reference/gateway-config.mdx index 1c846c29a8..6614b2e22d 100644 --- a/docs/reference/gateway-config.mdx +++ b/docs/reference/gateway-config.mdx @@ -205,6 +205,10 @@ namespace = "openshell" allow_reference_namespace = false ``` +Set both OIDC `admin_role` and `user_role` to empty strings to authorize every +authenticated identity. Omitting either field uses its default role name, so +set both explicitly when authentication-only mode is required. + Local Docker, Podman, and VM gateways can also set `[openshell.gateway.mtls_auth] enabled = true` to authenticate CLI callers from verified client certificates. Kubernetes deployments must leave this unset and use OIDC or a trusted access proxy; the Helm chart does not render this table. `[openshell.gateway.tls]` supports optional SNI-based dual-certificate mode for deployments that need separate internal and external server certificates. Set `external_cert_path` and `external_key_path` to point at the external (e.g. ACME/publicly-trusted) certificate and key. List the hostnames that should be served with the external certificate in `external_server_names`. Connections whose TLS SNI hostname matches one of those names receive the external certificate; all other connections (including those with no SNI) receive the primary internal certificate from `cert_path`/`key_path`. Both fields must be set together — providing only one is a configuration error. On Kubernetes with the Helm chart, the external certificate is managed automatically when `certManager.serverIssuerRef.name` is set; the chart populates these fields from the cert-manager-issued external server certificate.