Skip to content

RBAC Basics

Lab scenario ~30 min

RBAC is the front door of cluster security. Get it right and everything else — audit, secrets, policies — gets easier. Get it wrong and a compromised pod owns your cluster.

  • Role / ClusterRole — a set of verbs on resources. No principal attached.
  • RoleBinding / ClusterRoleBinding — glues a Role to a subject (user, group, or ServiceAccount).
  • Namespace-scoped vs cluster-scopedRole lives in one namespace; ClusterRole is cluster-wide.

We’ll create a ServiceAccount that can deploy to payments namespace and nothing else.

  • Directoryrbac/
    • 00-namespace.yaml
    • 01-serviceaccount.yaml
    • 02-role.yaml
    • 03-rolebinding.yaml
  1. Create the namespace

    rbac/00-namespace.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
    name: payments
    labels:
    team: payments
  2. Create the ServiceAccount

    rbac/01-serviceaccount.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: deployer
    namespace: payments
  3. Define the Role

    rbac/02-role.yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
    name: deployer
    namespace: payments
    rules:
    - apiGroups: ["apps"]
    resources: ["deployments", "statefulsets"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
    - apiGroups: [""]
    resources: ["configmaps", "secrets"]
    verbs: ["get", "list", "create", "update"]
  4. Bind the Role

    rbac/03-rolebinding.yaml
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
    name: deployer
    namespace: payments
    subjects:
    - kind: ServiceAccount
    name: deployer
    namespace: payments
    roleRef:
    kind: Role
    name: deployer
    apiGroup: rbac.authorization.k8s.io
  5. Apply and verify

    Terminal window
    kubectl apply -f rbac/
    kubectl auth can-i create deployments \
    --as=system:serviceaccount:payments:deployer \
    --namespace=payments
    # → yes
    kubectl auth can-i delete pods \
    --as=system:serviceaccount:payments:deployer \
    --namespace=payments
    # → no

Diff: from “cluster-admin lite” to least-privilege

Section titled “Diff: from “cluster-admin lite” to least-privilege”

A common anti-pattern: giving a CI/CD SA cluster-admin because “it’s easier”. Here’s the fix in context.

ci-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: ci-deployer
- roleRef: { kind: ClusterRole, name: cluster-admin, apiGroup: rbac.authorization.k8s.io }
+ roleRef:
+ kind: ClusterRole
+ name: ci-deployer
+ apiGroup: rbac.authorization.k8s.io
+ # ClusterRole scoped to `apps` and `batch` only — see previous file
+ # Bound per-namespace via a RoleBinding, not cluster-wide.
subjects:
- kind: ServiceAccount
name: ci
namespace: ci-system
Terminal window
# who can do what in a namespace
kubectl auth can-i --list --namespace=payments \
--as=system:serviceaccount:payments:deployer
# all bindings referencing a service account
kubectl get rolebindings,clusterrolebindings -A -o json \
| jq '.items[] | select(.subjects[]?.name == "deployer") | .metadata'