Authentication and Authorization¶
What You'll Learn¶
- The authentication methods the API server accepts, and which ones you'll actually see in production
- The full request pipeline — Authentication → Authorization → Admission Control — and what each stage can and cannot do
- Where mutating and validating admission webhooks sit in that pipeline, and why the order between them matters
Why This Matters¶
Every kubectl command, every controller reconcile loop, every CI/CD pipeline deploy — all of it is just an HTTPS request to the API server. If you can't explain how that request gets checked, you can't reason about why a kubectl apply gets a 403 Forbidden, why a webhook silently mutated your pod spec, or why a perfectly valid manifest gets rejected at the door. This pipeline is also one of the most common system-design and interview topics in Kubernetes because it's the single choke point every write passes through.
Mental Model¶
The API server never trusts a request until it has been authenticated (who are you), authorized (are you allowed to do this), and passed through admission control (should this specific object be allowed, and does it need to be modified first).
flowchart LR
A[Client Request] --> B[Authentication]
B --> C[Authorization]
C --> D[Mutating Admission Webhooks]
D --> E[Object Schema Validation]
E --> F[Validating Admission Webhooks]
F --> G[Persisted to etcd]
If a request fails any stage, it stops there — a request that fails authentication never reaches authorization, and a request denied by RBAC never reaches admission control.
How It Works¶
Stage 1: Authentication¶
The API server doesn't maintain its own user database. It delegates identity to one or more configured authenticators, tried in order until one succeeds (or all fail, resulting in 401 Unauthorized).
| Method | How identity is proven | Typical use |
|---|---|---|
| Client certificates (x509) | mTLS cert signed by the cluster CA; CN becomes username, O becomes group | kubectl for cluster admins, kubelet-to-API-server auth |
| Static token file | Bearer token from a file loaded at API server startup | Legacy/dev clusters only — not rotatable without a restart |
| Bootstrap tokens | Short-lived token used only to join a new node to the cluster | kubeadm join |
| Service account tokens | JSON Web Token, either the legacy long-lived Secret-backed token or the modern bound/projected token | Every in-cluster workload calling the API |
| OIDC (OpenID Connect) | Token issued by an external identity provider (Okta, Azure AD, Google) | Human users in production clusters — the recommended approach |
| Webhook token authentication | API server calls out to an external service to validate the token | Custom identity systems, cloud-provider IAM bridges |
In practice, production clusters use OIDC for humans and service account tokens for workloads. Client certificates are common for the initial admin/bootstrap identity but rarely handed out broadly, since x509 certs can't be revoked without a CRL or short expiry.
Authentication produces exactly one output: a username and a set of group memberships. Nothing more. What that identity is allowed to do is a completely separate question, answered next.
Stage 2: Authorization¶
Once the API server knows who is asking, it checks what they're allowed to do. Kubernetes supports multiple authorization modes, and like authenticators, they're evaluated in the order configured on the API server — the first mode to return an explicit allow wins; if every mode abstains or denies, the request is rejected.
| Mode | How it decides | Notes |
|---|---|---|
| RBAC | Role/ClusterRole bound to a subject via Role/ClusterRoleBinding | The default and near-universal choice today |
| ABAC | Static JSON policy file read at API server startup | Legacy — inflexible, requires API server restart to change; avoid for new clusters |
| Node authorization | Special-purpose mode that lets each kubelet only read/write objects related to its own node | Always on alongside RBAC in any real cluster |
| Webhook | API server calls an external service with a SubjectAccessReview; the service returns allow/deny |
Used for integrating with external policy engines or custom entitlement systems |
RBAC is covered in full in RBAC — this page focuses on where it sits in the bigger pipeline.
Stage 3: Admission Control¶
A request that passes authorization isn't done yet — it still has to clear admission controllers, which run only on create, update, delete, and connect requests (not on reads). Admission runs in two phases, always in this order:
- Mutating admission webhooks (and built-in mutating controllers, e.g.
DefaultStorageClass) — these can change the object before it's persisted. A sidecar-injector (like Istio's) or a defaulting webhook that adds labels runs here. - Validating admission webhooks (and built-in validating controllers, e.g. Pod Security Admission) — these can only accept or reject the object as it now stands. They never modify it.
This ordering matters: validation always sees the object after every mutation has already been applied, never before. A validating webhook that checks for a required label will still pass if a mutating webhook injected that label upstream of it.
Both webhook types are backed by a ValidatingWebhookConfiguration or MutatingWebhookConfiguration object that tells the API server which resources to intercept and which endpoint to call.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: require-team-label.example.com
webhooks:
- name: require-team-label.example.com
clientConfig:
service:
name: policy-webhook
namespace: policy-system
path: /validate
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
admissionReviewVersions: ["v1"]
sideEffects: None
failurePolicy: Fail
failurePolicy: Fail means if the webhook endpoint is unreachable, the request is rejected — the safer default for security-critical policy, versus Ignore, which lets the request through if the webhook can't be reached.
Verifying the pipeline yourself¶
# What identity am I authenticated as?
kubectl auth whoami
# Am I authorized to do X? (checked against RBAC/ABAC/Node/Webhook)
kubectl auth can-i create pods --namespace production
# What webhooks are currently intercepting admission?
kubectl get validatingwebhookconfigurations
kubectl get mutatingwebhookconfigurations
Common Mistakes¶
- Treating authentication and authorization as one step — they're separate stages with separate failure modes (
401vs.403). - Forgetting that admission control only runs on writes — a read-only
kubectl getnever touches a webhook, so a webhook bug can't explain a brokenget. - Assuming validating webhooks see the original request body — they see the object after mutating webhooks have already changed it.
- Using
failurePolicy: Ignoreon a security-critical webhook, which silently lets requests through the moment the webhook pod is unavailable. - Relying on ABAC for new clusters — it requires an API server restart to update and has no dynamic policy story; RBAC (and Webhook mode for advanced cases) has fully replaced it.
Interview Questions¶
- Walk through what happens, stage by stage, when
kubectl apply -f pod.yamlis run. - What's the difference between a mutating and a validating admission webhook, and why does the order between them matter?
- Why can a request pass RBAC and still get rejected by admission control?
- What does
failurePolicy: Failvs.Ignoremean for a webhook, and when would you choose each?
See Interview Prep for full answers.
Next¶
Continue to RBAC to go deep on the authorization mode almost every cluster relies on.