|
1 | 1 | --- |
2 | 2 | # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. |
3 | 3 | # SPDX-License-Identifier: Apache-2.0 |
4 | | -title: "OIDC with Keycloak" |
5 | | -sidebar-title: "OIDC with Keycloak" |
| 4 | +title: "OIDC on OpenShift" |
| 5 | +sidebar-title: "OIDC on OpenShift" |
6 | 6 | slug: "kubernetes/openshift/oidc-keycloak" |
7 | | -description: "Configure Keycloak as the OIDC provider for OpenShell on OpenShift, including the required protocol mappers and Helm values." |
| 7 | +description: "Connect the OpenShell CLI to a Keycloak-authenticated gateway on OpenShift." |
8 | 8 | keywords: "Generative AI, Cybersecurity, Kubernetes, OpenShift, OIDC, Keycloak, Authentication, JWT" |
9 | 9 | position: 3 |
10 | 10 | --- |
11 | 11 |
|
12 | | -The generic [Access Control](/kubernetes/access-control) guide covers OIDC configuration for any provider. This page covers Keycloak-specific setup on OpenShift, including the protocol mappers required for the gateway to validate access tokens. |
| 12 | +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. |
13 | 13 |
|
14 | 14 | ## Prerequisites |
15 | 15 |
|
16 | 16 | - OpenShell [installed on OpenShift](/kubernetes/openshift/install) with TLS enabled |
17 | | -- Keycloak instance accessible from the cluster |
18 | | -- Admin access to Keycloak |
19 | | - |
20 | | -## Create the realm and client |
21 | | - |
22 | | -Create a dedicated `openshell` realm and a public OIDC client for the CLI. |
23 | | - |
24 | | -<Note> |
25 | | -The `kcadm.sh` examples below use `KC_POD` and `KC_ADM` variables defined in the first code block. Set them once in your shell and reuse them for all subsequent commands. The `--config /tmp/kcadm.config` flag is required because the Keycloak container runs as non-root and cannot write to the default config path. |
26 | | -</Note> |
27 | | - |
28 | | -<Tabs> |
29 | | -<Tab title="kcadm.sh"> |
30 | | - |
31 | | -```shell |
32 | | -KC_POD="oc exec keycloak-0 -n keycloak --" |
33 | | -KC_ADM="/opt/keycloak/bin/kcadm.sh --config /tmp/kcadm.config" |
34 | | - |
35 | | -$KC_POD $KC_ADM config credentials \ |
36 | | - --server http://localhost:8080 \ |
37 | | - --realm master \ |
38 | | - --user <admin-user> \ |
39 | | - --password <admin-password> |
40 | | - |
41 | | -$KC_POD $KC_ADM create realms \ |
42 | | - -s realm=openshell \ |
43 | | - -s enabled=true |
44 | | - |
45 | | -$KC_POD $KC_ADM create clients -r openshell \ |
46 | | - -s clientId=openshell-cli \ |
47 | | - -s enabled=true \ |
48 | | - -s publicClient=true \ |
49 | | - -s directAccessGrantsEnabled=true \ |
50 | | - -s standardFlowEnabled=true \ |
51 | | - -s 'redirectUris=["http://localhost:*","http://127.0.0.1:*"]' \ |
52 | | - -s 'webOrigins=["http://localhost","http://127.0.0.1"]' \ |
53 | | - -s 'attributes={"pkce.code.challenge.method":"S256"}' |
54 | | -``` |
55 | | - |
56 | | -</Tab> |
57 | | -<Tab title="REST API"> |
58 | | - |
59 | | -```shell |
60 | | -KC_URL=https://keycloak.example.com |
61 | | - |
62 | | -TOKEN=$(curl -sk "${KC_URL}/realms/master/protocol/openid-connect/token" \ |
63 | | - -d "client_id=admin-cli" \ |
64 | | - -d "username=<admin-user>" \ |
65 | | - -d "password=<admin-password>" \ |
66 | | - -d "grant_type=password" | jq -r .access_token) |
67 | | - |
68 | | -curl -sk -X POST "${KC_URL}/admin/realms" \ |
69 | | - -H "Authorization: Bearer $TOKEN" \ |
70 | | - -H "Content-Type: application/json" \ |
71 | | - -d '{"realm":"openshell","enabled":true}' |
72 | | - |
73 | | -curl -sk -X POST "${KC_URL}/admin/realms/openshell/clients" \ |
74 | | - -H "Authorization: Bearer $TOKEN" \ |
75 | | - -H "Content-Type: application/json" \ |
76 | | - -d '{ |
77 | | - "clientId": "openshell-cli", |
78 | | - "enabled": true, |
79 | | - "publicClient": true, |
80 | | - "directAccessGrantsEnabled": true, |
81 | | - "standardFlowEnabled": true, |
82 | | - "redirectUris": ["http://localhost:*", "http://127.0.0.1:*"], |
83 | | - "webOrigins": ["http://localhost", "http://127.0.0.1"], |
84 | | - "attributes": {"pkce.code.challenge.method": "S256"} |
85 | | - }' |
86 | | -``` |
87 | | - |
88 | | -</Tab> |
89 | | -</Tabs> |
90 | | - |
91 | | -## Add required protocol mappers |
92 | | - |
93 | | -Keycloak does not include `sub`, `aud`, or realm roles in access tokens for public clients by default. Without these claims, the gateway rejects tokens with errors like `missing field 'sub'`, audience mismatch, or `role 'openshell-user' required`. |
94 | | - |
95 | | -Add three protocol mappers to the `openshell-cli` client: |
96 | | - |
97 | | -| Mapper name | Mapper type | Key config | |
98 | | -|---|---|---| |
99 | | -| `sub` | Subject (sub) | access.token.claim: true | |
100 | | -| `openshell-audience` | Audience | included.client.audience: `openshell-cli` | |
101 | | -| `realm-roles` | User Realm Role | claim.name: `realm_access.roles`, multivalued: true | |
102 | | - |
103 | | -Add these via the Keycloak admin console under **Clients → openshell-cli → Client scopes → Dedicated scope → Add mapper**, or via the CLI/API: |
104 | | - |
105 | | -<Tabs> |
106 | | -<Tab title="kcadm.sh"> |
107 | | - |
108 | | -```shell |
109 | | -CLIENT_UUID=$($KC_POD $KC_ADM get clients -r openshell \ |
110 | | - -q clientId=openshell-cli --fields id --format csv --noquotes) |
111 | | - |
112 | | -$KC_POD $KC_ADM create clients/$CLIENT_UUID/protocol-mappers/models -r openshell \ |
113 | | - -s name=sub \ |
114 | | - -s protocol=openid-connect \ |
115 | | - -s protocolMapper=oidc-sub-mapper \ |
116 | | - -s 'config={"access.token.claim":"true","id.token.claim":"true"}' |
117 | | - |
118 | | -$KC_POD $KC_ADM create clients/$CLIENT_UUID/protocol-mappers/models -r openshell \ |
119 | | - -s name=openshell-audience \ |
120 | | - -s protocol=openid-connect \ |
121 | | - -s protocolMapper=oidc-audience-mapper \ |
122 | | - -s 'config={"included.client.audience":"openshell-cli","access.token.claim":"true","id.token.claim":"true"}' |
123 | | - |
124 | | -$KC_POD $KC_ADM create clients/$CLIENT_UUID/protocol-mappers/models -r openshell \ |
125 | | - -s name=realm-roles \ |
126 | | - -s protocol=openid-connect \ |
127 | | - -s protocolMapper=oidc-usermodel-realm-role-mapper \ |
128 | | - -s 'config={"claim.name":"realm_access.roles","jsonType.label":"String","multivalued":"true","access.token.claim":"true","id.token.claim":"true","userinfo.token.claim":"true"}' |
129 | | -``` |
130 | | - |
131 | | -</Tab> |
132 | | -<Tab title="REST API"> |
133 | | - |
134 | | -```shell |
135 | | -CLIENT_UUID=$(curl -sk "${KC_URL}/admin/realms/openshell/clients?clientId=openshell-cli" \ |
136 | | - -H "Authorization: Bearer $TOKEN" | jq -r '.[0].id') |
137 | | - |
138 | | -for MAPPER in \ |
139 | | - '{"name":"sub","protocol":"openid-connect","protocolMapper":"oidc-sub-mapper","config":{"access.token.claim":"true","id.token.claim":"true"}}' \ |
140 | | - '{"name":"openshell-audience","protocol":"openid-connect","protocolMapper":"oidc-audience-mapper","config":{"included.client.audience":"openshell-cli","access.token.claim":"true","id.token.claim":"true"}}' \ |
141 | | - '{"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 |
142 | | - curl -sk -X POST "${KC_URL}/admin/realms/openshell/clients/${CLIENT_UUID}/protocol-mappers/models" \ |
143 | | - -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$MAPPER" |
144 | | -done |
145 | | -``` |
146 | | - |
147 | | -</Tab> |
148 | | -</Tabs> |
149 | | - |
150 | | -## Create realm roles |
151 | | - |
152 | | -<Tabs> |
153 | | -<Tab title="kcadm.sh"> |
154 | | - |
155 | | -```shell |
156 | | -$KC_POD $KC_ADM create roles -r openshell -s name=openshell-user |
157 | | -$KC_POD $KC_ADM create roles -r openshell -s name=openshell-admin |
158 | | -``` |
159 | | - |
160 | | -</Tab> |
161 | | -<Tab title="REST API"> |
162 | | - |
163 | | -```shell |
164 | | -curl -sk -X POST "${KC_URL}/admin/realms/openshell/roles" \ |
165 | | - -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ |
166 | | - -d '{"name":"openshell-user"}' |
167 | | - |
168 | | -curl -sk -X POST "${KC_URL}/admin/realms/openshell/roles" \ |
169 | | - -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \ |
170 | | - -d '{"name":"openshell-admin"}' |
171 | | -``` |
172 | | - |
173 | | -</Tab> |
174 | | -</Tabs> |
175 | | - |
176 | | -Assign `openshell-user` to users who need sandbox access and `openshell-admin` to administrators through the Keycloak admin console or API. |
| 17 | +- Gateway [exposed externally](/kubernetes/openshift/gateway-connection) |
| 18 | +- Keycloak realm and client configured per the [Keycloak setup](/kubernetes/access-control#keycloak-setup) guide |
177 | 19 |
|
178 | 20 | ## Configure the gateway |
179 | 21 |
|
|
0 commit comments