Advanced Kubernetes Operations

RBAC in Depth

18 min Lesson 1 of 30

RBAC in Depth

Role-Based Access Control (RBAC) is Kubernetes' primary authorization mechanism. Every production cluster — from a 10-node startup deployment to a thousands-of-nodes fleet at a top-tier cloud provider — depends on RBAC being configured correctly. Get it wrong and you either lock engineers out of their own clusters or, far worse, give compromised workloads the ability to read secrets across every namespace or pivot to the control plane.

This lesson builds a thorough mental model: what RBAC checks, how the API server evaluates it, and how senior SREs design least-privilege policies that hold up under a security audit.

How the API Server Evaluates a Request

Every request arriving at the Kubernetes API server passes through a pipeline: Authentication → Authorization → Admission Control. RBAC sits in the Authorization phase. The API server asks a single question: "Does this identity, operating on this resource in this namespace, have permission to perform this verb?"

Kubernetes denies by default. A request is allowed only if at least one RBAC policy explicitly grants it. There is no concept of deny rules — you model restrictions by simply not granting the permission in the first place.

RBAC request evaluation flow in the Kubernetes API server kubectl / Service Account Authn Who are you? (cert / token) Authz (RBAC) Role + Binding verb + resource allow / deny Admission Mutating / Validating webhooks etcd persist
Kubernetes API request pipeline: Authentication → RBAC Authorization → Admission Control → etcd.

The Four Core RBAC Objects

RBAC uses four resource kinds arranged in two pairs:

  • Role — grants permissions within a single namespace.
  • ClusterRole — grants permissions cluster-wide, or on non-namespaced resources such as Nodes, PersistentVolumes, and Namespaces themselves.
  • RoleBinding — binds a Role or a ClusterRole to subjects inside one namespace.
  • ClusterRoleBinding — binds a ClusterRole to subjects cluster-wide.

A common production pattern is to define a ClusterRole once (for example, pod-reader) and then use per-namespace RoleBindings to grant it only where needed. This avoids duplicating identical role manifests across dozens of namespaces.

Subjects: Users, Groups, and ServiceAccounts

Bindings attach to three kinds of subject:

  • User — a human identity asserted by the authenticator (certificate CN field or OIDC sub claim). Kubernetes has no User resource; the name is just a string.
  • Group — a set of users, typically driven by OIDC group claims or the certificate Organization field. Binding to groups (e.g., team-platform) is far more maintainable than binding individual users.
  • ServiceAccount — a namespaced Kubernetes object, automatically mounted as a projected JWT into every pod. This is how workloads authenticate to the API server at runtime.
The system: prefix is reserved. Built-in subjects like system:authenticated, system:serviceaccounts:kube-system, and system:masters are managed by Kubernetes. Never create custom users or groups with this prefix — they may collide with internal bindings or break on a cluster upgrade.

Writing Least-Privilege Manifests

The production baseline: every workload runs under its own dedicated ServiceAccount with only the verbs it actually exercises. The default ServiceAccount in every namespace mounts a token automatically — disable this for workloads that make no Kubernetes API calls.

# Create a dedicated ServiceAccount kubectl create serviceaccount metrics-reader -n monitoring --- # Role: read-only access to pods and their logs in the monitoring namespace apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: pod-log-reader namespace: monitoring rules: - apiGroups: [""] # core API group resources: ["pods", "pods/log"] verbs: ["get", "list", "watch"] --- # Bind the Role to the ServiceAccount apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: metrics-reader-pod-logs namespace: monitoring subjects: - kind: ServiceAccount name: metrics-reader namespace: monitoring roleRef: kind: Role name: pod-log-reader apiGroup: rbac.authorization.k8s.io --- # Deployment using the ServiceAccount apiVersion: apps/v1 kind: Deployment metadata: name: metrics-collector namespace: monitoring spec: template: spec: serviceAccountName: metrics-reader automountServiceAccountToken: true # true only because this pod needs API access
Disable auto-mount globally, enable per pod. In the ServiceAccount spec set automountServiceAccountToken: false as the default. Then set automountServiceAccountToken: true only on the pods that actually call the Kubernetes API. This eliminates the token attack surface on every batch job, frontend pod, and database workload in the cluster.

Aggregated ClusterRoles

Kubernetes ships three default ClusterRoles built for humans: view, edit, and admin. They use aggregation — a label selector that automatically pulls in rules from any ClusterRole carrying a matching label. When you install a CRD (custom resource) and want it visible to users who already hold view, you add this to your CRD's ClusterRole:

apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: my-operator-view labels: rbac.authorization.k8s.io/aggregate-to-view: "true" # auto-merged into the built-in view role rules: - apiGroups: ["mycompany.io"] resources: ["myresources"] verbs: ["get", "list", "watch"]

Auditing Permissions: Who Can Do What?

Before a production launch or a compliance review, you need to enumerate exactly what each identity can do. kubectl auth can-i answers single questions, while the rakkess and kubectl-who-can plugins give you a full matrix view.

# Can the current user create deployments in the production namespace? kubectl auth can-i create deployments -n production # Impersonate a ServiceAccount to audit its permissions kubectl auth can-i list secrets \ --as=system:serviceaccount:monitoring:metrics-reader \ -n production # List all subjects that can delete pods in the production namespace # (requires kubectl-who-can plugin: kubectl krew install who-can) kubectl who-can delete pods -n production # Enumerate ALL permissions a ServiceAccount has (requires rakkess plugin) kubectl rakkess --sa monitoring:metrics-reader # Check if RBAC is enabled at the cluster level kubectl api-versions | grep authorization.k8s.io
Watch for * wildcards and escalate/bind verbs. A role with verbs: ["*"] or resources: ["*"] is effectively cluster admin within its scope. The escalate verb lets a subject create Roles with more permissions than they currently hold; the bind verb lets them attach ClusterRoles to arbitrary subjects. Both are privilege-escalation vectors that should never appear in developer-facing roles. Audit for them regularly with: kubectl get clusterroles -o json | jq '.items[] | select(.rules[].verbs[] | contains("escalate","bind"))'.

Least-Privilege Principles at Scale

Large organizations operationalize RBAC through a few proven patterns:

  1. GitOps all RBAC manifests. Store every Role, ClusterRole, RoleBinding, and ClusterRoleBinding in Git. No manual kubectl create role in production — pull requests enforce peer review, and drift is caught automatically.
  2. Namespace-per-team isolation. Each team owns exactly the namespaces assigned to them; their ServiceAccounts have no cross-namespace permissions. Shared platform services use dedicated namespaces with explicitly scoped bindings.
  3. Time-bound escalation. For break-glass scenarios, grant cluster-admin via a ClusterRoleBinding with an ownerReference pointing to a TTL-based Job, or use tools like Teleport or Pomerium for JIT (just-in-time) access that auto-revokes after a session ends.
  4. Regular permission reviews. Run kubectl auth reconcile --dry-run to detect drift. Schedule quarterly audits that compare current bindings against the GitOps-declared state and flag any ServiceAccount with secrets get or namespace-wide create permissions.
RBAC does not restrict data-plane traffic. A pod with no RBAC permissions can still open TCP connections to other pods. Network Policies (lesson 5 in the networking tutorial) and service meshes with mutual TLS handle workload-to-workload authorization — RBAC only governs Kubernetes API access.

Mastering RBAC is what separates engineers who can deploy Kubernetes from engineers who can operate it safely. Every concept in this tutorial — admission webhooks, custom operators, multi-tenancy — rests on the RBAC foundation you have built here.