Skip to content

Commit 424bf00

Browse files
committed
docs(openshift): expand OpenShift guide into multi-page section
Replace the single-page plaintext-only OpenShift guide with a section containing four sub-pages: - install: TLS-enabled installation with SCC overrides - external-access: reencrypt Route and Gateway API (Istio) options - oidc-keycloak: Keycloak OIDC setup with required protocol mappers - identity-federation: OpenShift OAuth as a Keycloak identity provider Addresses NVIDIA#2091 Signed-off-by: Akram <[email protected]>
1 parent 474d2d4 commit 424bf00

6 files changed

Lines changed: 491 additions & 95 deletions

File tree

‎docs/kubernetes/openshift.mdx‎

Lines changed: 0 additions & 95 deletions
This file was deleted.
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
---
2+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
title: "External Access"
5+
sidebar-title: "External Access"
6+
slug: "kubernetes/openshift/external-access"
7+
description: "Expose the OpenShell gateway on OpenShift using a reencrypt Route or the Kubernetes Gateway API."
8+
keywords: "Generative AI, Cybersecurity, Kubernetes, OpenShift, Route, Gateway API, Istio, gRPC, Ingress"
9+
position: 2
10+
---
11+
12+
The gateway multiplexes gRPC and HTTP on a single port. External access must preserve HTTP/2 for gRPC to work. OpenShift offers two paths:
13+
14+
| Method | HTTP/2 | Config complexity | Dependencies |
15+
|---|---|---|---|
16+
| [Reencrypt Route](#reencrypt-route) | Via annotation | Low (2 commands) | None |
17+
| [Gateway API](#gateway-api-with-istio) | Native | Medium (3 YAML resources) | Istio / Gateway API controller |
18+
19+
## Why not edge or passthrough?
20+
21+
| Route type | Problem |
22+
|---|---|
23+
| Edge | Terminates TLS and forces HTTP/1.1 to the backend, breaking gRPC. |
24+
| Passthrough | Preserves HTTP/2 but exposes the gateway's mTLS client certificate requirement to browsers, causing `ERR_BAD_SSL_CLIENT_AUTH_CERT`. |
25+
26+
## Reencrypt Route
27+
28+
A reencrypt route terminates external TLS at the OpenShift router, then re-establishes TLS to the gateway backend. The `backend-protocol=h2` annotation tells HAProxy to use HTTP/2 for the backend connection.
29+
30+
```shell
31+
DEST_CA=$(oc get secret openshell-server-tls -n openshell \
32+
-o jsonpath='{.data.ca\.crt}' | base64 -d)
33+
34+
oc create route reencrypt openshell \
35+
--service=openshell --port=8080 \
36+
--dest-ca-cert=<(echo "$DEST_CA") \
37+
-n openshell
38+
39+
oc annotate route openshell -n openshell \
40+
haproxy.router.openshift.io/backend-protocol=h2 --overwrite
41+
```
42+
43+
Register the gateway with the CLI using the route hostname:
44+
45+
```shell
46+
oc get route openshell -n openshell -o jsonpath='{.spec.host}'
47+
openshell gateway add https://<route-hostname> --gateway-insecure --name openshift
48+
```
49+
50+
## Gateway API with Istio
51+
52+
OpenShift manages the Gateway API CRDs through the Ingress Operator. The standard [Envoy Gateway](/kubernetes/ingress) cannot be installed because the Ingress Operator rejects third-party Gateway API CRD installations. Instead, use the OpenShift-managed Istio-based Gateway controller.
53+
54+
<Steps>
55+
56+
## Identify the GatewayClass
57+
58+
```shell
59+
oc get gatewayclass
60+
```
61+
62+
Look for a class with an Istio-based controller (e.g. `istio` or `data-science-gateway-class`). The class must show `ACCEPTED: True`.
63+
64+
## Create the Gateway and GRPCRoute
65+
66+
```shell
67+
kubectl apply -f - <<'EOF'
68+
apiVersion: gateway.networking.k8s.io/v1
69+
kind: Gateway
70+
metadata:
71+
name: openshell-gateway
72+
namespace: openshell
73+
spec:
74+
gatewayClassName: istio
75+
listeners:
76+
- name: grpc
77+
protocol: HTTPS
78+
port: 443
79+
tls:
80+
mode: Terminate
81+
certificateRefs:
82+
- name: openshell-server-tls
83+
kind: Secret
84+
allowedRoutes:
85+
namespaces:
86+
from: Same
87+
---
88+
apiVersion: gateway.networking.k8s.io/v1
89+
kind: GRPCRoute
90+
metadata:
91+
name: openshell
92+
namespace: openshell
93+
spec:
94+
parentRefs:
95+
- name: openshell-gateway
96+
namespace: openshell
97+
rules:
98+
- backendRefs:
99+
- name: openshell
100+
port: 8080
101+
EOF
102+
```
103+
104+
## Configure TLS to the backend
105+
106+
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:
107+
108+
```shell
109+
kubectl apply -f - <<'EOF'
110+
apiVersion: networking.istio.io/v1
111+
kind: DestinationRule
112+
metadata:
113+
name: openshell-tls-origination
114+
namespace: openshell
115+
spec:
116+
host: openshell.openshell.svc.cluster.local
117+
trafficPolicy:
118+
tls:
119+
mode: SIMPLE
120+
insecureSkipVerify: true
121+
EOF
122+
```
123+
124+
## Get the external address
125+
126+
The Gateway controller creates a LoadBalancer service. Wait for the external address:
127+
128+
```shell
129+
oc get gateway openshell-gateway -n openshell \
130+
-o jsonpath='{.status.addresses[0].value}'
131+
```
132+
133+
<Note>
134+
AWS ELB DNS names can take 1-2 minutes to propagate after creation.
135+
</Note>
136+
137+
## Register the gateway
138+
139+
```shell
140+
openshell gateway add https://<external-address> --gateway-insecure --name openshift
141+
```
142+
143+
</Steps>
144+
145+
## Next steps
146+
147+
- [OIDC with Keycloak](/kubernetes/openshift/oidc-keycloak) — add `--oidc-issuer` to the `gateway add` command for authenticated access.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
title: "OpenShift Identity Federation"
5+
sidebar-title: "Identity Federation"
6+
slug: "kubernetes/openshift/identity-federation"
7+
description: "Configure Keycloak to delegate authentication to the OpenShift OAuth server so cluster users can log in with their existing credentials."
8+
keywords: "Generative AI, Cybersecurity, Kubernetes, OpenShift, Keycloak, Identity Federation, OAuth, SSO"
9+
position: 4
10+
---
11+
12+
Keycloak can delegate authentication to the OpenShift OAuth server so users log in with their cluster credentials instead of separate Keycloak accounts. Users are auto-imported into the Keycloak realm on first login.
13+
14+
## Prerequisites
15+
16+
- [OIDC with Keycloak](/kubernetes/openshift/oidc-keycloak) configured and working
17+
- `cluster-admin` access to create `OAuthClient` resources
18+
19+
## Create an OAuthClient in OpenShift
20+
21+
Generate a client secret and create the `OAuthClient` that Keycloak uses to initiate the OAuth flow:
22+
23+
```shell
24+
OCP_SECRET=$(openssl rand -hex 32)
25+
KC_URL=https://keycloak.example.com
26+
27+
cat <<EOF | oc apply -f -
28+
apiVersion: oauth.openshift.io/v1
29+
kind: OAuthClient
30+
metadata:
31+
name: keycloak-openshell
32+
secret: "${OCP_SECRET}"
33+
grantMethod: auto
34+
redirectURIs:
35+
- "${KC_URL}/realms/openshell/broker/openshift/endpoint"
36+
EOF
37+
```
38+
39+
## Add OpenShift as a Keycloak identity provider
40+
41+
```shell
42+
TOKEN=$(curl -sk "${KC_URL}/realms/master/protocol/openid-connect/token" \
43+
-d "client_id=admin-cli" \
44+
-d "username=<admin-user>" \
45+
-d "password=<admin-password>" \
46+
-d "grant_type=password" | jq -r .access_token)
47+
48+
curl -sk -X POST "${KC_URL}/admin/realms/openshell/identity-provider/instances" \
49+
-H "Authorization: Bearer $TOKEN" \
50+
-H "Content-Type: application/json" \
51+
-d "{
52+
\"alias\": \"openshift\",
53+
\"displayName\": \"OpenShift\",
54+
\"providerId\": \"openshift-v4\",
55+
\"enabled\": true,
56+
\"trustEmail\": true,
57+
\"firstBrokerLoginFlowAlias\": \"first broker login\",
58+
\"config\": {
59+
\"clientId\": \"keycloak-openshell\",
60+
\"clientSecret\": \"${OCP_SECRET}\",
61+
\"baseUrl\": \"$(oc whoami --show-server)\",
62+
\"defaultScope\": \"user:info\",
63+
\"syncMode\": \"IMPORT\"
64+
}
65+
}"
66+
```
67+
68+
<Note>
69+
**ROSA HCP**: set `baseUrl` to the API server URL (`https://api.<cluster>:443`), not the OAuth route (`oauth.<cluster>`). On ROSA HCP, the OAuth metadata endpoint (`/.well-known/oauth-authorization-server`) is served by the API server. The OAuth route returns 404.
70+
</Note>
71+
72+
## Assign roles to federated users
73+
74+
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:
75+
76+
**Keycloak Admin Console → Users → select user → Role Mappings → Assign role → openshell-user**
77+
78+
Or via the API:
79+
80+
```shell
81+
USER_ID=$(curl -sk "${KC_URL}/admin/realms/openshell/users?username=<openshift-username>&exact=true" \
82+
-H "Authorization: Bearer $TOKEN" | jq -r '.[0].id')
83+
84+
ROLE_ID=$(curl -sk "${KC_URL}/admin/realms/openshell/roles/openshell-user" \
85+
-H "Authorization: Bearer $TOKEN" | jq -r '.id')
86+
87+
curl -sk -X POST "${KC_URL}/admin/realms/openshell/users/${USER_ID}/role-mappings/realm" \
88+
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
89+
-d "[{\"id\":\"${ROLE_ID}\",\"name\":\"openshell-user\"}]"
90+
```
91+
92+
## Result
93+
94+
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.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
title: "OpenShift"
5+
sidebar-title: "OpenShift"
6+
slug: "kubernetes/openshift"
7+
description: "Deploy the OpenShell gateway on OpenShift with TLS, external access, and OIDC authentication."
8+
keywords: "Generative AI, Cybersecurity, Kubernetes, OpenShift, SCC, Security Context Constraints, Helm, Gateway, Installation, OIDC, Keycloak"
9+
position: 5
10+
---
11+
12+
<Warning>
13+
The OpenShift install path is experimental. It currently requires running sandbox pods under the `privileged` SCC. Use only for evaluation on a private network.
14+
</Warning>
15+
16+
Deploy the OpenShell gateway on OpenShift with Security Context Constraints, external access via Routes or Gateway API, and OIDC authentication with Keycloak.
17+
18+
<Cards>
19+
20+
<Card title="Install" href="/kubernetes/openshift/install">
21+
22+
Install the gateway with TLS enabled, configure the SCC binding, and verify the deployment.
23+
</Card>
24+
25+
<Card title="External Access" href="/kubernetes/openshift/external-access">
26+
27+
Expose the gateway externally using a reencrypt Route or the Kubernetes Gateway API with Istio.
28+
</Card>
29+
30+
<Card title="OIDC with Keycloak" href="/kubernetes/openshift/oidc-keycloak">
31+
32+
Configure Keycloak as the OIDC provider, set up the required protocol mappers, and connect the CLI.
33+
</Card>
34+
35+
<Card title="OpenShift Identity Federation" href="/kubernetes/openshift/identity-federation">
36+
37+
Let cluster users log in with their OpenShift credentials via Keycloak identity federation.
38+
</Card>
39+
40+
</Cards>

0 commit comments

Comments
 (0)