Kubernetes Security & Hardening›03 · Authentication methods

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.

Advanced
Key wordsauthenticationX.509 client certificatesCSR APIServiceAccount tokensbound tokensOIDCwebhookkubectl auth whoami

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

  1. Create the asha certificate via the CSR API (group devops), add it to your kubeconfig, and run kubectl --user=asha auth whoami.
  2. Try kubectl --user=asha get pods: forbidden. Bind view to the group devops in default, and try again.
  3. Create a ServiceAccount ci-deployer, mint a 10-minute token with kubectl create token, and use it through a token-only kubeconfig user (kubectl config set-credentials ci --token=…, then --user=ci). Who does auth whoami say you are?
  4. Wait for the token to expire and try again.

Going deeper: authentication hardening

  • Disable anonymous auth where possible (--anonymous-auth=false), or restrict what system:anonymous can 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 whoami shows 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 token for 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.