diff --git a/docs/kubernetes/access-control.mdx b/docs/kubernetes/access-control.mdx index 8824b6de1..229c37bd6 100644 --- a/docs/kubernetes/access-control.mdx +++ b/docs/kubernetes/access-control.mdx @@ -82,6 +82,131 @@ Both `adminRole` and `userRole` must be set, or both must be empty. Setting only | Microsoft Entra ID | `roles` | | Okta | `groups` | +### Keycloak setup + +Keycloak public clients do not include `sub`, `aud`, or realm roles in access tokens by default. Without these claims, the gateway rejects tokens with errors like `missing field 'sub'`, audience mismatch, or `role 'openshell-user' required`. + +After creating a realm and a public client (with PKCE S256, redirect URIs `http://localhost:*` and `http://127.0.0.1:*`), add these protocol mappers to the client: + +| Mapper name | Mapper type | Key config | +|---|---|---| +| `sub` | Subject (sub) | access.token.claim: true | +| `openshell-audience` | Audience | included.client.audience: `openshell-cli` | +| `realm-roles` | User Realm Role | claim.name: `realm_access.roles`, multivalued: true | + +Add these via the Keycloak admin console under **Clients → openshell-cli → Client scopes → Dedicated scope → Add mapper**, or via the CLI: + + + + +```shell +KC_ADM="kcadm.sh --config /tmp/kcadm.config" + +$KC_ADM config credentials \ + --server http://localhost:8080 \ + --realm master \ + --user \ + --password + +$KC_ADM create realms \ + -s realm=openshell \ + -s enabled=true + +$KC_ADM create clients -r openshell \ + -s clientId=openshell-cli \ + -s enabled=true \ + -s publicClient=true \ + -s directAccessGrantsEnabled=true \ + -s standardFlowEnabled=true \ + -s 'redirectUris=["http://localhost:*","http://127.0.0.1:*"]' \ + -s 'webOrigins=["http://localhost","http://127.0.0.1"]' \ + -s 'attributes={"pkce.code.challenge.method":"S256"}' + +CLIENT_UUID=$($KC_ADM get clients -r openshell \ + -q clientId=openshell-cli --fields id --format csv --noquotes) + +$KC_ADM create clients/$CLIENT_UUID/protocol-mappers/models -r openshell \ + -s name=sub \ + -s protocol=openid-connect \ + -s protocolMapper=oidc-sub-mapper \ + -s 'config={"access.token.claim":"true","id.token.claim":"true"}' + +$KC_ADM create clients/$CLIENT_UUID/protocol-mappers/models -r openshell \ + -s name=openshell-audience \ + -s protocol=openid-connect \ + -s protocolMapper=oidc-audience-mapper \ + -s 'config={"included.client.audience":"openshell-cli","access.token.claim":"true","id.token.claim":"true"}' + +$KC_ADM create clients/$CLIENT_UUID/protocol-mappers/models -r openshell \ + -s name=realm-roles \ + -s protocol=openid-connect \ + -s protocolMapper=oidc-usermodel-realm-role-mapper \ + -s 'config={"claim.name":"realm_access.roles","jsonType.label":"String","multivalued":"true","access.token.claim":"true","id.token.claim":"true","userinfo.token.claim":"true"}' + +$KC_ADM create roles -r openshell -s name=openshell-user +$KC_ADM create roles -r openshell -s name=openshell-admin +``` + + + + +```shell +KC_URL=https://keycloak.example.com + +TOKEN=$(curl -sk "${KC_URL}/realms/master/protocol/openid-connect/token" \ + -d "client_id=admin-cli" \ + -d "username=" \ + -d "password=" \ + -d "grant_type=password" | jq -r .access_token) + +curl -sk -X POST "${KC_URL}/admin/realms" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"realm":"openshell","enabled":true}' + +curl -sk -X POST "${KC_URL}/admin/realms/openshell/clients" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "clientId": "openshell-cli", + "enabled": true, + "publicClient": true, + "directAccessGrantsEnabled": true, + "standardFlowEnabled": true, + "redirectUris": ["http://localhost:*", "http://127.0.0.1:*"], + "webOrigins": ["http://localhost", "http://127.0.0.1"], + "attributes": {"pkce.code.challenge.method": "S256"} + }' + +CLIENT_UUID=$(curl -sk "${KC_URL}/admin/realms/openshell/clients?clientId=openshell-cli" \ + -H "Authorization: Bearer $TOKEN" | jq -r '.[0].id') + +for MAPPER in \ + '{"name":"sub","protocol":"openid-connect","protocolMapper":"oidc-sub-mapper","config":{"access.token.claim":"true","id.token.claim":"true"}}' \ + '{"name":"openshell-audience","protocol":"openid-connect","protocolMapper":"oidc-audience-mapper","config":{"included.client.audience":"openshell-cli","access.token.claim":"true","id.token.claim":"true"}}' \ + '{"name":"realm-roles","protocol":"openid-connect","protocolMapper":"oidc-usermodel-realm-role-mapper","config":{"claim.name":"realm_access.roles","jsonType.label":"String","multivalued":"true","access.token.claim":"true","id.token.claim":"true","userinfo.token.claim":"true"}}'; do + curl -sk -X POST "${KC_URL}/admin/realms/openshell/clients/${CLIENT_UUID}/protocol-mappers/models" \ + -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$MAPPER" +done + +curl -sk -X POST "${KC_URL}/admin/realms/openshell/roles" \ + -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ + -d '{"name":"openshell-user"}' + +curl -sk -X POST "${KC_URL}/admin/realms/openshell/roles" \ + -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ + -d '{"name":"openshell-admin"}' +``` + + + + +Assign `openshell-user` to users who need sandbox access and `openshell-admin` to administrators. + + +On Kubernetes, run `kcadm.sh` via `kubectl exec` into the Keycloak pod. The `--config /tmp/kcadm.config` flag is required when the container runs as non-root. On OpenShift, see [OIDC on OpenShift](/kubernetes/openshift/oidc-keycloak) for the `oc exec` variant and OpenShift-specific details. + + ## Reverse-Proxy Auth Termination When an access proxy, such as Cloudflare Access, ngrok, or a corporate SSO gateway, handles authentication in front of the OpenShell gateway, you can explicitly allow unauthenticated user calls at the gateway: diff --git a/docs/kubernetes/openshift.mdx b/docs/kubernetes/openshift.mdx deleted file mode 100644 index b8313bdfe..000000000 --- a/docs/kubernetes/openshift.mdx +++ /dev/null @@ -1,95 +0,0 @@ ---- -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -title: "OpenShift" -sidebar-title: "OpenShift" -description: "Install the OpenShell Helm chart on OpenShift, including the SCC binding and chart overrides required by OpenShift's Security Context Constraints." -keywords: "Generative AI, Cybersecurity, Kubernetes, OpenShift, SCC, Security Context Constraints, Helm, Gateway, Installation" -position: 5 ---- - - -The OpenShift install path is experimental. It currently requires running sandbox pods under the `privileged` SCC and installing the gateway with TLS and the PKI init job disabled. Use only for evaluation on a private network. - - -OpenShift's [Security Context Constraints](https://docs.openshift.com/container-platform/latest/authentication/managing-security-context-constraints.html) reject the chart's default pod security settings. Installing on OpenShift requires precreating the namespace, granting the `privileged` SCC to the sandbox service account, and overriding a few chart values so the cluster admission controller can assign UIDs and FS groups itself. - -## Prerequisites - -- OpenShift 4.x cluster with `oc` configured -- Helm 3.x -- [Agent Sandbox](/kubernetes/setup#install-agent-sandbox) controller and CRDs installed - -## Install - - - -## Create the namespace - -Pre-create the namespace so the SCC binding can be applied before the chart installs: - -```shell -oc create ns openshell -``` - -## Grant the privileged SCC to sandbox pods - -Sandbox pods run under the `openshell-sandbox` service account in the `openshell` namespace and require the `privileged` SCC: - -```shell -oc adm policy add-scc-to-user privileged -z openshell-sandbox -n openshell -``` - -## Install the chart with OpenShift overrides - -```shell -helm install openshell oci://ghcr.io/nvidia/openshell/helm-chart \ - --version \ - --namespace openshell \ - --set pkiInitJob.enabled=false \ - --set server.disableTls=true \ - --set podSecurityContext.fsGroup=null \ - --set securityContext.runAsUser=null -``` - -| Override | Reason | -|---|---| -| `pkiInitJob.enabled=false` | Skips the built-in TLS PKI Job. TLS must also be disabled unless you provide TLS Secrets another way. | -| `server.disableTls=true` | The gateway has no certificates without `pkiInitJob`, so it must run plaintext. | -| `podSecurityContext.fsGroup=null` / `securityContext.runAsUser=null` | Clear the chart's hardcoded UID and fsGroup so OpenShift's SCC admission can assign them. | - -The gateway still needs the sandbox JWT signing Secret. When disabling -`pkiInitJob` without enabling cert-manager, pre-create that Secret before -installing the chart. - -## Wait for the gateway to be ready - -```shell -oc -n openshell rollout status statefulset/openshell -``` - -If you set `workload.kind=deployment`, use -`oc -n openshell rollout status deployment/openshell` instead. - - - -## Connect to the gateway - -The gateway is now running over plaintext HTTP. Connect with `oc port-forward`: - -```shell -oc -n openshell port-forward svc/openshell 8080:8080 -``` - -Register the gateway with the CLI: - -```shell -openshell gateway add http://127.0.0.1:8080 --local --name openshift -openshell status -``` - -## Next Steps - -- For TLS-enabled deployments, refer to [Managing Certificates](/kubernetes/managing-certificates) after SCC-compatible PKI is supported. -- To expose the gateway externally, refer to [Ingress](/kubernetes/ingress). -- To configure OIDC authentication, refer to [Access Control](/kubernetes/access-control). diff --git a/docs/kubernetes/openshift/gateway-connection.mdx b/docs/kubernetes/openshift/gateway-connection.mdx new file mode 100644 index 000000000..0c9b72ad1 --- /dev/null +++ b/docs/kubernetes/openshift/gateway-connection.mdx @@ -0,0 +1,169 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Gateway Connection" +sidebar-title: "Gateway Connection" +slug: "kubernetes/openshift/gateway-connection" +description: "Connect the OpenShell CLI to a gateway running on OpenShift using port forwarding, a reencrypt Route, or the Kubernetes Gateway API." +keywords: "Generative AI, Cybersecurity, Kubernetes, OpenShift, Route, Gateway API, Istio, gRPC, Ingress, CLI" +position: 2 +--- + +After the gateway is installed, register it with the CLI so you can create and manage sandboxes. The gateway is only reachable inside the cluster by default. How you connect depends on whether you need local-only access or external access for your team. + +| Method | Use case | +|---|---| +| [Port forward](#local-access) | Local evaluation from your workstation | +| [Route](#remote-access-with-routes) | Shared or production access using OpenShift-native routing | +| [Gateway API](#remote-access-with-gateway-api) | Shared or production access using the standard Kubernetes Gateway API | + +## Local access + +For quick evaluation, forward the gateway port to your workstation: + +```shell +oc -n openshell port-forward svc/openshell 8080:8080 +``` + +Register the gateway with the CLI: + +```shell +openshell gateway add http://127.0.0.1:8080 --local --name openshift +openshell status +``` + +## Remote access + +In shared and production environments, the gateway is exposed externally so that team members and CI systems can connect from outside the cluster. On OpenShift, there are two options: native Routes or the Kubernetes Gateway API. + +The gateway multiplexes gRPC and HTTP on a single port. Both options must preserve HTTP/2 for gRPC to work. + +### Remote access with Routes + +OpenShift Routes are the simplest way to expose the gateway externally. However, not all route types support gRPC: + +| Route type | gRPC support | Issue | +|---|---|---| +| Edge | Broken | Terminates TLS and forces HTTP/1.1 to the backend, which drops gRPC frames. | +| Passthrough | Broken | Preserves HTTP/2 but exposes the gateway's mTLS client certificate requirement to browsers, causing `ERR_BAD_SSL_CLIENT_AUTH_CERT`. | +| **Reencrypt** | **Works** | Terminates external TLS at the router, re-establishes TLS to the backend, and supports HTTP/2 with the `backend-protocol=h2` annotation. | + +Create a reencrypt route using the gateway's CA certificate for the backend TLS connection: + +```shell +DEST_CA=$(oc get secret openshell-server-tls -n openshell \ + -o jsonpath='{.data.ca\.crt}' | base64 -d) + +oc create route reencrypt openshell \ + --service=openshell --port=8080 \ + --dest-ca-cert=<(echo "$DEST_CA") \ + -n openshell + +oc annotate route openshell -n openshell \ + haproxy.router.openshift.io/backend-protocol=h2 --overwrite +``` + +Register the gateway with the CLI using the route hostname: + +```shell +oc get route openshell -n openshell -o jsonpath='{.spec.host}' +openshell gateway add https:// --gateway-insecure --name openshift +``` + +### Remote access with Gateway API + +The Kubernetes [Gateway API](https://gateway-api.sigs.k8s.io) provides native gRPC routing via `GRPCRoute` resources, without needing HTTP/2 annotations. + +On OpenShift, the Ingress Operator manages Gateway API CRDs. The standard [Envoy Gateway](/kubernetes/ingress) cannot be installed because the Ingress Operator rejects third-party CRD installations. Instead, use the Istio-based Gateway controller that OpenShift provides. + + + +## Identify the GatewayClass + +```shell +oc get gatewayclass +``` + +Look for a class with an Istio-based controller (e.g. `istio` or `data-science-gateway-class`). The class must show `ACCEPTED: True`. + +## Create the Gateway and GRPCRoute + +```shell +kubectl apply -f - <<'EOF' +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: openshell-gateway + namespace: openshell +spec: + gatewayClassName: istio + listeners: + - name: grpc + protocol: HTTPS + port: 443 + tls: + mode: Terminate + certificateRefs: + - name: openshell-server-tls + kind: Secret + allowedRoutes: + namespaces: + from: Same +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: GRPCRoute +metadata: + name: openshell + namespace: openshell +spec: + parentRefs: + - name: openshell-gateway + namespace: openshell + rules: + - backendRefs: + - name: openshell + port: 8080 +EOF +``` + +## Configure TLS to the backend + +The Istio envoy proxy terminates external TLS at the Gateway, then connects to the backend in plaintext by default. Since the OpenShell gateway expects TLS, create a `DestinationRule` for TLS origination: + +```shell +kubectl apply -f - <<'EOF' +apiVersion: networking.istio.io/v1 +kind: DestinationRule +metadata: + name: openshell-tls-origination + namespace: openshell +spec: + host: openshell.openshell.svc.cluster.local + trafficPolicy: + tls: + mode: SIMPLE + insecureSkipVerify: true +EOF +``` + +## Get the external address + +The Gateway controller creates a LoadBalancer service. Wait for the external address: + +```shell +oc get gateway openshell-gateway -n openshell \ + -o jsonpath='{.status.addresses[0].value}' +``` + + +## Register the gateway + +```shell +openshell gateway add https:// --gateway-insecure --name openshift +``` + + + +## Next steps + +- [OIDC with Keycloak](/kubernetes/openshift/oidc-keycloak) — add `--oidc-issuer` to the `gateway add` command for authenticated access. diff --git a/docs/kubernetes/openshift/identity-federation.mdx b/docs/kubernetes/openshift/identity-federation.mdx new file mode 100644 index 000000000..9e1da2881 --- /dev/null +++ b/docs/kubernetes/openshift/identity-federation.mdx @@ -0,0 +1,138 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "OpenShift Identity Federation" +sidebar-title: "Identity Federation" +slug: "kubernetes/openshift/identity-federation" +description: "Optionally configure Keycloak to delegate authentication to the OpenShift OAuth server so cluster users can log in with their existing credentials." +keywords: "Generative AI, Cybersecurity, Kubernetes, OpenShift, Keycloak, Identity Federation, OAuth, SSO" +position: 4 +--- + +If your organisation wants OpenShell users to authenticate with their existing OpenShift cluster credentials instead of managing separate Keycloak accounts, you can configure Keycloak to federate to the OpenShift OAuth server. This is optional — the [OIDC with Keycloak](/kubernetes/openshift/oidc-keycloak) setup works standalone with its own user directory. + +When federation is configured, users are auto-imported into the Keycloak realm on first login. + +## Prerequisites + +- [OIDC with Keycloak](/kubernetes/openshift/oidc-keycloak) configured and working +- `cluster-admin` access to create `OAuthClient` resources + +## Create an OAuthClient in OpenShift + +Generate a client secret and create the `OAuthClient` that Keycloak uses to initiate the OAuth flow: + +```shell +OCP_SECRET=$(openssl rand -hex 32) +KC_URL=https://keycloak.example.com + +cat < + + +```shell +KC_POD="oc exec keycloak-0 -n keycloak --" +KC_ADM="/opt/keycloak/bin/kcadm.sh --config /tmp/kcadm.config" + +$KC_POD $KC_ADM create identity-provider/instances -r openshell \ + -s alias=openshift \ + -s displayName=OpenShift \ + -s providerId=openshift-v4 \ + -s enabled=true \ + -s trustEmail=true \ + -s "firstBrokerLoginFlowAlias=first broker login" \ + -s "config.clientId=keycloak-openshell" \ + -s "config.clientSecret=${OCP_SECRET}" \ + -s "config.baseUrl=$(oc whoami --show-server)" \ + -s "config.defaultScope=user:info" \ + -s "config.syncMode=IMPORT" +``` + + + + +```shell +TOKEN=$(curl -sk "${KC_URL}/realms/master/protocol/openid-connect/token" \ + -d "client_id=admin-cli" \ + -d "username=" \ + -d "password=" \ + -d "grant_type=password" | jq -r .access_token) + +curl -sk -X POST "${KC_URL}/admin/realms/openshell/identity-provider/instances" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{ + \"alias\": \"openshift\", + \"displayName\": \"OpenShift\", + \"providerId\": \"openshift-v4\", + \"enabled\": true, + \"trustEmail\": true, + \"firstBrokerLoginFlowAlias\": \"first broker login\", + \"config\": { + \"clientId\": \"keycloak-openshell\", + \"clientSecret\": \"${OCP_SECRET}\", + \"baseUrl\": \"$(oc whoami --show-server)\", + \"defaultScope\": \"user:info\", + \"syncMode\": \"IMPORT\" + } + }" +``` + + + + + +**ROSA HCP**: set `baseUrl` to the API server URL (`https://api.:443`), not the OAuth route (`oauth.`). On ROSA HCP, the OAuth metadata endpoint (`/.well-known/oauth-authorization-server`) is served by the API server. The OAuth route returns 404. + + +## Assign roles to federated users + +Users imported from OpenShift do not receive the `openshell-user` or `openshell-admin` realm roles automatically. After a user's first login through the "OpenShift" button, assign the appropriate role through the Keycloak admin console: + +**Keycloak Admin Console → Users → select user → Role Mappings → Assign role → openshell-user** + +Or via the CLI/API: + + + + +```shell +$KC_POD $KC_ADM add-roles -r openshell \ + --uusername \ + --rolename openshell-user +``` + + + + +```shell +USER_ID=$(curl -sk "${KC_URL}/admin/realms/openshell/users?username=&exact=true" \ + -H "Authorization: Bearer $TOKEN" | jq -r '.[0].id') + +ROLE_ID=$(curl -sk "${KC_URL}/admin/realms/openshell/roles/openshell-user" \ + -H "Authorization: Bearer $TOKEN" | jq -r '.id') + +curl -sk -X POST "${KC_URL}/admin/realms/openshell/users/${USER_ID}/role-mappings/realm" \ + -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ + -d "[{\"id\":\"${ROLE_ID}\",\"name\":\"openshell-user\"}]" +``` + + + + +## Result + +The Keycloak login page shows a "Login with OpenShift" button below the standard username/password form. Clicking it redirects to the OpenShift login page. After authentication, Keycloak issues an OIDC token with the user's identity and assigned roles, and the CLI stores the token. diff --git a/docs/kubernetes/openshift/index.mdx b/docs/kubernetes/openshift/index.mdx new file mode 100644 index 000000000..5e5bf292a --- /dev/null +++ b/docs/kubernetes/openshift/index.mdx @@ -0,0 +1,40 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "OpenShift" +sidebar-title: "OpenShift" +slug: "kubernetes/openshift" +description: "Deploy the OpenShell gateway on OpenShift with TLS, external access, and OIDC authentication." +keywords: "Generative AI, Cybersecurity, Kubernetes, OpenShift, SCC, Security Context Constraints, Helm, Gateway, Installation, OIDC, Keycloak" +position: 5 +--- + + +The OpenShift install path is experimental. It currently requires running sandbox pods under the `privileged` SCC. Use only for evaluation on a private network. + + +Deploy the OpenShell gateway on OpenShift with Security Context Constraints, external access via Routes or Gateway API, and OIDC authentication with Keycloak. + + + + + +Install the gateway with TLS enabled, configure the SCC binding, and verify the deployment. + + + + +Connect the CLI to the gateway using port forwarding, a reencrypt Route, or the Gateway API. + + + + +Configure the gateway and CLI for Keycloak OIDC authentication on OpenShift. + + + + +Optionally let cluster users log in with their OpenShift credentials via Keycloak identity federation. + + + diff --git a/docs/kubernetes/openshift/install.mdx b/docs/kubernetes/openshift/install.mdx new file mode 100644 index 000000000..cec3e1bd1 --- /dev/null +++ b/docs/kubernetes/openshift/install.mdx @@ -0,0 +1,74 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "Install on OpenShift" +sidebar-title: "Install" +slug: "kubernetes/openshift/install" +description: "Install the OpenShell Helm chart on OpenShift with TLS enabled and the required SCC overrides." +keywords: "Generative AI, Cybersecurity, Kubernetes, OpenShift, SCC, Helm, Gateway, Installation, TLS" +position: 1 +--- + +OpenShift's [Security Context Constraints](https://docs.openshift.com/container-platform/latest/authentication/managing-security-context-constraints.html) reject the chart's default pod security settings. Installing on OpenShift requires precreating the namespace, granting the `privileged` SCC to the sandbox service account, and overriding a few chart values so the cluster admission controller can assign UIDs and FS groups itself. + +## Prerequisites + +- OpenShift 4.x cluster with `oc` configured +- Helm 3.x +- [Agent Sandbox](/kubernetes/setup#install-agent-sandbox) controller and CRDs installed + +## Install + + + +## Create the namespace + +Pre-create the namespace so the SCC binding can be applied before the chart installs: + +```shell +oc create ns openshell +``` + +## Grant the privileged SCC to sandbox pods + +Sandbox pods run under the `openshell-sandbox` service account in the `openshell` namespace and require the `privileged` SCC: + +```shell +oc adm policy add-scc-to-user privileged -z openshell-sandbox -n openshell +``` + +## Install the chart + +```shell +helm install openshell oci://ghcr.io/nvidia/openshell/helm-chart \ + --version \ + --namespace openshell \ + --set podSecurityContext.fsGroup=null \ + --set securityContext.runAsUser=null +``` + +| Override | Reason | +|---|---| +| `podSecurityContext.fsGroup=null` | Clear the hardcoded fsGroup so OpenShift's SCC admission can assign it. | +| `securityContext.runAsUser=null` | Clear the hardcoded UID so OpenShift's SCC admission can assign it. | + +TLS and the PKI init job remain enabled by default. The certgen hook generates a self-signed CA, server certificate, and client certificate for mTLS between the gateway and sandbox supervisors. + +## Wait for the gateway to be ready + +```shell +oc -n openshell rollout status statefulset/openshell +``` + +If you set `workload.kind=deployment`, use +`oc -n openshell rollout status deployment/openshell` instead. + + + +## Next steps + +- [Gateway connection](/kubernetes/openshift/gateway-connection) — connect the CLI to the gateway. +- [OIDC with Keycloak](/kubernetes/openshift/oidc-keycloak) — add user authentication. +- [Identity federation](/kubernetes/openshift/identity-federation) (optional) — if you want cluster users to log in with their OpenShift credentials instead of separate Keycloak accounts. +- For TLS certificate management with cert-manager, refer to [Managing Certificates](/kubernetes/managing-certificates). +- For the generic OIDC configuration reference, refer to [Access Control](/kubernetes/access-control). diff --git a/docs/kubernetes/openshift/oidc-keycloak.mdx b/docs/kubernetes/openshift/oidc-keycloak.mdx new file mode 100644 index 000000000..becb879b6 --- /dev/null +++ b/docs/kubernetes/openshift/oidc-keycloak.mdx @@ -0,0 +1,62 @@ +--- +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +title: "OIDC on OpenShift" +sidebar-title: "OIDC on OpenShift" +slug: "kubernetes/openshift/oidc-keycloak" +description: "Connect the OpenShell CLI to a Keycloak-authenticated gateway on OpenShift." +keywords: "Generative AI, Cybersecurity, Kubernetes, OpenShift, OIDC, Keycloak, Authentication, JWT" +position: 3 +--- + +This page covers the OpenShift-specific steps for connecting the CLI to a Keycloak-authenticated gateway. For the full Keycloak setup (realm, client, protocol mappers, roles), refer to the [Keycloak setup](/kubernetes/access-control#keycloak-setup) section of the Access Control guide. + +## Prerequisites + +- OpenShell [installed on OpenShift](/kubernetes/openshift/install) with TLS enabled +- Gateway [exposed externally](/kubernetes/openshift/gateway-connection) +- Keycloak realm and client configured per the [Keycloak setup](/kubernetes/access-control#keycloak-setup) guide + +## Configure the gateway + +Upgrade the Helm release with OIDC values: + +```shell +helm upgrade openshell oci://ghcr.io/nvidia/openshell/helm-chart \ + --version \ + --namespace openshell \ + --reuse-values \ + --set server.oidc.issuer=https://keycloak.example.com/realms/openshell \ + --set server.oidc.audience=openshell-cli \ + --set server.oidc.rolesClaim=realm_access.roles \ + --set server.oidc.adminRole=openshell-admin \ + --set server.oidc.userRole=openshell-user +``` + +Verify the gateway logs show OIDC is enabled: + +```shell +oc logs -f statefulset/openshell -n openshell | grep -i oidc +``` + +## Connect the CLI + + +Always pass `--oidc-issuer` when registering the gateway. Without it, the CLI defaults to the Cloudflare Access edge-auth flow, which hangs indefinitely on non-Cloudflare deployments. + + +```shell +openshell gateway add https:// \ + --gateway-insecure \ + --name openshift \ + --oidc-issuer https://keycloak.example.com/realms/openshell \ + --oidc-client-id openshell-cli \ + --oidc-audience openshell-cli +``` + +The browser opens to the Keycloak login page. After authentication, the CLI stores the OIDC token. + +## Next steps + +- [Identity federation](/kubernetes/openshift/identity-federation) (optional) — if you want cluster users to log in with their OpenShift credentials instead of separate Keycloak accounts. +- [Access Control](/kubernetes/access-control) — OIDC values reference, auth-only vs. RBAC mode, and provider-specific `rolesClaim` paths.