Adetayo Akinsanya unkletayo.dev

Cluster Security & Authorization: RBAC, ServiceAccounts, and Admission Webhooks

Understanding the 3-phase API security pipeline: Authentication, Authorization, and Admission Control.

Part 17 in Series — Catch up on the previous article: Kubernetes Scheduler Internals: Filtering (Predicates), Scoring (Priorities), and Affinities (Part 16) before diving into this post.

An attacker gains Remote Code Execution (RCE) inside a vulnerable web analytics Pod running in a production Kubernetes cluster.

The attacker checks the local filesystem and discovers a JWT token automatically mounted by Kubernetes:

cat /var/run/secrets/kubernetes.io/serviceaccount/token

Using this token, the attacker issues a curl request directly to the internal API server:

curl -k -H "Authorization: Bearer $(cat /var/run/.../token)" \
  https://kubernetes.default.svc/api/v1/namespaces/default/pods

In an unhardened cluster, the API Server responds with HTTP 200 OK and returns full cluster secrets, node IP lists, and pod manifests.

The attacker uses the token to delete production workloads across the entire cluster.

When the cluster enforces strict Role-Based Access Control (RBAC) and Admission Webhooks:

The API Server immediately rejects the attacker’s request with:

Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:web-api" cannot list resource "pods" in API group "" in the namespace "default"

How does kube-apiserver secure cluster access using Authentication, RBAC Authorization, and Admission Webhooks?


1. The 3-Phase API Security Pipeline

Every HTTP request submitted to kube-apiserver must pass through a strict 3-phase security pipeline before any state modification is written to etcd:

[ Incoming HTTP REST Request ]
              |
              v
+-------------------------------------------------------------------+
| PHASE 1: AUTHENTICATION (Who are you?)                            |
| Validates identity via X.509 Certs, OIDC Tokens, or ServiceAccount|
+-------------------------------------------------------------------+
              |
              v  Authenticated Subject (User / ServiceAccount)
+-------------------------------------------------------------------+
| PHASE 2: AUTHORIZATION (What are you allowed to do?)              |
| Evaluates RBAC Rules (Roles, ClusterRoles, RoleBindings)          |
+-------------------------------------------------------------------+
              |
              v  Authorized Request
+-------------------------------------------------------------------+
| PHASE 3: ADMISSION CONTROL (Is the payload valid & compliant?)    |
| Executed by Mutating Webhooks & Validating Webhooks               |
+-------------------------------------------------------------------+
              |
              v  Validated Payload
[ Persist State Change to etcd Storage ]

2. Phase 1: Authentication (ServiceAccounts & Identity)

Kubernetes distinguishes between two types of identities:

  1. Human Users: Authenticated via X.509 Client Certificates, OIDC providers (Okta, Google Workspace), or Webhook tokens. (Kubernetes does not store user accounts in etcd).
  2. ServiceAccounts: Managed identities stored in etcd assigned to Pods for in-cluster API communication.
apiVersion: v1
kind: ServiceAccount
metadata:
  name: payment-processor-sa
  namespace: production

When a Pod runs with serviceAccountName: payment-processor-sa, the Kubelet automatically projects a short-lived, auto-rotating JWT ServiceAccount token into /var/run/secrets/kubernetes.io/serviceaccount/token.


3. Phase 2: Authorization (RBAC Mechanics)

Once identity is authenticated, the API Server evaluates Role-Based Access Control (RBAC).

RBAC uses four core objects to define permissions:

                          RBAC ARCHITECTURE
                                    |
     +------------------------------+------------------------------+
     |                                                             |
     v                                                             v
[ Permissions Definition ]                           [ Identity Binding ]
- Role (Namespace-Scoped)                            - RoleBinding (Namespace-Scoped)
- ClusterRole (Cluster-Wide)                         - ClusterRoleBinding (Cluster-Wide)

Defining Permissions (Role / ClusterRole)

A Role grants permissions on specific API Groups, Resources, and Verbs (get, list, watch, create, update, delete):

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates core API group
  resources: ["pods", "configmaps"]
  verbs: ["get", "list", "watch"] # NO 'delete' or 'create' permissions!

Binding Permissions (RoleBinding)

A RoleBinding links a Role to a ServiceAccount or User:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods-binding
  namespace: production
subjects:
- kind: ServiceAccount
  name: payment-processor-sa
  namespace: production
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Least-Privilege Security Principle: Grant ServiceAccounts minimum required verbs on specific namespaces. Never assign cluster-admin bindings to application workloads!


4. Phase 3: Admission Control & Webhooks

Even if an authenticated request is authorized by RBAC, it must pass Admission Controllers.

Admission controllers inspect and modify request payloads before they are written to etcd.

[ Authorized Request ]
          |
          v
+-------------------------------------------------------------------+
| 1. Mutating Admission Webhooks                                    |
|    Modifies payload (e.g., injects Istio sidecar, adds default labels)|
+-------------------------------------------------------------------+
          |
          v
+-------------------------------------------------------------------+
| 2. Object Schema Validation                                       |
|    Verifies YAML schema syntax and data types                     |
+-------------------------------------------------------------------+
          |
          v
+-------------------------------------------------------------------+
| 3. Validating Admission Webhooks                                  |
|    Validates rules (e.g., blocks root containers, enforces limits)|
|    Returns ALLOW or REJECT                                        |
+-------------------------------------------------------------------+

A. Mutating Admission Webhooks

Can modify incoming resource manifests.

  • Use Case: Linkerd or Istio service meshes use Mutating Webhooks to automatically inject sidecar proxy containers into newly created Pod manifests.

B. Validating Admission Webhooks

Can accept or reject incoming resource manifests.

  • Use Case: Policy engines (OPA Gatekeeper, Kyverno) execute business rules (e.g., “Reject any Pod where image uses tag :latest or runs as root”).

Summary & Next Steps

Kubernetes enforces security across a 3-phase execution pipeline:

  • Authentication verifies identity via X.509 client certificates or ServiceAccount JWT tokens.
  • RBAC Authorization enforces least-privilege permissions by linking ServiceAccounts to Roles (get, list, watch).
  • Mutating Webhooks modify incoming resource manifests (e.g., sidecar injection).
  • Validating Webhooks enforce cluster security compliance policies before persisting state changes to etcd.

In the next article, we examine Extending Kubernetes: Custom Resource Definitions (CRDs) and the Operator Pattern.

References & Further Reading

  1. CNCF Istio Project. Istio Service Mesh Architecture & Envoy xDS Control Plane. Istio Docs.
  2. CNCF Linkerd Project. Linkerd Lightweight Rust-based Service Mesh Architecture. Linkerd Docs.
  3. Posta, C. (2021). Istio in Action. Manning Publications.

Up Next in Series →

Part 18: Extending Kubernetes: Custom Resource Definitions (CRDs) and the Operator Pattern

Continue to Part 18 →