Lesson 03 of 15 · Identity & Access
Authentication methods
How the API server decides who you are: client certificates (and why they're a poor fit for people), ServiceAccount tokens for workloads, OIDC for humans, webhook and proxy authentication, and how to see which identity a request really has.
Authentication vs authorization
- Authentication (authN): who is this? Produces a username, groups and maybe extra attributes.
- Authorization (authZ): may they do this? Usually RBAC (see Kubernetes Administration, lesson 15).
The API server tries each configured authenticator; the first one that recognises the request wins. If none do, the request is anonymous (and normally has almost no permissions).
At the school gate, the guard can recognise you in different ways: your photo ID card (a client certificate), a visitor sticker issued for today only (a token), or a phone call to your parents' office to confirm who you are (OIDC with an identity provider). The guard doesn't decide which rooms you can enter. That's the next person's job (RBAC).
$ kubectl auth whoami
ATTRIBUTE VALUE
Username kubernetes-admin
Groups [kubeadm:cluster-admins system:authenticated]
The authenticators
| Method | Identity comes from | Good for |
|---|---|---|
| X.509 client certificates | CN (user), O (groups) | Components, break-glass admin |
| ServiceAccount tokens | Signed JWT: system:serviceaccount:<ns>:<name> |
Workloads (pods, CI) |
| OIDC tokens | Claims from your identity provider (username, groups) | Humans |
| Webhook token authentication | An external service you run | Custom or cloud IAM integrations (e.g. EKS uses AWS IAM) |
| Authenticating proxy | Headers set by a trusted proxy | Special setups |
| Static token file | A CSV on the control plane | Avoid: no rotation |
Client certificates through the CSR API
You can issue a user certificate without touching the CA key directly:
$ openssl genrsa -out asha.key 2048
$ openssl req -new -key asha.key -subj "/CN=asha/O=devops" -out asha.csr
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: asha
spec:
request: <base64 of asha.csr, on one line> # base64 -w0 asha.csr
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400 # 1 day
usages: ["client auth"]
$ kubectl apply -f asha-csr.yaml
$ kubectl certificate approve asha
$ kubectl get csr asha -o jsonpath='{.status.certificate}' | base64 -d > asha.crt
$ kubectl config set-credentials asha --client-certificate=asha.crt --client-key=asha.key --embed-certs
$ kubectl --user=asha auth whoami
Certificates can't be revoked
If asha.key leaks, or Asha leaves, the certificate stays valid until it expires. Keep certificate lifetimes short, keep certificates for break-glass and components, and use OIDC for people.
ServiceAccount tokens: identities for workloads
Pods get a projected, bound token: short-lived, audience-scoped, rotated by the kubelet, and invalid once the pod is gone.
$ kubectl exec deploy/web -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | cut -d. -f2 | base64 -d 2>/dev/null
{"aud":["https://kubernetes.default.svc.cluster.local"],"exp":1790000000,…,"sub":"system:serviceaccount:default:default"}
(The payload is base64url-encoded, so plain base64 -d may complain about padding; the idea is what matters.) For CI or external tools, mint a short-lived token instead of creating long-lived token Secrets:
$ kubectl create token ci-deployer -n shop --duration=30m
The same tokens also let workloads authenticate to clouds and Vault (workload identity federation): the external system trusts the cluster's token issuer.
OIDC: the right answer for humans
With OIDC, the API server trusts tokens issued by your identity provider (Keycloak, Dex, Entra ID, Okta, Google…). Users log in through the browser, with MFA if the IdP requires it, and kubectl sends the resulting ID token. Disable a user in the IdP and their access ends when the token expires. Next lesson: setting it up.
Try it: two identities, one cluster
- Create the
ashacertificate via the CSR API (groupdevops), add it to your kubeconfig, and runkubectl --user=asha auth whoami. - Try
kubectl --user=asha get pods: forbidden. Bindviewto the groupdevopsindefault, and try again. - Create a ServiceAccount
ci-deployer, mint a 10-minute token withkubectl create token, and use it through a token-only kubeconfig user (kubectl config set-credentials ci --token=…, then--user=ci). Who doesauth whoamisay you are? - Wait for the token to expire and try again.
Going deeper: authentication hardening
- Disable anonymous auth where possible (
--anonymous-auth=false), or restrict whatsystem:anonymouscan reach. Recent versions can limit anonymous access to health endpoints only. - Recent Kubernetes versions support a structured authentication configuration file (multiple OIDC issuers, claim mappings and validation rules with CEL) instead of individual
--oidc-*flags. Prefer it on new clusters where available. - Avoid legacy long-lived ServiceAccount token Secrets; clean up old ones (
kubectl get secrets -A --field-selector type=kubernetes.io/service-account-token). - Log authentication failures via the audit log (lesson 13) and alert on unusual patterns.
Recap
- AuthN answers who; RBAC answers what.
kubectl auth whoamishows what the API server sees. - Client certs: CN = user, O = groups; no revocation. Use them for components and break-glass.
- ServiceAccount tokens: bound, short-lived identities for workloads;
kubectl create tokenfor CI. - OIDC for humans: central identity, MFA, and instant offboarding.
This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.