Skip to main content
RunBook Academy

KubernetesXIV · Namespace ArchitectureTenancy and isolation

RBAC and Roles per namespace — least privilege as tenancy boundary

Advanced⏱ ~16 minkubectl

What you'll learn

  • Explain how Roles and RoleBindings scope RBAC to a namespace
  • Distinguish Role from ClusterRole and RoleBinding from ClusterRoleBinding
  • Apply the principle of least privilege per namespace
  • Audit RBAC bindings for production safety

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

RBAC is the access-control mechanism that turns namespaces into real tenancy boundaries. This lesson covers Roles, RoleBindings, ClusterRoles, and ClusterRoleBindings; the production patterns for least-privilege per namespace; and the audit discipline.

Roles vs ClusterRoles

# Role: namespace-scoped
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
  namespace: team-a-prod
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# ClusterRole: cluster-wide (or aggregated)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-reader
rules:
- apiGroups: [""]
  resources: ["nodes", "nodes/metrics"]
  verbs: ["get", "list", "watch"]

Two role kinds:

  • Role: namespaced. Applies to resources within a single namespace. Cannot reference cluster-scoped resources.
  • ClusterRole: cluster-scoped. Applies to cluster-scoped resources (Nodes, ClusterRoles, etc.) or to all namespaces (with a ClusterRoleBinding).

For per-namespace access control, use Role. For cluster-wide access (operators, monitoring), use ClusterRole.

RoleBindings vs ClusterRoleBindings

# RoleBinding: grants a Role or ClusterRole in one namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: team-a-developers
  namespace: team-a-prod
subjects:
- kind: Group
  name: team-a-developers
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer
  apiGroup: rbac.authorization.k8s.io
# ClusterRoleBinding: grants a ClusterRole cluster-wide
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-admins
subjects:
- kind: Group
  name: cluster-admins
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

Two binding kinds:

  • RoleBinding: grants a Role (or ClusterRole) in a specific namespace.
  • ClusterRoleBinding: grants a ClusterRole cluster-wide.

For per-namespace access, use RoleBinding.

The RBAC model

flowchart LR
    SA[ServiceAccount / User / Group] --> Binding[RoleBinding / ClusterRoleBinding]
    Binding --> Role[Role / ClusterRole]
    Role --> Verbs["verbs: get, list, watch, create, update, patch, delete"]
    Role --> Resources["resources: pods, services, ..."]
    Role --> APIGroups["apiGroups: '', apps, batch, ..."]

Three concepts:

  • Subject: who gets access (User, Group, ServiceAccount).
  • Binding: the linkage between subject and role (RoleBinding or ClusterRoleBinding).
  • Role: what access is granted (verbs on resources in apiGroups).

A request from a user is checked: the user must be in a subject that is bound to a role that grants the verb on the resource in the API group.

Production patterns

Per-team namespace with team-specific Role:

# Role for team-a developers (in team-a-prod)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
  namespace: team-a-prod
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps", "secrets"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: team-a-developers
  namespace: team-a-prod
subjects:
- kind: Group
  name: team-a-developers
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer
  apiGroup: rbac.authorization.k8s.io

This setup:

  • Team-a developers can create, update, and delete Pods, Services, ConfigMaps, Secrets, Deployments, StatefulSets in team-a-prod.
  • Team-a developers cannot access other namespaces (no RoleBinding there).
  • Team-a developers cannot access cluster-scoped resources (Nodes, ClusterRoles, etc.).

