Whether you use kubectl, a client library or plain REST, every request reaches kube-apiserver and must pass three gates before it touches etcd.
flowchart LR
C["kubectl / app / curl"] --> A["1. Authentication<br/>Who are you?"]
A -- "401 on failure" --> X1["Rejected"]
A --> Z["2. Authorization<br/>What may you do?"]
Z -- "403 if not allowed" --> X2["Rejected"]
Z --> M["3. Admission<br/>Is the request valid?"]
M --> E[("etcd")]
Two kinds of identity
| Kind | Behaviour |
|---|---|
| ServiceAccount | A Kubernetes object in a namespace, created through the API; used by pods and CI tools |
| Normal user | Has no object in the cluster and there is no kubectl create user; the identity comes from a certificate signed by the cluster CA, OIDC or an authenticating proxy |
Authentication methods
- X.509 client certificate: CN is the username, O is the group; used in kubeconfig and between components.
- Bearer token: a ServiceAccount token is mounted into the pod under
/var/run/secrets/kubernetes.io/serviceaccount/. Since 1.24 no long-lived Secret token is generated automatically; use short-lived tokens (kubectl create token). - OIDC (Entra ID, Google…): the apiserver reads the
id_token, not the access token. - HTTP basic auth and the static token file have been removed in recent releases.
| Command | Meaning |
|---|---|
kubectl config view --minify |
Current user/context (sensitive data redacted) |
kubectl create serviceaccount ci -n dev |
Create a ServiceAccount |
kubectl create token ci -n dev |
Issue a short-lived token for a ServiceAccount |
kubectl auth whoami |
Who the apiserver thinks you are (1.28+) |
Inside a kubeconfig
apiVersion: v1
kind: Config
clusters:
- name: lab
cluster: { server: https://192.0.2.50:6443, certificate-authority-data: <base64> }
users:
- name: alice
user: { client-certificate-data: <base64>, client-key-data: <base64> }
contexts:
- name: alice@lab
context: { cluster: lab, user: alice, namespace: dev }
current-context: alice@lab
A context joins a cluster, a user, and a default namespace. The KUBECONFIG environment variable can list several files, which kubectl merges. Treat kubeconfig files like passwords: they often contain keys or tokens.
Issuing a user certificate
For a self-managed cluster, a user creates a key and CSR, an admin submits it as a CertificateSigningRequest object, approves it with kubectl certificate approve alice, and hands back the signed certificate. Certificates cannot be revoked individually before they expire, which is one reason companies prefer OIDC for people.
Cloud and OIDC sign-in
Managed clusters plug in the cloud's identity: aws eks update-kubeconfig adds an exec plugin that fetches a token from IAM, and az aks get-credentials with Entra ID integration uses kubelogin. Each kubectl call then gets a short-lived token, and access ends when the user leaves the company directory.
ServiceAccounts in practice
- Every namespace has a
defaultServiceAccount; give each app its own and setserviceAccountNamein the pod. - Set
automountServiceAccountToken: falsefor pods that never call the API, so a compromised container holds no token. - Projected tokens are bound to the pod, expire (one hour by default, refreshed by the kubelet), and carry an audience, so they are far safer than old Secret-based tokens.
- Cloud workload identity (EKS Pod Identity, Azure workload identity, GKE Workload Identity) maps a ServiceAccount to a cloud identity without storing cloud keys.
The apiserver's audit log records who did what, configured with an audit policy file on self-managed clusters and as a log category on managed ones.