Install kubelogin
kubelogin is a kubectl credential plugin that runs the OIDC browser flow against Keycloak, caches the token, and feeds it to the Kestrel kube-apiserver. The upstream project is int128/kubelogin. There is an unrelated binary also called kubelogin maintained by Microsoft for Azure AD — that is not what Kestrel uses. If your package manager offers both, pick the int128/kubelogin build.
For the mental model of how kubelogin sits between Keycloak, the kube-apiserver, and Capsule, see Identity chain.
Install
Section titled “Install”The recommended path on macOS is Homebrew:
brew install kubeloginIf Homebrew is not available, download the kubelogin_darwin_arm64.zip or kubelogin_darwin_amd64.zip archive from the upstream release page, extract it, and put the kubelogin binary on your PATH.
The recommended path on Linux is Krew:
kubectl krew install oidc-loginWhen installed via Krew, the plugin is invoked as kubectl oidc-login (not kubelogin). Your kubeconfig exec.command should be kubectl with args: [oidc-login, get-token, ...].
Alternatively, install via Linuxbrew (brew install kubelogin) or download the kubelogin_linux_amd64.zip archive from the upstream release page. kubelogin is not packaged in apt, yum, or dnf repositories.
The recommended path on Windows is Chocolatey:
choco install kubeloginAlternatively, install via Krew (kubectl krew install oidc-login) or download the kubelogin_windows_amd64.zip archive from the upstream release page, extract it, and put kubelogin.exe on your PATH.
Configure your kubeconfig
Section titled “Configure your kubeconfig”Paste the following block into ~/.kube/config (merge with any existing config carefully — or use KUBECONFIG=~/.kube/config-kestrel kubectl ... to keep it isolated while you test).
apiVersion: v1kind: Configclusters: - name: kestrel cluster: server: https://proxy.kestrel.arbutus.cloudcontexts: - name: kestrel context: cluster: kestrel user: kestrel-oidccurrent-context: kestrelusers: - name: kestrel-oidc user: exec: apiVersion: client.authentication.k8s.io/v1 command: kubectl args: - oidc-login - get-token - --oidc-issuer-url=https://keycloak.arbutus.alliancecan.ca/realms/atmosphere - --oidc-client-id=kubernetes - --token-cache-storage=keyring interactiveMode: IfAvailable provideClusterInfo: falseYour tenant name is your Cloud RAP’s Alliance LDAP group name — one of def-profname, crg-profname-xx, or cpp-profname-xx. Ask your PI if you don’t know yours. See Identity chain for why the tenant name matches the Cloud RAP group.
First login
Section titled “First login”Run any read-only kubectl command that hits the apiserver. The simplest is:
kubectl get nsOn the first command, kubelogin opens your default browser to the Keycloak login page. Authenticate with your Alliance CCDB credentials — Keycloak’s upstream identity provider is Alliance LDAP, so the same CCDB username and password you use at ccdb.alliancecan.ca work here. Keycloak redirects back to a local port (localhost:8000 by default) that kubelogin is listening on, exchanges the authorization code for an id_token, caches it under ~/.kube/cache/oidc-login/, and returns the token to kubectl. The kubectl get ns command then completes and prints the namespaces you are allowed to see — at least one will start with your Cloud RAP group name (for example, crg-profname-01-experiments if your PI’s Cloud RAP is crg-profname-01).
Subsequent kubectl commands reuse the cached token until it expires, at which point kubelogin silently refreshes it against Keycloak without prompting you again.
Troubleshooting
Section titled “Troubleshooting”Port 8000 already in use
Section titled “Port 8000 already in use”Symptom: browser shows “Unable to connect” after the Keycloak login page; kubelogin in the terminal hangs.
Cause: another process already bound localhost:8000 — a dev server, a previous kubelogin session, or a Docker port publish.
Fix: override the listen address with --listen-address=localhost:18000 in the kubeconfig exec.args, or set KUBELOGIN_LISTEN_ADDRESS=localhost:18000 in your shell environment before running kubectl. RCS has registered multiple candidate ports with Keycloak, so the alternate port is accepted as a redirect target.
State does not match
Section titled “State does not match”Symptom: browser reaches the Keycloak login page but returns an error page after you authenticate (“State does not match” or a similar OIDC state-mismatch message).
Cause: stale OIDC state in the local cache — usually from a previous aborted login, or a duplicate browser tab that followed an old callback link.
Fix: clear the cache and retry:
kubectl oidc-login cleankubectl get nsIf it persists, open a fresh browser window (or an incognito session) so the Keycloak session cookie is new.
Browser does not open on WSL2 or over SSH
Section titled “Browser does not open on WSL2 or over SSH”Symptom: kubectl get ns hangs; no browser window appears.
Cause: you are running inside WSL2, tmux, or a remote SSH session with no local GUI — kubelogin has no default browser to open.
Fix: add --skip-open-browser to the exec.args in your kubeconfig, then copy the printed URL into a local browser manually and complete the OAuth flow. If the shell is remote, forward the callback port first:
ssh -L 8000:localhost:8000 <user>@<remote-host>The browser on your local workstation will then reach localhost:8000 and hand the authorization code back to the kubelogin process running on the remote host.
kubectl get ns returns nothing after a clean login
Section titled “kubectl get ns returns nothing after a clean login”Symptom: the OIDC browser flow completes and kubelogin writes a token cache successfully, but kubectl get ns returns zero namespaces — not an error, just an empty result.
Cause: you have successfully authenticated to Keycloak and the kube-apiserver has accepted your identity, but the groups claim in your OIDC id_token does not contain any Cloud RAP group that maps to a Capsule Tenant on Kestrel. The two common reasons:
- Your PI has not added you to the Cloud RAP in CCDB. Cloud RAPs do not auto-add sponsored users — this is the single most common failure mode on first login. Ask your PI to confirm you are listed on their Cloud RAP at
ccdb.alliancecan.ca. - Alliance LDAP propagation delay. Your PI added you, but the LDAP read happened before propagation finished. Usually immediate, occasionally a few minutes.
Fix: once your PI has added you (or after waiting for propagation), clear the cached token and force a fresh login:
# You own this — clears the stale OIDC cache so the next kubectl triggers a fresh loginkubectl oidc-login cleankubectl get nsIf kubectl get ns still returns nothing after a fresh token, the problem is upstream of Keycloak. See Requesting access for the end-to-end CCDB flow, and contact accounts@tech.alliancecan.ca for CCDB-level issues.