Here's a fun game. Run this in your cluster and read what comes back:
kubectl get clusterrolebindings -o json | \
jq '.items[] | select(.roleRef.name=="cluster-admin") | .subjects'
I'll wait.
If you saw more than two entries — probably just kube-system service accounts — you have an RBAC problem. If you saw service accounts from your own applications, CI pipelines, or external tools with cluster-admin, you have a very serious RBAC problem that's been sitting there, quietly, waiting.
π€ Why RBAC Feels Secure When It Isn't
RBAC gives you the tools to implement least privilege. It does not implement it for you. And because misconfigured RBAC doesn't immediately cause visible errors — everything just keeps working — the problems accumulate silently for months or years.
An application with overly broad permissions doesn't fail. It runs perfectly fine. Right up until someone exploits that permission — through a compromised container, a misconfigured webhook, or a dependency with a supply chain issue.
π§ How Kubernetes RBAC Actually Works
RBAC in Kubernetes is built on four objects. You need to understand all four or you'll keep making the same mistakes.
- Role — namespace-scoped permissions. Only applies within one namespace.
- ClusterRole — cluster-wide permissions. Applies everywhere or can be bound per-namespace.
- RoleBinding — links a subject (user, group, service account) to a Role or ClusterRole, in one namespace.
- ClusterRoleBinding — links a subject to a ClusterRole across the entire cluster.
π Most RBAC mistakes come from using ClusterRole + ClusterRoleBinding when a Role + RoleBinding would've been sufficient and much safer.
⚙️ The Most Common RBAC Misconfigurations
1. cluster-admin handed out like candy
# This pattern is everywhere and it's dangerous
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: my-app-admin # innocuous name, catastrophic permissions
subjects:
- kind: ServiceAccount
name: my-app
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin # full god-mode access to everything
Why does this happen? Because it works immediately, with no debugging, and the engineer under deadline pressure moves on. Technical debt with cluster-wide blast radius.
2. Wildcard verbs and resources
# Also very common, also very bad
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
This is cluster-admin wearing a disguise. Same permissions, different name.
3. Service accounts with more scope than needed
# What your CI pipeline actually needs:
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "patch", "update"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
# What it usually gets: cluster-admin "because Helm needs it"
π‘️ What Production-Grade RBAC Actually Looks Like
# Scoped service account for a typical web application
apiVersion: v1
kind: ServiceAccount
metadata:
name: web-app
namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: web-app-role
namespace: production
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["web-app-credentials"] # only THIS secret, not all secrets
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: web-app-binding
namespace: production
subjects:
- kind: ServiceAccount
name: web-app
namespace: production
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: web-app-role
π Notice the resourceNames field. This restricts access to a specific named Secret rather than all secrets in the namespace. Almost nobody uses this. It's one of the most powerful and underused RBAC controls available.
⚠️ Common Mistakes
- Giving Helm cluster-admin "because it's easier" — Helm doesn't need cluster-admin. It needs permissions to manage the resources it actually deploys. Scope it to the namespaces it touches.
- Forgetting that aggregated ClusterRoles inherit permissions — The
view,edit, andadminbuilt-in roles aggregate permissions from anything labeledrbac.authorization.k8s.io/aggregate-to-view: "true". CRDs can accidentally expand these roles. - Not auditing when people or services leave — Old bindings for decommissioned CI tools are extremely common. Run
kubectl auth reconcileand clean up regularly.
π₯ CloudChef Pro Tip
Use rbac-tool to visualise what you actually have.
# Install and audit your RBAC graph
kubectl krew install rbac-tool
kubectl rbac-tool who-can get secrets -n production
π That last command will show you every subject that can read Secrets in your production namespace. The list is almost always longer than expected. Fix the surprises first.
π Continue Your CloudChef Journey
π References
π Final Thoughts
RBAC is not a checkbox. It's a continuous practice. Build the minimal permissions first, document why each permission exists, and review it when roles change. The five minutes spent scoping a service account correctly today is worth considerably more than the incident response you'll avoid later.
π Start with that cluster-admin audit command at the top of this article. Whatever you find — fix it this week.
No comments:
Post a Comment