Skip to content
This repository was archived by the owner on Jan 13, 2026. It is now read-only.

Commit eb2ee14

Browse files
dlaloue-vmwareDimitri Laloueantgamdia
authored
added keycloak doc (#4414)
* added keycloak doc * Update docs/user/OIDC/OAuth2OIDC-keycloak.md Co-authored-by: Dr. Antonio Gámez <antgamdia@gmail.com> * Update docs/user/OIDC/OAuth2OIDC-keycloak.md Co-authored-by: Dr. Antonio Gámez <antgamdia@gmail.com> * Update docs/user/OIDC/OAuth2OIDC-keycloak.md Co-authored-by: Dr. Antonio Gámez <antgamdia@gmail.com> * Update docs/user/OIDC/OAuth2OIDC-keycloak.md Co-authored-by: Dr. Antonio Gámez <antgamdia@gmail.com> * Update docs/user/OIDC/OAuth2OIDC-keycloak.md Co-authored-by: Dr. Antonio Gámez <antgamdia@gmail.com> * Update docs/user/OIDC/OAuth2OIDC-keycloak.md Co-authored-by: Dr. Antonio Gámez <antgamdia@gmail.com> * Update docs/user/OIDC/OAuth2OIDC-keycloak.md Co-authored-by: Dr. Antonio Gámez <antgamdia@gmail.com> * Update docs/user/OIDC/OAuth2OIDC-keycloak.md Co-authored-by: Dr. Antonio Gámez <antgamdia@gmail.com> * minor enhancements * Update docs/user/OIDC/OAuth2OIDC-keycloak.md Co-authored-by: Dr. Antonio Gámez <antgamdia@gmail.com> * Update docs/user/OIDC/OAuth2OIDC-keycloak.md Co-authored-by: Dr. Antonio Gámez <antgamdia@gmail.com> * minor enhancements Co-authored-by: Dimitri Laloue <dlaloue@dlaloue-a01.vmware.com> Co-authored-by: Dr. Antonio Gámez <antgamdia@gmail.com>
1 parent 4d22a21 commit eb2ee14

1 file changed

Lines changed: 310 additions & 5 deletions

File tree

Lines changed: 310 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,314 @@
11
# Configuring Keycloak as an OIDC provider
22

3-
This document explains how to configure Keycloak as an OIDC provider (check general information and pre-requisites for [using an OAuth2/OIDC Provider with Kubeapps](../using-an-OIDC-provider.md)).
3+
This document explains how to configure Keycloak as an IDP + OIDC provider (check general information and pre-requisites for [using an OAuth2/OIDC Provider with Kubeapps](../using-an-OIDC-provider.md)).
4+
It covers the installation and documentation for Kubeapps interacting with two Kubernetes clusters.
45

5-
In the case of Keycloak, you can find the parameters in the Keycloak admin console:
6+
The installation used the [bitnami chart for Keycloak](https://github.com/bitnami/charts/tree/master/bitnami/keycloak) (version 12.0.4/2.4.8) and [bitnami chart for Kubeapps](https://github.com/bitnami/charts/tree/master/bitnami/kubeapps) (version 7.0.0/2.3.2)
67

7-
- **Client-ID**: Keycloak client ID.
8-
- **Client-secret**: Secret associated to the client above.
9-
- **OIDC Issuer URL**: `https://<keycloak.domain>/auth/realms/<realm>`.
8+
# Keycloak Installation
9+
10+
## SSL
11+
12+
In order to support OIDC or OAuth, most servers and proxies require HTTPS. By default, the certificate created by the helm chart / Keycloak server is both invalid (error with `notBefore` attribute) and also based on a deprecated certificate version making it incompatible to use (i.e. is it based on Common Name instead of SAN and is rejected).
13+
14+
In this section, we will see how to configure Keycloak with its `auth.tls` enabled. Note that there are other options to configure TLS, for example via ingress TLS, either manually or using a cert manager. This section will focus on TLS at the server level.
15+
16+
Keycloak is a java-based server and is using JDK keystore/truststore. Both a keystore and a truststore must be created or the helm installation will fail. The keystore and truststore must then be installed on the cluster as a k8s Secret.
17+
18+
#### Step 1: create private key + certificate
19+
20+
The certificate must be a SAN certificate and should be capable of using wildcard alternative names. Keytool which is typically used for creating certificates does not support SANs with wildcards and is also using jks by default. We will use openssl instead.
21+
22+
To create the certificate, it is useful to create a openssl config file, something like the following (_certificate.config_):
23+
```properties
24+
[req]
25+
default_bits = 2048
26+
distinguished_name = req_dn
27+
x509_extensions = req_ext
28+
29+
[req_dn]
30+
countryName = Country Name (2 letter code)
31+
countryName_default = US
32+
stateOrProvinceName = State or Province Name (full name)
33+
stateOrProvinceName_default = CA
34+
localityName = Locality Name (eg, city)
35+
localityName_default = Campbell
36+
organizationName = Organization Name (eg, company)
37+
organizationName_default = vmware.com
38+
commonName = Common Name (e.g. server FQDN or YOUR name)
39+
commonName_default = keycloak
40+
41+
[req_ext]
42+
subjectAltName = @alt_names
43+
44+
[alt_names]
45+
DNS.1 = *.us-east-2.elb.amazonaws.com
46+
```
47+
48+
The important section of the config is the `[req_ext]` extension section with alternate names. As the load balancer URL is created during installation, we use the wildcard mechanism so the final hostname can be verified by the certificates (here `DNS.1` illustrates a cluster on AWS). Other hostnames, e.g. localhost, can also be added following the numbers pattern (`DNS.x`).
49+
50+
The following command will generate the private key and certificate files:
51+
52+
```shell
53+
openssl req \
54+
-newkey rsa:2048 -nodes -keyout certificate.key \
55+
-x509 -days 365 -config certificate.config -out certificate.crt
56+
```
57+
58+
#### Step 2: create the keystore and truststore
59+
60+
Creating the keystore is done in two steps, starting by creating a pkcs12 keystore and then importing it using keytool (this will require a password, that we will need in the helm values.yaml):
61+
62+
```shell
63+
openssl pkcs12 -export -in certificate.crt -inkey certificate.key -name keycloak -out certificate.p12
64+
65+
keytool -importkeystore -srckeystore certificate.p12 -srcstoretype pkcs12 -destkeystore keycloak-0.keystore.jks -alias keycloak
66+
```
67+
68+
Then we need to create the truststore:
69+
```shell
70+
keytool -import -alias keycloak -file certificate.crt -keystore keycloak.truststore.jks
71+
```
72+
73+
#### Step 3: create a k8s secret
74+
75+
The last step is to create a secret in the namespace where Keycloak will be installed.
76+
77+
Note that the names of the keystore and truststore matters and must be exactly as written here (make sure to rename them if the names have been changed in the commands in Step 2):
78+
79+
```shell
80+
kubectl create secret generic keycloak-tls --from-file=./keycloak-0.keystore.jks --from-file=./keycloak.truststore.jks
81+
```
82+
83+
## Helm Install
84+
85+
To provide a default install, not many values must be provided in the values file - the values are mostly default passwords and the name of the secret created in Step 3 above.
86+
87+
Here is the `my-values.yaml` file that was applied when installing the Helm Chart:
88+
89+
```yaml
90+
## Keycloak authentication parameters
91+
## ref: https://github.com/bitnami/bitnami-docker-keycloak#admin-credentials
92+
##
93+
auth:
94+
95+
## Create administrator user on boot.
96+
##
97+
createAdminUser: true
98+
99+
## Keycloak administrator user and password
100+
##
101+
adminUser: admin
102+
adminPassword: Vmware!23
103+
104+
## Wildfly management user and password
105+
##
106+
managementUser: manager
107+
managementPassword: Vmware!23
108+
109+
## TLS encryption parameters
110+
## ref: https://github.com/bitnami/bitnami-docker-keycloak#tls-encryption
111+
##
112+
tls:
113+
enabled: true
114+
115+
## Name of the existing secret containing the truststore and one keystore per Keycloak replica
116+
##
117+
jksSecret: keycloak-tls
118+
119+
## Password to access the keystore when it's password-protected.
120+
##
121+
keystorePassword: Vmware!23
122+
## Password to access the truststore when it's password-protected.
123+
##
124+
truststorePassword: Vmware!23
125+
```
126+
127+
Then just deploy Keycloak either using Kubeapps UI or helm cli as follows:
128+
```shell
129+
helm install keycloak bitnami/keycloak --values my-values.yaml
130+
```
131+
132+
133+
# Keycloak Configuration
134+
135+
Follow the [Keycloak documentation](https://www.keycloak.org/documentation) to create and configure a new Realm to work with.
136+
137+
This section will focus on a few aspects to configure for the SSO scenario to work.
138+
139+
## Groups Claim
140+
141+
By default, there is no "groups" scope/claim. We will create a global client scope for groups.
142+
143+
In the admin console:
144+
- Click “Client Scopes” from the left navigator menu
145+
- Click on “Create” from the table (top right corner)
146+
- Provide a name, ensure the protocol is set to “openid-connect” and that the option “Include in Token Scope” is on.
147+
148+
Once the client scope is created, you should be redirected to a page with several tabs. Navigate to the “Mappers” tab as we need to create a mapper to populate the value of the associated claim:
149+
- Click on the “Mappers” tab
150+
- Click on “Create” from the table to create a new mapper
151+
- Configure:
152+
- Enter a name
153+
- Select “Group Membership” as the claim type
154+
- Enter “groups” as the token claim name
155+
- Ensure the “Full group path” is OFF
156+
- Keep the other knobs as ON
157+
- Click ‘Save’
158+
159+
Note: if you navigate to “Client Scopes” and then select the tab “Default Client Scopes” you should be able to see the newly created “groups” scope in the “available client scopes” lists.
160+
161+
## Clients
162+
163+
In probably a very simplified view, Clients represent the application to be protected and accessed via SSO and OIDC. Here, the environment consisted of the Kubeapps web app and two Kubernetes clusters. So we need to create three clients.
164+
165+
### Cluster clients
166+
167+
For each of the two Kubernetes clusters, we will create a client as follows:
168+
- Click “Clients” from the left navigator
169+
- Click “Create” from the table
170+
- Enter an “id” and Save (for example, `cluster1`and `cluster2` respectively)
171+
172+
Once created, configure the authentication as follows:
173+
- Ensure the protocol is set to “openid-connect”
174+
- Configure the “Access Type” to be “confidential”. This will add a new “Credentials” tab from which you can get the client secret
175+
- If you just want to use tokens to access the cluster, you can disable the “Standard Flow Enabled”. Keep this option if you plan to use a local browser login screen (e.g. if using pinniped cli).
176+
- Ensure “Direct Access Grants Enabled” is enabled, as this is how we can get the tokens via API.
177+
- Save
178+
179+
You then need to configure the client scopes that will be available:
180+
- Click the “Client Scopes” tab
181+
- Ensure the “email” scope is available either in the “Assigned Default Client Scopes” list or the “Assigned Optional Client Scopes” list
182+
- The “groups” client scope should be available in the lists on the left. Add it either to the “Assigned Default Client Scopes” list or the “Assigned Optional Client Scopes” list.
183+
184+
### Kubeapps client
185+
186+
We need to first create the client:
187+
- Click “Clients” from the left navigator
188+
- Click “Create” from the table
189+
- Enter an “id” and Save (e.g. `kubeapps`)
190+
191+
Once created, configure the authentication as follows:
192+
- Ensure the protocol is set to “openid-connect”
193+
- Configure the “Access Type” to be “confidential”. This will add a new “Credentials” tab from which you can get the client secret
194+
- Ensure “Standard Flow Enabled” is enabled, this is required for the login screen.
195+
- “Direct Access Grants Enabled” can be disabled.
196+
- In the “Valid Redirect URIs” field, enter “http://localhost:8000/*” as a placeholder. We will need to revisit this field once we know the public hostname of kubeapps
197+
- Save
198+
199+
As for the cluster clients, we need to configure the client scopes:
200+
- Click the “Client Scopes” tab
201+
- Ensure the “email” scope is available either in the “Assigned Default Client Scopes” list or the “Assigned Optional Client Scopes” list
202+
- The “groups” client scope should be available in the lists on the left. Add it either to the “Assigned Default Client Scopes” list or the “Assigned Optional Client Scopes” list.
203+
204+
The last step is to configure the `kubeapps` client to be aware of the two cluster clients and be allowed to invoke them. There are different ways to configure Keycloak:
205+
- Using automatic audience resolution. We haven't explored this method yet, therefore it won't be covered in this guide.
206+
- Via Client Scopes: define the cluster clients as Client Scopes and add them to `kubeapps`.
207+
- Via Mappers in the client: define a mapper attached to the `kubeapps` client that will inject the client ids in th audience claim.
208+
209+
#### Option #2
210+
211+
In this option, we create a client scope similar to how we created the groups client scope. This solution is better than solution #3 as the client ids are injected in the audience claim only if they were asked for in the scope request field.
212+
- Click “Client Scopes” from the left navigator menu
213+
- Click on “Create” from the table (top right corner)
214+
- Provide a name (e.g. `cluster1-client`), ensure the protocol is set to “openid-connect” and that the option “Include in Token Scope” is on.
215+
- Click the Mappers tab
216+
- Click Create from the table to create a new mapper
217+
- Enter a name
218+
- Select the mapper type “Audience”
219+
- In “Included Client Audience” select the cluster client created above (e.g. `cluster1`)
220+
- Ensure “Add to ID token” is enabled
221+
- Save
222+
- Repeat for the second cluster
223+
224+
Then in the `kubeapps` client:
225+
- Navigate to the “Client Scope” tab
226+
- The two new scopes created above should be available in the lists on the left. You can choose to add them to either the default list or the optional list.
227+
228+
#### Option #3
229+
230+
In this option, the claim is statically defined via a mapper similar to the one created in option #2.
231+
- Navigate to the Mappers tab of the `kubeapps` client
232+
- Click Create from the table
233+
- Enter a name
234+
- For Mapper Type select “Audience”
235+
- In “Included Client Audience” select the cluster client(e.g. `cluster1`)
236+
- Ensure “Add to ID token” is enabled
237+
- Save
238+
- Repeat for the second cluster
239+
240+
The two client ids will be injected in the audience claim automatically.
241+
242+
## Users
243+
244+
Users are intuitive to create. But they must be configured with a “verified” email address.
245+
246+
The oauth proxy used in kubeapps requires email as the username. Furthermore, if the email is not marked as verified, JWT validation will fail and authentication will fail.
247+
248+
In order to test multiple users with different levels of authorization, it is useful to create them with multiple dummy email addresses. This can be done by ensuring that when the user is created, the field “email verified” is ON (skipping an actual email verification workflow).
249+
250+
# Kubeapps Installation
251+
252+
## Helm Install
253+
254+
Few changes are required to values.yaml for the helm installation:
255+
- The `frontend` service type is set to LoadBalancer so we can have a public hostname for the callback. Using an ingress could be another alternative.
256+
- The auth proxy must be configured. Here we will be using the default one.
257+
- the `provider` field must be set to oidc
258+
- The `clientID` and `clientSecret` field values can be retrieved from the `kubeapps` client in Keycloak
259+
- the flag `--oidc-issuer-url` is the url to the Keycloak realm
260+
261+
The following excerpt shows the relevant values used in values.yaml when installing the Helm Chart:
262+
263+
```yaml
264+
## Frontend parameters
265+
##
266+
frontend:
267+
service:
268+
type: LoadBalancer
269+
270+
271+
272+
# Auth Proxy configuration for OIDC support
273+
# ref: https://github.com/kubeapps/kubeapps/blob/master/docs/user/using-an-OIDC-provider.md
274+
authProxy:
275+
## Set to true if Kubeapps should configure the OAuth login/logout URIs defined below.
276+
#
277+
enabled: true
278+
279+
## Skip the Kubeapps login page when using OIDC and directly redirect to the IdP
280+
##
281+
skipKubeappsLoginPage: false
282+
283+
## Mandatory parameters for the internal auth-proxy.
284+
## those are the client id and secret from the oidc provider
285+
provider: oidc
286+
clientID: kubeapps
287+
clientSecret: 5b824b57-dc17-4ac8-8043-947d5edcfb03
288+
289+
## cookieSecret is used by oauth2-proxy to encrypt any credentials so that it requires
290+
## no storage. Note that it must be a particular number of bytes. Recommend using the
291+
## following to generate a cookieSecret as per the oauth2 configuration documentation
292+
## at https://pusher.github.io/oauth2_proxy/configuration :
293+
## python -c 'import os,base64; print base64.urlsafe_b64encode(os.urandom(16))'
294+
cookieSecret: Y29va2llLXNlY3JldC0xNg==
295+
## Use "example.com" to restrict logins to emails from example.com
296+
emailDomain: "*"
297+
## Additional flags for oauth2-proxy
298+
##
299+
additionalFlags:
300+
- --ssl-insecure-skip-verify
301+
- --cookie-secure=false
302+
- --scope=openid email groups
303+
- --oidc-issuer-url=https://<xxx>.us-east-2.elb.amazonaws.com/auth/realms/AWS
304+
```
305+
306+
## Configuration
307+
308+
Once Kubeapps is installed and the load balancer is ready, we need to go back to Keycloak to configure the callback URL:
309+
- Navigate to the `kubeapps` Client
310+
- In the “Valid Redirect URIs” enter the callback URL for Kubeapps. It will be of the form “http://`<hostname>`/oauth2/callback” (where `<hostname>` is the load balancer hostname)
311+
312+
## Users
313+
314+
Users created in Keycloak will be authenticated but they will not have access to the cluster resources by default. Make sure to create role bindings to users and/or groups in both clusters.

0 commit comments

Comments
 (0)