Authentication is the first gate in the API server pipeline: "Who are you?" Kubernetes doesn't manage user accounts itself — it delegates authentication to external systems (certificates, tokens, OIDC providers). Understanding the authentication methods is critical for CKS and for securing production clusters.

1. Two Types of Identity

Kubernetes distinguishes between two kinds of identities:

Human UsersService Accounts
Managed byExternal system (OIDC, certs, LDAP)Kubernetes API (objects in etcd)
Exists as K8s object?❌ No (K8s has no "User" resource)✅ Yes (kind: ServiceAccount)
Namespaced?No (cluster-wide identity)Yes (per-namespace)
Used bykubectl users, CI/CD pipelines, adminsPods, controllers, operators
AuthenticationClient certs, OIDC tokens, static tokensProjected SA tokens (JWT)
Kubernetes does NOT store user accounts. There's no kubectl create user command. Users are established by external authenticators (X.509 cert CN, OIDC sub claim, etc.). The API server verifies the credential and extracts the username/groups — but never stores them. This is fundamentally different from ServiceAccounts which ARE K8s objects.

The Authentication Flow

Request + credential Authentication Plugins Certs | Tokens | OIDC | Webhook (tried in order, first match wins) Authenticated! user: jane, groups: [dev] → AuthZ

The API server runs multiple authenticators. Each request is tried against all configured plugins. The first one that succeeds establishes the identity. If all fail → 401 Unauthorized.

2. X.509 Client Certificates

The most common authentication for cluster components (kubelet, scheduler, controller-manager) and kubeadm-created admin users. The API server trusts any certificate signed by its configured CA.

How It Works

  1. Client presents a TLS client certificate during the HTTPS handshake
  2. API server validates the cert against its --client-ca-file (the cluster CA)
  3. Username is extracted from the certificate's Common Name (CN)
  4. Groups are extracted from the certificate's Organization (O) fields
# Certificate with CN=jane, O=developers, O=admins
# → Authenticated as user "jane" with groups ["developers", "admins"]

Creating a User Certificate (CKA Exam Pattern)

# 1. Generate private key:
openssl genrsa -out jane.key 2048

# 2. Create Certificate Signing Request (CSR):
openssl req -new -key jane.key -out jane.csr \
  -subj "/CN=jane/O=developers"
#         ↑ username    ↑ group

# 3. Submit CSR to Kubernetes for signing:
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: jane-csr
spec:
  request: $(cat jane.csr | base64 | tr -d '\n')
  signerName: kubernetes.io/kube-apiserver-client
  usages: ["client auth"]
EOF

# 4. Approve the CSR:
kubectl certificate approve jane-csr

# 5. Get the signed certificate:
kubectl get csr jane-csr -o jsonpath='{.status.certificate}' | base64 -d > jane.crt

# 6. Add to kubeconfig:
kubectl config set-credentials jane \
  --client-certificate=jane.crt \
  --client-key=jane.key
kubectl config set-context jane-ctx \
  --cluster=kubernetes --user=jane
CKA/CKS exam: creating user certificates via CertificateSigningRequest is a common question. Know the steps: generate key → create CSR → submit to K8s → approve → extract cert. The critical detail: signerName: kubernetes.io/kube-apiserver-client and usages: ["client auth"].
Client certificates cannot be revoked without rotating the entire cluster CA. Once issued, a cert is valid until it expires. This is a major limitation — if a user's key is compromised, you can't invalidate just their cert. This is why OIDC is preferred for human users in production.

3. OIDC (OpenID Connect)

The recommended method for human users in production. Integrates with identity providers (Google, Azure AD, Okta, Keycloak, Dex) for SSO with centralized user management.

How It Works

  1. User authenticates with the OIDC provider (login page, MFA)
  2. Provider returns an ID token (JWT) containing user claims
  3. kubectl sends the JWT as a bearer token to the API server
  4. API server validates the JWT signature against the provider's public keys
  5. Username/groups extracted from configured JWT claims
