RBAC minimization
Least privilege and the grants that are really escalation.
Once a request is authenticated, RBAC decides whether it is allowed — and it is the control that most often drifts toward over-permission, because granting access fixes a broken deployment in seconds and nobody ever comes back to tighten it. RBAC is purely additive and default-deny: nothing is permitted unless some binding grants it, and there are no deny rules, so minimization is a subtraction game played against grants that quietly accumulated.
Four objects, two pairs. A Role (namespaced) or ClusterRole (cluster-wide) holds rules — combinations of apiGroups, resources, and verbs. A RoleBinding or ClusterRoleBinding attaches a role to subjects: users, groups, or service accounts. The useful trick is that a RoleBinding can reference a ClusterRole, reusing one role definition namespace-by-namespace without granting it cluster-wide.
apiVersion: rbac.authorization.k8s.io/v1kind: Role # namespacedmetadata: { namespace: payments, name: deployer }rules:- apiGroups: ["apps"]resources: ["deployments"]verbs: ["get", "list", "update", "patch"] # named verbs, never ["*"]---apiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata: { namespace: payments, name: ci-deployer }subjects:- kind: ServiceAccountname: deployernamespace: ciroleRef: { kind: Role, name: deployer, apiGroup: rbac.authorization.k8s.io }
Audit what already exists
Start by finding the over-grants. List everyone bound to cluster-admin, hunt for wildcard verbs or resources, and use kubectl auth can-i — the authoritative query, because it runs the real authorizer — to ask what a given subject can actually do, impersonating it with --as.
# every subject bound to cluster-admin$ kubectl get clusterrolebindings -o json | jq -r '.items[] | select(.roleRef.name=="cluster-admin") | .subjects[]?.name'# what can this service account really do, and can it do the scary thing?$ kubectl auth can-i --list --as=system:serviceaccount:ci:deployer -n payments$ kubectl auth can-i create pods --as=system:serviceaccount:ci:deployer -n kube-systemno
The grants that are really escalation
Some permissions are far more dangerous than they read because they let a subject grant themselves more, or reach past the namespace. secrets:get reads every credential in scope. pods/exec is an interactive shell into any pod. create pods lets a subject mount any service account (including a powerful one) and inherit its token. And the verbs escalate, bind, and impersonate are literally self-promotion. Treat all of these as near-admin.