RBAC in Kubernetes: Technical Guardrails and Human Weaknesses
Kubernetes RBAC is one of those things everyone agrees is important, but very few people are excited to touch.
It’s powerful. It’s flexible. It’s also a fantastic way to accidentally give half your cluster the keys to the kingdom while telling yourself it’s fine because “it’s just internal”.
RBAC is meant to be a guardrail. In reality, it often becomes a mirror, reflecting how teams actually behave under pressure, deadlines, and vague ownership.
RBAC does exactly what you tell it to do
At its core, Kubernetes RBAC is simple.
You define:
Roles: what actions are allowed
RoleBindings: who gets those actions
Subjects: users, groups, or service accounts
Kubernetes enforces it ruthlessly. There’s no guessing intent. No “they probably didn’t mean that”. If a subject can do something, it’s because you explicitly allowed it.
Which means most RBAC failures aren’t Kubernetes problems. They’re human ones.
The “just give it cluster-admin” phase
Almost every cluster goes through this phase.
Something breaks. A deployment won’t start. A controller can’t list resources. Someone is blocked and it’s usually five minutes before a demo.
So we do the thing.
“Just give it cluster-admin for now.”
“We’ll lock it down later.”
“It’s only non-prod.”
This is how RBAC slowly turns into a flat permission model with extra YAML.
Cluster-admin becomes the universal solvent. It fixes the immediate issue while quietly removing every safety net RBAC was supposed to provide. And once it’s in place, nobody wants to be the person who takes it away and breaks things again.
Over-permissioning feels safer than under-permissioning
From a human perspective, over-permissioning feels helpful.
People hate being blocked. They hate vague errors. They hate waiting on approvals from someone who might be in a different time zone or on holiday.
So roles get broader.
Wildcards sneak in.
Read becomes write.
Write becomes admin.
The intention is good. The outcome is not.
RBAC designed around convenience tends to age badly. What made sense for one workload becomes inherited by ten others. Access granted for debugging becomes permanent. Nobody remembers why a service account can delete namespaces, but everyone is afraid to remove it.
AKS makes the gap very obvious
If you’re running AKS, the RBAC story gets an extra layer that looks richer on paper than it feels in practice.
Azure RBAC for AKS has expanded well beyond the old days of “admin or user”. You now have roles like Cluster Admin, Cluster User, Contributor, Monitoring User, and even Namespace User and Namespace Contributor.
This is progress. It’s definitely better than it used to be.
But most of these roles still operate at the Azure management plane.
They control who can:
Access cluster credentials
Read or modify the AKS resource in Azure
Interact with namespace resources from an Azure perspective
What they don’t really describe is what someone can do inside the cluster once they’re authenticated.
Azure RBAC gets you through the front door. Kubernetes RBAC decides what cupboards you can open once you’re inside.
There’s no Azure role that neatly says “can deploy workloads but not read secrets” or “can restart pods but not touch RBAC”. That level of least privilege lives squarely in Kubernetes RBAC.
This is where the two models are meant to meet.
You can bind Kubernetes Roles and ClusterRoles to Entra ID backed security groups using RoleBindings. Azure stays the source of truth for identity and group membership, while Kubernetes handles the fine-grained permissions in-cluster.
That means:
Access is still managed centrally in Azure
Joiners, movers, and leavers are handled without cluster archaeology
Permissions aren’t trapped in IaC or forgotten YAML
Azure RBAC sets the boundaries. Kubernetes RBAC fills in the detail. Without both, least privilege is mostly aspirational.
Service accounts are people too (sort of)
RBAC discussions often focus on humans, but service accounts are where things really get spicy.
They don’t complain.
They don’t raise tickets.
They just quietly accumulate permissions.
A CI pipeline needs to deploy a Helm chart. Fine.
Now it also needs to manage CRDs. Sure.
Now it needs access across namespaces. Why not.
Before long, you have machine identities with more power than most humans, often backed by long-lived tokens sitting in build logs, artefact stores, or secret managers nobody audits anymore.
RBAC worked perfectly. We just kept saying yes.
Namespaces don’t fix trust problems
Namespaces are often treated as a security boundary. They help, but they’re not magic.
If your RBAC model says “developers get admin in their namespace”, you’ve still got to trust that:
They understand what admin actually means
They won’t accidentally expose something
They won’t copy-paste YAML from the internet at speed
RBAC can restrict where actions happen. It can’t judge whether those actions are sensible.
The gap between design and reality
On paper, RBAC models look tidy.
Least privilege.
Clear separation of duties.
Nicely named roles.
In reality:
Teams change
Services evolve
Ownership gets fuzzy
Nobody updates the RBAC diagram
RBAC doesn’t rot on its own. It rots because humans move on and the system keeps faithfully enforcing decisions made under completely different assumptions.
Making RBAC work with humans, not against them
The goal isn’t to make RBAC perfect. It’s to make it survivable.
A few things that actually help:
Start with narrow roles and expand deliberately, not the other way round
Avoid wildcards unless you can explain them to future you
Review RoleBindings like you review code, regularly and with context
Treat service accounts as high-risk identities, not background noise
Make the secure path the easy path, especially for developers
Kubernetes gives you the tools. RBAC gives you the guardrails. What happens next depends entirely on how people behave when nobody’s watching.