Today the default way to reach a self‑hosted Kubernetes cluster is shifting from a static client certificate or long‑lived token to a public OIDC client that uses PKCE. The change removes a shared secret from every workstation and makes access decisions flow through the identity provider’s group membership.
Why the shift matters to engineers and security teams
Static credentials live on disks, get copied, and rarely get revoked when a user leaves or changes role. By delegating authentication to an OIDC provider (for example Keycloak) and configuring the client as public, the only secret that ever needs distribution is the client ID, which is not sensitive. Access changes become simple identity operations – add or remove a user from a group – and the Kubernetes RBAC layer consumes those groups directly from the token.
Core components of the new flow
- kubectl with the
kubeloginexec plugin initiates a browser‑based login, receives an ID token, and injects it as a bearer token on every API call. - Identity provider (Keycloak) authenticates the user, issues an ID token that includes
preferred_usernameand agroupsclaim, and signs the token with its private key. - kube‑apiserver configured with
--oidc-issuer-url,--oidc-client-id,--oidc-username-claim, and--oidc-groups-claim. It validates the token against the provider’s public signing keys and passes the extracted identity to the RBAC engine.
Implementation checklist
- In Keycloak, add a protocol mapper of type Group Membership to the client scope, map it to the claim name
groups, and enable it for the ID token. - Start the API server with OIDC flags, for example:
--oidc-issuer-url=https:///realms/ --oidc-client-id=kubernetes --oidc-username-claim=preferred_username --oidc-groups-claim=groups
If the IdP uses a self‑signed certificate, also supply--oidc-ca-file=/etc/kubernetes/pki/oidc-ca.crtso the server can fetch the signing keys. - Configure
kubectlto use an exec‑credential entry instead of static certs:users: - name: oidc user: exec: apiVersion: client.authentication.k8s.io/v1 command: kubectl args: - oidc-login - get-token - --oidc-issuer-url=https:///realms/ - --oidc-client-id=kubernetesNosecretfield is present. - Create RBAC bindings that reference the groups claim, e.g.:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: platform-viewers subjects: - kind: Group name: platform-viewer apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io
Operational and security implications
Because the client is public, no secret is stored on the workstation, eliminating the risk of a leaked shared credential. PKCE ensures that an intercepted authorization code cannot be exchanged without the original verifier, protecting the token flow from man‑in‑the‑middle attacks. Access revocation is now an identity‑provider operation; removing a user from a group instantly prevents future token issuance with that group.
However, the cluster now depends on the IdP’s availability and the correctness of its signing keys. Operators must monitor the health of the OIDC endpoint and have a process for rotating the IdP’s signing certificate. Since the API server only fetches the keys once, a key rotation requires a restart or a manual reload of the trust store.
Related CloudNinjas coverage: hands-on guides.
What This Means For Practitioners
Adopt the public OIDC client pattern to eliminate secret distribution and align Kubernetes access with existing identity workflows. Verify that your IdP can emit the required groups claim and that PKCE is enforced. Update your API server flags, replace static credentials in kubeconfig with the exec plugin, and bind RBAC to the groups you manage centrally. Finally, put monitoring in place for IdP health, token expiration, and key rotation to keep the authentication path reliable.

