This manual explains how to configure a custom OIDC provider to use with Kubermatic Kubernetes Platform (KKP).
When nothing is configured, KKP uses https://<domain>/dex as the OIDC provider
URL, which by default points to Dex. The domain is taken from the
KubermaticConfiguration.
Login into the KKP dashboard uses the OAuth Authorization Code flow with PKCE. The flow is
driven by the KKP API, not by the browser: when the user clicks Sign in on the KKP login
page, the browser is sent to https://<domain>/api/v2/auth/login, which redirects to the OIDC
provider with the following parameters:
&response_type is set to code&client_id is set to the value of spec.auth.issuerClientID (defaults to kubermaticIssuer)&redirect_uri is set to https://<domain>/api/v2/auth/callback&scope is set to openid email profile groups offline_access&state is a randomly generated string to protect against CSRF&nonce is a randomly generated string to prevent replay attacks&code_challenge and &code_challenge_method=S256 implement PKCEThe authorization code is exchanged for tokens by the KKP API in a server-to-server call. The
resulting tokens are stored in HttpOnly and Secure cookies and are never exposed to
JavaScript in the browser. A refresh token is used to renew the session silently before the ID
token expires.
Your OIDC client must be a confidential client (client authentication enabled) and must have
https://<domain>/api/v2/auth/callback registered as a valid redirect URI. Without the
offline_access scope no refresh token is issued and users are logged out as soon as the ID
token expires.
The default configuration can be changed as KKP supports other OIDC providers as well. This
involves updating the KKP dashboard and API using the KubermaticConfiguration CRD on the
master cluster. The used configuration can be retrieved using kubectl:
kubectl -n kubermatic get kubermaticconfigurations
#NAME AGE
#kubermatic 2h
kubectl -n kubermatic get kubermaticconfiguration kubermatic -o yaml
#apiVersion: kubermatic.k8c.io/v1
#kind: KubermaticConfiguration
#metadata:
# finalizers:
# - operator.kubermatic.io/cleanup
# name: kubermatic
# namespace: kubermatic
#spec:
# auth:
# issuerClientSecret: abcd1234
# issuerCookieKey: wxyz9876
# serviceAccountKey: 2468mnop
# ...
The following sections describe the parts that need to be updated.
The KKP API validates the given token for authentication and therefore needs to be able to
find the new token issuer. The relevant fields are under spec.auth and the following snippet
demonstrates the default values:
spec:
auth:
clientID: kubermaticIssuer
issuerClientID: kubermaticIssuer
issuerClientSecret: ""
issuerCookieKey: ""
issuerRedirectURL: https://<domain>/api/v1/kubeconfig
serviceAccountKey: ""
skipTokenIssuerTLSVerify: false
tokenIssuer: https://<domain>/dex
The tokenIssuer needs to be updated, the rest can be left out if the default values are
used. This gives us:
spec:
auth:
tokenIssuer: 'https://keycloak.kubermatic.test/auth/realms/test'
A few fields deserve attention:
clientID and issuerClientID must be the same client. The KKP API validates the aud
claim of tokens that were issued to the issuer client, so a separate public client for the
dashboard no longer works. Both fields default to kubermaticIssuer.issuerClientSecret and issuerCookieKey are required for logging into the dashboard.
Previously they were only needed when the OIDC kubeconfig feature was enabled.Since the login URL is built by the KKP API, the only OIDC-related options left in the
spec.ui.config JSON field are the ones controlling logout:
oidc_provider is the name of the OIDC provider. It determines how the logout URL is built.
Currently, only dex and keycloak are supported.oidc_logout_url is the end-session endpoint of the OIDC provider. If it is not set, logging
out only clears the KKP session cookies and returns the user to the dashboard root; the
session at the provider stays open.A configuration of a custom OIDC provider may look like this:
spec:
ui:
config: |
{
"oidc_provider": "keycloak",
"oidc_logout_url": "https://keycloak.kubermatic.test/auth/realms/test/protocol/openid-connect/logout"
}
The oidc_provider_url, oidc_provider_scope, oidc_provider_client_id and
oidc_connector_id options are no longer used and are ignored if present. The authorization
URL, including the scopes and the client ID, is now built by the KKP API from spec.auth.
When the user token size exceeds the browser’s cookie size limit (e.g., when the user is a member of many groups), the token is split across multiple cookies to ensure proper authentication.
External tools outside of KKP (e.g., Kubernetes Dashboard, Grafana, Prometheus) are not supported with multi-cookie tokens.
When using the bundled Dex, the client used for the dashboard login is configured in the
values.yaml of the dex Helm chart:
dex:
config:
oauth2:
responseTypes:
- code # required for the dashboard login
staticClients:
- id: kubermaticIssuer
name: Kubermatic OIDC Issuer
secret: <same value as spec.auth.issuerClientSecret>
RedirectURIs:
- https://kkp.example.com/api/v2/auth/callback # KKP dashboard login
- https://kkp.example.com/api/v1/kubeconfig # user cluster kubeconfig
- https://kkp.example.com/api/v2/kubeconfig/secret # webterminal kubeconfig secret
- https://kkp.example.com/api/v2/dashboard/login # k8s dashboard login
No Dex-specific PKCE setting is required; Dex supports the S256 code challenge method for
confidential clients out of the box.
Two settings control how long a user stays signed in:
dex.config.expiry.idTokens, which the KKP chart sets to 24h). The dashboard refreshes the
token silently shortly before it expires, so this value does not determine the session length.Independently of the provider, the KKP refresh_token cookie has a lifetime of 30 days, so a
session ends after at most 30 days even if the provider would allow a longer one.
A session can also end earlier than these values suggest. Because the dashboard shares an OIDC client with the kubeconfig and web terminal flows, using one of those invalidates the refresh token of the running dashboard session. See OIDC refresh tokens are invalidated when the same user/client ID pair is authenticated multiple times.
In some cases a Seed may require an independent OIDC provider. For this reason a Seed CRD contains relevant fields under spec.oidcProviderConfiguration. Filling those fields results in overwriting a configuration from KubermaticConfiguration CRD. The following snippet presents an example of Seed CRD configuration:
spec:
oidcProviderConfiguration:
issuerURL: https://example.kubermatic.io/dex
issuerClientID: kubermaticIssuer
issuerClientSecret: "SuperSecretIssuerClientSecret"
It is highly recommended to use the same domain in email scope both for Seed level and main OIDC providers. This is a prerequisite for web terminal feature and it saves some time on user cluster RBAC configuration.
Edit KubermaticConfiguration or Seed either directly via kubectl edit or apply them from YAML
files by using kubectl apply. The KKP Operator will pick up on the changes and
reconfigure the components accordingly. After a few seconds the new pods should be up and
running.
If you are using Keycloak as a custom OIDC provider, configure the kubermaticIssuer client as follows:
https://<domain>/api/v2/auth/callback.S256.offline_access has to be part of the default or optional client scopes, otherwise no refresh token is issued.