Authentication, Authorization and RBAC
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production; see the section bibliography for the reference material consulted while preparing these pages. |
Every request to the Kubernetes API server — from kubectl, from a kubelet, from a controller, from a Pod calling the
API — passes through the same three stages: who are you (authentication), are you allowed to do this (authorization),
and is the request acceptable (admission). This page covers the first two and the ServiceAccount identity that Pods
use; admission is in Admission Control and Policy. It is written
against Kubernetes 1.37; see the section index for the version baseline. Hardening
of the Pods themselves is in Pod Security.
Every credential shown on this page is a placeholder such as <token>; never paste or commit real tokens,
client certificates, private keys or kubeconfig credentials.
The request pipeline
Authentication establishes a username, groups and extra attributes; it does not grant anything. Authorization then
evaluates that identity against the verb, resource, namespace and name of the request. Several authenticators and
authorizers may be configured, and the first that accepts (authentication) or allows (authorization) wins. A request
that no authenticator recognises is treated as system:anonymous if anonymous access is enabled, and is normally denied
by authorization.
Authenticating users
Kubernetes has no User object: users are whatever the configured authenticators assert. Common methods:
| Method | How it works |
|---|---|
X.509 client certificates |
The certificate’s common name becomes the username and its organisation fields become groups. Used by kubeadm’s admin kubeconfig and by kubelets. Certificates cannot be revoked individually, so prefer short lifetimes. |
OpenID Connect (OIDC) |
An external identity provider issues an ID token that the API server validates (issuer, audience, claims mapped to
username and groups). Configured with the structured |
Webhook token authentication |
The API server sends the presented bearer token to an external service to validate. |
ServiceAccount tokens |
Signed JWTs for in-cluster workloads; see below. |
Authenticating proxy |
A front proxy sets trusted headers carrying the identity. |
Source: Kubernetes Docs — Authenticating.
Static token files and HTTP basic auth are not recommended and basic auth has been removed. Managed services usually bridge their cloud identity provider to Kubernetes; for example, the Azure AKS pages describe Microsoft Entra ID integration (see AKS Clusters).
kubeconfig users
A kubeconfig file holds clusters (server address and CA), users (credentials) and contexts (a cluster + user
namespace triple). The users entry is where the authentication method lives: an embedded client certificate and key, a
bearer token, or — preferably — an exec plugin that fetches short-lived credentials on demand. Because kubeconfig
files grant access, treat them as secrets and never commit them. A plugin-based entry holds no secret itself:
apiVersion: v1
kind: Config
users:
- name: alice-oidc
user:
exec:
apiVersion: client.authentication.k8s.io/v1
command: kubectl-oidc_login # credential plugin binary on PATH
args: ["get-token", "--oidc-issuer-url=<issuer-url>", "--oidc-client-id=<client-id>"]
interactiveMode: IfAvailable
kubectl config get-contexts
kubectl config use-context kind-bookshelf
kubectl auth whoami # who the API server thinks you are
ServiceAccounts
A ServiceAccount is the identity of a workload. It is namespaced, and its username is
system:serviceaccount:<namespace>:<name>. Every namespace has a default ServiceAccount, and every Pod runs as one,
which is why you should create a dedicated one per workload.
Tokens. Since Kubernetes 1.24 the control plane no longer auto-creates long-lived token Secrets for ServiceAccounts.
Instead the kubelet obtains a short-lived, audience-bound token through the TokenRequest API and mounts it as a
projected volume; the token is bound to the Pod, expires (and is refreshed automatically by the kubelet), and becomes
invalid when the Pod is deleted. A client library reads it from
/var/run/secrets/kubernetes.io/serviceaccount/token. For automation outside the cluster, mint a token on demand:
kubectl create serviceaccount notifier -n bookshelf
kubectl create token notifier -n bookshelf --duration=10m # prints a short-lived token
Source: Kubernetes Docs — Service Accounts.
A long-lived token Secret (type: kubernetes.io/service-account-token) still exists as an explicit, discouraged
fallback; see Secrets.
Not every Pod needs API access. The default behaviour mounts a token into every Pod. Turn that off where the
application does not call the API, either on the ServiceAccount or on the Pod (the Pod setting wins):
apiVersion: v1
kind: ServiceAccount
metadata:
name: catalog-api
namespace: bookshelf
automountServiceAccountToken: false
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: notifier
namespace: bookshelf
---
apiVersion: v1
kind: Pod
metadata:
name: notifier
namespace: bookshelf
spec:
serviceAccountName: notifier
automountServiceAccountToken: true
containers:
- name: notifier
image: ghcr.io/example/bookshelf-notifier:1.0.0
A projected token with a custom audience can also be mounted explicitly (serviceAccountToken volume source with
audience and expirationSeconds), which is how workloads authenticate to external systems; cloud workload identity
features federate that token to a cloud IAM role so no cloud key is stored in the cluster (see
AKS Microservices for the Azure version).
Pod certificates
Besides bearer tokens, Pods can now obtain X.509 certificates for their own identity. The PodCertificateRequest API and
the podCertificate projected volume let the kubelet generate a key, submit a request to a signer, and mount the
resulting certificate chain, rotating it automatically — useful for workload mTLS without sidecars or an external
issuer. According to the feature-gates reference, PodCertificateRequest is stable and enabled by default from 1.37
(beta in 1.35 and 1.36); on earlier clusters it needs the beta API enabled. Signers (for example one provided by a
service mesh or cert-manager integration) are separate components.
RBAC
Role-based access control is the standard authorizer (--authorization-mode=Node,RBAC, or authorizers entries such as
{type: Node, name: node} and {type: RBAC, name: rbac} in the --authorization-config file). It is purely
additive: there are no deny rules, so a request is allowed if any rule permits it.
| Object | Meaning |
|---|---|
|
A set of rules (verbs on resources) that applies inside one namespace. |
|
A set of rules that is cluster-wide: for cluster-scoped resources (nodes, PersistentVolumes), for non-resource URLs, or as a reusable template bound per namespace. |
|
Grants a Role or ClusterRole to subjects (users, groups, ServiceAccounts) within a namespace. |
|
Grants a ClusterRole to subjects across all namespaces. |
Rules name apiGroups, resources (and optionally resourceNames or subresources such as pods/log) and verbs
(get, list, watch, create, update, patch, delete, deletecollection, plus special verbs bind,
escalate, impersonate).
Example: the notifier reads one ConfigMap
The Bookshelf notifier needs to read its own ConfigMap (see ConfigMaps) and
nothing else. Restricting by resourceNames narrows it to that object.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: notifier-config-reader
namespace: bookshelf
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["notifier-config"]
verbs: ["get", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: notifier-config-reader
namespace: bookshelf
subjects:
- kind: ServiceAccount
name: notifier
namespace: bookshelf
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: notifier-config-reader
Note that list and watch with resourceNames only work when the client uses a field selector on the name; a plain
list needs an unrestricted rule.
Example: a CI deployer scoped to one namespace
A pipeline that applies manifests to bookshelf should not be a cluster administrator. Bind a narrow Role to its
ServiceAccount (see GitOps and CI/CD).
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ci-deployer
namespace: bookshelf
rules:
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["services", "configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ci-deployer
namespace: bookshelf
subjects:
- kind: ServiceAccount
name: ci-deployer
namespace: bookshelf
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: ci-deployer
Deliberately absent are secrets (reading Secrets is effectively reading credentials), rolebindings (to prevent
privilege escalation) and delete. The API server also prevents a user from creating a Role or binding that grants
permissions they do not hold themselves, unless they have the escalate or bind verb.
Testing permissions
kubectl auth can-i create deployments -n bookshelf \
--as=system:serviceaccount:bookshelf:ci-deployer
kubectl auth can-i get secrets -n bookshelf \
--as=system:serviceaccount:bookshelf:ci-deployer
kubectl auth can-i --list -n bookshelf --as=system:serviceaccount:bookshelf:notifier
yes
no
Resources Non-Resource URLs Resource Names Verbs
configmaps [] [notifier-config] [get watch]
Aggregation and default roles
A ClusterRole with an aggregationRule collects the rules of every ClusterRole matching a label selector. The built-in
user-facing roles admin, edit and view are aggregated this way, so a CRD author extends them by adding a ClusterRole
labelled rbac.authorization.k8s.io/aggregate-to-edit: "true" (see
Custom Resources and Operators). Other defaults to know:
-
cluster-admin— everything, everywhere. Binding it to a group is a serious decision; bind it to a namespace (through a RoleBinding referencingadmin) instead wherever possible. -
admin,edit,view— namespace-scoped developer roles, usually granted with a RoleBinding. -
system:*roles and bindings for control-plane components, kubelets andsystem:authenticatedusers, which you should not edit; kubeadm and the API server reconcile them at start-up.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: bookshelf-monitoring-view
labels:
rbac.authorization.k8s.io/aggregate-to-view: "true"
rules:
- apiGroups: ["bookshelf.example.com"]
resources: ["reports"]
verbs: ["get", "list", "watch"]
RBAC good practices
-
Grant the minimum verbs and resources; avoid wildcards (
*) and avoidcluster-adminfor humans and pipelines. -
Prefer namespaced Roles and RoleBindings over ClusterRoleBindings.
-
Be careful with
secretsreads,pods/exec,pods/attach,impersonate,escalate,bind, and the ability to create Pods: anyone who can create a Pod in a namespace can mount any Secret or ServiceAccount there. -
One ServiceAccount per workload; disable token automounting where unused.
-
Bind to groups supplied by your identity provider rather than individual users, and review bindings periodically (
kubectl get rolebindings,clusterrolebindings -A).