Read-only role for on-call:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: read-only
rules:
- apiGroups: [""]
  resources: ["*"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps", "batch", "networking.k8s.io"]
  resources: ["*"]
  verbs: ["get", "list", "watch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: on-call-readonly
subjects:
- kind: Group
  name: on-call
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: read-only
  apiGroup: rbac.authorization.k8s.io

The on-call group can read all resources cluster-wide but cannot modify anything. Useful for incident response without granting destructive access.

The principle of least privilege

For every binding, ask: does the subject need exactly this access?

  • Don’t grant * verbs: list specific verbs (get, list, create, etc.).
  • Don’t grant * resources: list specific resources (pods, services, configmaps).
  • Don’t grant cluster-wide access: scope to a namespace when possible.
  • Don’t include Secrets in developer roles: developers don’t need to read Secrets; the application reads them.

Production discipline: the smaller the role, the safer the cluster. A team that has cluster-admin is one bug away from disaster.

Aggregated ClusterRoles

Kubernetes has built-in ClusterRoles that aggregate other roles:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: admin
  labels:
    rbac.authorization.k8s.io/aggregate-to-admin: "true"
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps", ...]
  verbs: ["*"]

The rbac.authorization.k8s.io/aggregate-to-admin: "true" label tells Kubernetes to merge this role’s rules into the admin ClusterRole. Custom controllers can extend built-in roles by adding aggregated ClusterRoles.

ServiceAccounts as subjects

Pods authenticate to the API server via ServiceAccounts. RBAC can grant a ServiceAccount a role:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: cert-manager
  namespace: cert-manager
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cert-manager-controller
rules:
- apiGroups: ["cert-manager.io"]
  resources: ["*"]
  verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cert-manager-controller
subjects:
- kind: ServiceAccount
  name: cert-manager
  namespace: cert-manager
roleRef:
  kind: ClusterRole
  name: cert-manager-controller
  apiGroup: rbac.authorization.k8s.io

The cert-manager Pod uses this ServiceAccount and gets the cert-manager-controller ClusterRole. Production discipline: ServiceAccounts are application identities; grant them exactly the access they need.

Auditing RBAC

# List all ClusterRoleBindings
kubectl get clusterrolebindings -o wide

# List all RoleBindings in a namespace
kubectl get rolebindings -n team-a-prod -o wide

# Check what access a user has
kubectl auth can-i create pods --as alice -n team-a-prod

# Check what access a ServiceAccount has
kubectl auth can-i list secrets --as system:serviceaccount:team-a-prod:default -n team-a-prod

# Find subjects with cluster-admin
kubectl get clusterrolebindings -o json | \
  jq '.items[] | select(.roleRef.name=="cluster-admin") | .subjects'

Production discipline: run kubectl auth can-i checks regularly; audit RoleBindings and ClusterRoleBindings.

Cross-course references

  • The Linux course part XXVI-Linux-SSH covers authentication and authorisation; RBAC is the cluster-level equivalent.
  • The Linux course part XXVII-Linux-Auth covers identity management; ServiceAccounts are the cluster-level equivalent.
  • The Docker course part XXXVIII-Docker-Secrets covers secret access patterns; Kubernetes RBAC for Secrets is the cluster-level equivalent.

Quiz

Knowledge check · 4 questions

  1. Q1. Which combination is the right choice for granting team-a developers access to their own namespace only?

  2. Q2. Production discipline says to grant the smallest role that lets the workload or user do their job.

  3. Q3. An audit reveals that a developer has `cluster-admin` access via a direct RoleBinding. Walk through the risk and the fix.

    A developer `alice` was granted cluster-admin to debug an issue six months ago. The issue was fixed; the access was never revoked. Alice is still in the `cluster-admin` ClusterRoleBinding. The audit tool flags this.

  4. Q4. How do you grant a Pod's ServiceAccount access to read ConfigMaps in its own namespace?

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • Use Role + RoleBinding for namespace-scoped access. ClusterRole + ClusterRoleBinding is for cluster-wide only.
  • Apply the principle of least privilege. List specific verbs and resources; exclude Secrets unless needed.
  • Audit RBAC bindings regularly. kubectl auth can-i checks; review cluster-admin grants.
  • Use ServiceAccounts for application access. Pods authenticate as their ServiceAccount; grant that SA exactly what it needs.
  • Revoke standing high-privilege access. Cluster-admin grants should be temporary, not standing.