# API server configuration for OIDC:
kube-apiserver \
  --oidc-issuer-url=https://accounts.google.com \
  --oidc-client-id=my-k8s-cluster \
  --oidc-username-claim=email \
  --oidc-groups-claim=groups \
  --oidc-username-prefix="oidc:" \
  --oidc-groups-prefix="oidc:"

OIDC vs Certificates

AspectX.509 CertificatesOIDC
Revocation❌ Can't revoke (must rotate CA)✅ Disable user in provider → immediate
Short-livedTypically long-lived (1 year)✅ Tokens expire (hours, configurable)
MFA❌ No (just key possession)✅ Provider enforces MFA
Centralized❌ Per-cluster CA✅ One provider for all clusters
Setup complexityLow (built-in)Medium (need OIDC provider)
Best forComponent auth, bootstrap, kubeadm adminHuman users in production
In production multi-cluster environments, OIDC + a shared identity provider (Okta, Azure AD) is the standard. One login gets you access to all clusters. Disable a user in the IdP → they lose access to ALL clusters immediately. Tools like kubelogin and oidc-login handle the token refresh flow transparently in kubectl.

4. ServiceAccount Tokens

ServiceAccounts are for Pods and automated systems — not humans. Every namespace has a default ServiceAccount. Pods use SA tokens to authenticate with the API server.

Modern Bound Tokens (K8s 1.22+)

# Automatically projected into every Pod:
/var/run/secrets/kubernetes.io/serviceaccount/token

# This is a short-lived JWT (bound token):
# - Expires after 1 hour (auto-rotated by kubelet)
# - Bound to the specific Pod (invalidated on Pod deletion)
# - Audience-bound (valid only for the API server)

# Decoded token payload:
{
  "iss": "https://kubernetes.default.svc",
  "sub": "system:serviceaccount:default:my-app-sa",
  "aud": ["https://kubernetes.default.svc"],
  "exp": 1705334400,
  "iat": 1705330800,
  "kubernetes.io": {
    "namespace": "default",
    "pod": {"name": "web-abc", "uid": "..."},
    "serviceaccount": {"name": "my-app-sa", "uid": "..."}
  }
}

Creating Long-Lived Tokens (When Needed)

# For external systems that need a static token (CI/CD, monitoring):
apiVersion: v1
kind: Secret
metadata:
  name: ci-token
  annotations:
    kubernetes.io/service-account.name: ci-sa
type: kubernetes.io/service-account-token
# Controller generates a non-expiring token in this Secret

# Or create a token with specific expiry:
kubectl create token ci-sa --duration=8760h   # 1 year
Long-lived tokens are a security risk — they don't expire until manually deleted. K8s 1.24+ stopped auto-creating them. Only create long-lived tokens when absolutely necessary (legacy integrations that can't handle token rotation). Always prefer bound tokens (automatic, short-lived, Pod-specific).

5. Other Authentication Methods

Bootstrap Tokens

# Used during kubeadm join — short-lived tokens for node registration:
kubeadm token create --print-join-command
# Token format: abcdef.0123456789abcdef (6 chars.16 chars)
# Stored as Secrets in kube-system namespace
# Default TTL: 24 hours — expire after cluster bootstrap

Webhook Token Authentication

# Delegates authentication to an external service:
kube-apiserver --authentication-token-webhook-config-file=/etc/k8s/webhook-config.yaml
# API server sends the bearer token to your webhook
# Webhook responds with: authenticated=true, user=..., groups=[...]
# Use case: custom auth systems, legacy token validation

Static Token File (Avoid in Production)

# API server reads tokens from a CSV file:
# kube-apiserver --token-auth-file=/etc/k8s/tokens.csv
# Format: token,user,uid,"group1,group2"
# ⚠️ Not recommended: no expiry, no revocation, requires API server restart to change

