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

flowchart LR C["Client\nkubectl, kubelet, Pod, controller"] -->|HTTPS| TLS["TLS termination"] TLS --> AUTHN["Authentication\nwho is this?"] AUTHN -->|identity established| AUTHZ["Authorization\nmay they do this?"] AUTHN -->|no authenticator matches| R401["401 Unauthorized"] AUTHZ -->|allowed| MUT["Mutating admission\nwebhooks, MutatingAdmissionPolicy"] AUTHZ -->|denied| R403["403 Forbidden"] MUT --> SCHEMA["Object schema validation"] SCHEMA --> VAL["Validating admission\nValidatingAdmissionPolicy, webhooks"] VAL --> ETCD["Persist to etcd"]

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 AuthenticationConfiguration file. The usual choice for humans.

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.

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

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

Role

A set of rules (verbs on resources) that applies inside one namespace.

ClusterRole

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.

RoleBinding

Grants a Role or ClusterRole to subjects (users, groups, ServiceAccounts) within a namespace.

ClusterRoleBinding

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 referencing admin) instead wherever possible.

  • admin, edit, view — namespace-scoped developer roles, usually granted with a RoleBinding.

  • system:* roles and bindings for control-plane components, kubelets and system:authenticated users, 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 avoid cluster-admin for humans and pipelines.

  • Prefer namespaced Roles and RoleBindings over ClusterRoleBindings.

  • Be careful with secrets reads, 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).