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.

Next
Next

Supply Chain Attacks: Why Developers Overtrust Dependencies