Anonymous Authentication

# If no authenticator matches → request is anonymous:
# user: system:anonymous
# groups: [system:unauthenticated]
# Some paths allow anonymous (healthz, readyz)
# Disable for non-public endpoints: --anonymous-auth=false

6. What Each Component Uses

ComponentAuth MethodIdentity
kubeletX.509 client certsystem:node:<nodename>
kube-schedulerX.509 client certsystem:kube-scheduler
kube-controller-managerX.509 client certsystem:kube-controller-manager
kube-proxyX.509 client certsystem:kube-proxy
kubectl (admin)X.509 client cert (kubeadm) or OIDCCN from cert or OIDC claim
PodsServiceAccount token (bound JWT)system:serviceaccount:<ns>:<name>
CI/CD pipelinesSA token or OIDCDepends on setup
Pattern: system components use X.509 certs, humans use OIDC, Pods use SA tokens. This three-tier model gives you: immutable component identities (certs), centrally-managed human access (OIDC), and auto-rotating workload identities (bound tokens).

Summary

MethodIdentity SourceBest ForRevocable?
X.509 CertsCN=user, O=groupsComponents, bootstrap admin❌ (only CA rotation)
OIDCJWT claims (email, groups)Human users (production)✅ (disable in IdP)
SA Tokens (bound)Projected JWT (1h, Pod-bound)Pods, workload identity✅ (delete Pod/SA)
SA Tokens (static)Secret-stored JWT (no expiry)Legacy integrations✅ (delete Secret)
Bootstrap Tokenskube-system Secret (24h TTL)kubeadm node join✅ (delete/expire)
WebhookExternal auth serviceCustom auth systems✅ (external control)

📝 Quiz: Authentication Methods

Q1: A user presents a client certificate with CN=alice and O=engineering. What username and groups does the API server extract?

Username: alice (from Common Name). Groups: ["engineering"] (from Organization). If the cert had multiple O fields (O=engineering, O=ops), both would be groups.

Q2: A user's private key is compromised. They were authenticated via X.509 cert. How do you revoke their access?

You can't directly revoke a single cert. Options: (1) Remove their RBAC bindings (they authenticate but can't do anything). (2) Rotate the entire cluster CA (invalidates ALL certs — very disruptive). (3) If the cert has a short TTL, wait for expiry. This is why OIDC is preferred — you just disable the user in the identity provider for immediate revocation.

Q3: Does Kubernetes have a "User" resource you can create with kubectl create user?

No. Kubernetes has no User resource and no user management API. Users are external — established by authenticators (cert CN, OIDC claims). Only ServiceAccounts are K8s-native identity objects. To "create a user," you issue them a certificate or add them to your OIDC provider.

Q4: What's the difference between a legacy SA token (Secret-stored) and a modern bound SA token (projected)?

Legacy: Stored in a Secret, never expires, not bound to any Pod, valid until manually deleted. Dangerous if leaked.
Bound (modern): Projected into the Pod, expires in ~1h (auto-rotated by kubelet), bound to specific Pod UID (invalidated when Pod is deleted), audience-restricted. Much safer — compromised token is short-lived and useless after Pod deletion.

Q5: The kubelet on worker-1 authenticates to the API server. What identity does it present?

Username: system:node:worker-1. Group: system:nodes. It uses an X.509 client certificate with CN=system:node:worker-1 and O=system:nodes. This identity is used by the Node authorizer to limit kubelet access to only its own node's Pods and Secrets.

Q6: Why is OIDC preferred over X.509 certs for human users in production?

Four reasons: (1) Revocation — disable user in IdP, immediate effect. Certs can't be revoked. (2) Short-lived — OIDC tokens expire in hours; certs are valid for months/years. (3) MFA — IdP can enforce multi-factor auth. (4) Centralized — one IdP manages access to all clusters. Certs are per-cluster and per-user.