OIDC & SSO for kubectl
Summary
- OIDC lets humans authenticate to the Kubernetes API with corporate SSO instead of long-lived certificates or static tokens.
- Insight: the identity provider issues an ID token, the API server validates it, and RBAC maps the token's username and groups to permissions.
- Key Concepts: OIDC issuer, ID token, claims for username and groups, and the
kubectl oidc-logincredential plugin. - When to Use: any multi-user cluster where you want central identity, group-based access, and easy offboarding.
- Limitations: OIDC handles authentication only, tokens are bearer credentials that expire, and clusters cannot revoke an already-issued ID token before it lapses.
Recipe
Point the API server at your OIDC issuer, then have users log in through a credential plugin that caches and refreshes tokens.
kubectl oidc-login setup \
--oidc-issuer-url=https://login.example.com \
--oidc-client-id=kubernetesBind RBAC to the groups your provider emits, not to individual users, so access follows directory membership.
Working Example
On a self-managed control plane, configure the API server flags to trust your issuer.
# kube-apiserver flags (static pod manifest or control-plane config)
--oidc-issuer-url=https://login.example.com
--oidc-client-id=kubernetes
--oidc-username-claim=email
--oidc-username-prefix=oidc:
--oidc-groups-claim=groups
--oidc-groups-prefix=oidc:Managed clusters expose the same settings through their console or API, so you rarely edit raw flags there.
Configure each user's kubeconfig to obtain tokens through the kubelogin plugin.
apiVersion: v1
kind: Config
users:
- name: oidc-user
user:
exec:
apiVersion: client.authentication.k8s.io/v1
command: kubectl
args:
- oidc-login
- get-token
- --oidc-issuer-url=https://login.example.com
- --oidc-client-id=kubernetes
- --oidc-extra-scope=email
- --oidc-extra-scope=groupsBind a group claim to a Role so directory membership grants cluster access.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: payments
name: payments-devs-edit
subjects:
- kind: Group
name: "oidc:payments-team"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: edit
apiGroup: rbac.authorization.k8s.ioWhen a user runs kubectl, the plugin opens a browser, completes SSO, and returns an ID token the API server validates.
Deep Dive
The login flow
The credential plugin performs a standard OIDC authorization code flow with the identity provider.
The provider returns an ID token, a signed JWT containing claims such as email and groups.
kubectl sends that token as a bearer credential on every API request.
The API server validates the signature against the issuer's public keys, checks expiry and audience, then extracts the configured claims.
Username and group claims
The --oidc-username-claim and --oidc-groups-claim flags tell the API server which claims become the RBAC subject and its groups.
Prefixes like oidc: prevent collisions with built-in users and groups, and they must match the values you use in bindings.
Binding to groups rather than users means adding or removing someone in the corporate directory instantly changes their cluster access.
Token lifetime and refresh
ID tokens are short-lived, often minutes to an hour.
The kubelogin plugin caches the token and uses the OIDC refresh token to obtain a new ID token silently when it expires.
Because tokens are bearer credentials, a leaked token is valid until expiry, which is why short lifetimes matter.
Managed cluster variations
Cloud platforms often front the API with their own IAM and can federate to an external OIDC provider or issue their own tokens.
The RBAC model is identical - you still bind Roles to the resulting username or groups.
Verifying the login end to end
After configuration, confirm both authentication and authorization independently.
kubectl --user=oidc-user get pods -n payments
kubectl auth can-i --list --user=oidc-user -n payments- The first command exercises the full browser login and token exchange.
- The second lists the effective permissions the token's groups resolve to.
- A
yes/nomismatch against expectations usually points to a missing or misprefixed group binding.
Bootstrap and break-glass access
Keep one non-OIDC path so a provider outage cannot lock you out of the cluster.
A short-lived X.509 admin certificate or a cloud-native admin role works, provided its use is logged and rare.
Never make that break-glass path the everyday login, since it bypasses central identity and group refresh.
Gotchas
Group prefixes must match exactly between the API server flags and your RoleBindings, or bindings silently never apply.
OIDC authenticates but never authorizes, so a successful login with no matching binding still returns Forbidden.
Do not distribute a shared kubeconfig with an embedded static token, since it defeats per-user identity and offboarding.
The API server cannot revoke an issued ID token early, so rely on short lifetimes and disable the account at the provider.
Large group lists can exceed token size limits at some providers, so scope the emitted groups to what the cluster needs.
Clock skew between the provider and the API server can reject valid tokens, so keep NTP healthy on control-plane nodes.
Alternatives
Use OIDC SSO for all human access - it centralizes identity and is the recommended default for teams.
Use X.509 client certificates only for bootstrap or break-glass, since they are hard to revoke and carry no group refresh.
Use a cloud provider's native IAM integration when you are on a managed platform and want to reuse existing cloud identities.
Use ServiceAccount tokens for workloads and automation, never for interactive human login.
FAQs
Does OIDC replace RBAC? No. OIDC proves who you are, and RBAC decides what you can do. You need both.
Why do I get Forbidden right after a successful login? Your token authenticated, but no RoleBinding grants your username or groups any permissions yet.
How are tokens refreshed?
The kubelogin credential plugin uses the OIDC refresh token to fetch a new short-lived ID token without another browser prompt.
Should I bind Roles to users or groups? Bind to groups. Directory membership then drives access, and onboarding or offboarding needs no cluster change.
Can I revoke a specific user immediately? Disable them at the identity provider and remove group membership. The existing token still works until it expires, so keep lifetimes short.
Related
- How Kubernetes Decides Who Can Do What
- RBAC Basics
- Service Accounts
- RBAC Auditing
- RBAC Best Practices
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).