A kubernetes rbac audit is one of those jobs nobody enjoys and everybody needs. The cluster usually works right up until the day an overbroad role, a stale service account, or a forgotten cluster-admin binding turns a routine change into a security incident.

This post is for teams that already run Kubernetes and want to treat access the way they treat code: reviewed, scoped, and measurable. If you are a CTO, VP of Engineering, or technical founder, the goal is simple. Find the risky grants, cut the unnecessary ones, and keep the blast radius small enough that one mistake does not become a platform event.

Table of contents:

Kubernetes RBAC audit basics

RBAC in Kubernetes is not complicated. That is the trap. The primitives are small: Role, ClusterRole, RoleBinding, ClusterRoleBinding, plus service accounts and verbs like get, list, watch, create, update, patch, delete. The problem is not the model. The problem is accumulation. Every hotfix, operator install, and “temporary” admin grant becomes part of the permanent surface area.

A proper kubernetes rbac audit starts with one question: who can do what, where, and under which identity? Most teams answer this only for humans. That is too narrow. The risky permissions are often attached to CI jobs, controllers, external integrations, and service accounts that nobody has reviewed since the last incident. A cluster-admin binding on a human account is obvious. A service account that can patch deployments across namespaces is not.

There are three things to map first. One, human access: SSO groups, kubeconfig users, and break-glass accounts. Two, workload access: service accounts used by apps, jobs, operators, and GitOps agents. Three, scope: namespace-level permissions versus cluster-wide permissions. If you skip the last one, the audit is theater. Namespace scope is where least privilege lives. Cluster scope is where least privilege dies.

A useful mental model is the blast-radius ladder:

  1. Read-only access to one namespace.
  2. Write access to one namespace.
  3. Read-only access across namespaces.
  4. Write access across namespaces.
  5. Cluster-wide mutation.

Anything above step two deserves a reason, not a habit. If your team cannot explain why a role needs cluster-wide list or watch on secrets, it probably does not. For a deeper infrastructure baseline, our how we engage page explains our Sprint, Build, or Fractional engagements, but the principle is the same: scope first, then ship.

If you want background on the people doing the work, see Kevin’s 28 years of senior engineering. That history matters because RBAC mistakes are usually not syntax problems. They are judgment problems.

Finding overbroad Kubernetes RBAC permissions

The fastest way to start a kubernetes rbac audit is to dump the existing bindings and look for the obvious sins. Run kubectl get clusterrolebindings, kubectl get rolebindings -A, and inspect who is bound to admin, edit, view, and custom ClusterRoles. You are looking for service accounts bound to broad roles, humans bound to cluster-admin outside break-glass, and any role that grants access to secrets without a narrow reason.

Here is a simple pattern I use in audits. Export the policy objects, then sort by risk rather than by namespace. Risk is usually a combination of scope and verbs. A role that can get pods in one namespace is fine. A role that can update deployments and get secrets across all namespaces is not. The audit should rank permissions by the damage they can do if stolen or misused.

kubectl get clusterrole,clusterrolebinding,role,rolebinding -A -o yaml \
  | grep -E "kind:|name:|verbs:|resources:|subjects:|namespace:"

That grep is crude, but it surfaces the shape of the policy fast. In a real audit, I usually follow it with a spreadsheet or a script that converts YAML into a matrix: subject, namespace, resource, verb, scope, and justification. Once you have that matrix, patterns appear immediately. The same service account is bound to multiple roles. A read-only role includes secrets. A CI user has patch on deployments when it only needs apply through GitOps.

One mistake I see often is granting list and watch as if they are harmless. They are not harmless when the resource is sensitive. Watch on secrets, configmaps with credentials, or custom resources that encode tenant data is a quiet data-exposure path. Another is assuming namespaces create safety by themselves. A namespace is only a boundary if the role bindings respect it. If the same service account is bound cluster-wide, the namespace is just decoration.

When teams want a practical tool, I like rbac-lookup, kubectl-who-can, and kubeaudit as starting points. They do not replace judgment, but they help answer the question, “Who can do this?” That is the right question for an audit. Not “What objects exist?” but “What is possible if credentials are stolen, a CI token leaks, or a controller is compromised?”

If you want a related reliability angle, our post on Circuit Breaker Implementation for Production Reliability covers the same discipline from the runtime side: contain failure, then recover cleanly.

Service accounts, namespaces, and workload identity

Most RBAC messes come from service accounts that were meant to be temporary and became permanent. A service account is not just a Kubernetes object. It is an identity. Treat it like one. Give it a name that describes the workload, bind it in the narrowest namespace possible, and rotate the credential path if the account is external-facing or used by automation.

In a clean setup, each workload gets its own service account. The deployment controller uses one. The job runner uses another. The migration job uses another. That seems tedious until you need to answer a breach question quickly. Then the separation pays for itself. Shared service accounts save time on day one and create forensic ambiguity on day ninety.

Namespace design matters too. If your namespaces mix product code, jobs, and operators, the RBAC story gets muddy. I prefer one of two models. Either a namespace per application boundary, with tight role bindings, or a platform namespace for shared controllers and a separate app namespace for business workloads. What I avoid is the “everything in default” pattern. It guarantees drift.

On modern cloud setups, workload identity is better than long-lived secret-based credentials. On AWS, that often means IRSA. On GCP, GKE Workload Identity. On Azure, Workload Identity or managed identities bridged into Kubernetes. The point is the same: stop baking static tokens into pods. If a pod identity is compromised, you want the credential to be narrow and ephemeral, not a cluster-wide skeleton key.

One practical rule: if a workload needs to talk to the Kubernetes API, ask whether it really needs the API or just a controller boundary. Many jobs can move to an event, a queue, or a GitOps reconciliation step instead of direct API writes. That reduces the number of places where RBAC has to be correct. Fewer API writers means fewer places to audit.

For teams building modern internal platforms, this is where Kubernetes RBAC: Managing Access Control Effectively pairs well with the broader question of identity. If your auth boundaries are fuzzy, you end up compensating with bigger roles. That is the wrong direction.

And if the service account story is tangled with auth across your stack, our piece on Central OAuth Broker: How We Killed Login Friction shows how identity decisions ripple beyond the cluster.

A practical Kubernetes RBAC audit process

A good kubernetes rbac audit follows a sequence. First, inventory all subjects. Second, map their bindings. Third, rank the permissions. Fourth, remove the obviously wrong ones. Fifth, test the breakage. Most teams do steps one and two. The audit only becomes real when you test what happens after revocation.

Start with a baseline export. Capture all RoleBindings and ClusterRoleBindings in version control. Then annotate each with an owner and a reason. If a binding has no owner, it is already suspect. If it has an owner but no reason, it is still suspect. This is not bureaucracy. It is how you keep access from becoming archaeological.

Then run a permission review against real workloads. In one engagement, a team had nine service accounts with access to update deployments, but only two actually needed it. The rest were a legacy artifact from an old deployment path. Removing those bindings did not break production. It removed a hidden escalation path. That is the kind of win an audit should produce.

Here is a compact review checklist I use:

  • Are any humans bound to cluster-admin outside break-glass?
  • Do any service accounts have access to secrets they do not strictly need?
  • Are any roles granting write access across namespaces when one namespace would do?
  • Do any CI or GitOps identities have more verbs than their workflow requires?
  • Can you explain every wildcard resource or wildcard verb?

Wildcards deserve special attention. resources: ["*"] or verbs: ["*"] should be rare enough that you can name the exceptions from memory. If you cannot, the policy is too loose. The same goes for aggregated ClusterRoles. They can be useful, but they also make the final permission set harder to reason about. Audits should favor explicitness over cleverness.

Test revocations in a non-production cluster that mirrors your bindings. Do not assume because a role looks unused that it is unused. Some controllers only exercise a path during failure or during a monthly job. Break it in staging first. Then watch the logs, the events, and the workload behavior. A role that seems unused may be the only thing keeping an overnight job alive.

If your team is also tightening deploy safety, our post on Feature Flag Rollouts: Engineering Safe Deploys at Scale pairs well with RBAC. Both are about making change boring.

Policies, tooling, and how to keep it clean

Once the audit is done, the hard part begins: keeping it that way. Manual reviews decay fast. You need policy at admission time, visibility at review time, and a workflow that makes the secure path the easy path. In Kubernetes, that usually means a mix of Kyverno or OPA Gatekeeper, periodic reviews, and GitOps-managed manifests.

A practical policy set is small. Deny cluster-admin except for a named break-glass group. Block wildcard verbs in application namespaces. Require service accounts to be explicitly named. Prevent workloads from using the default service account. For sensitive namespaces, deny secret reads unless the role is approved by the platform owner. These rules catch the common drift without turning the cluster into a minefield of exceptions.

Tooling helps, but only if it fits the operating model. kubectl-who-can is good for quick answers. kubeaudit catches broad misconfigurations. Kyverno is useful when you want policy as code without writing Rego for every rule. If your team already runs Terraform or GitOps, keep RBAC manifests in the same review path as the rest of the platform code. Access should be versioned, reviewed, and attributable.

One thing I recommend: add an RBAC review to your release checklist for platform changes. Not every application deploy. Platform changes. If a new controller, operator, or CI workflow lands, ask what identity it uses and what it can touch. That is where accidental privilege usually enters the system. The change looks small. The blast radius is not.

For teams running broader infrastructure programs, our article on Using Terraform for Efficient Infrastructure Management is relevant because RBAC should be treated as infrastructure, not an afterthought. The same discipline applies to Effective Kubernetes Secrets Management: minimize exposure, make drift visible, and keep ownership explicit.

If you want a place to see how we think about this kind of work, browse work we ship for ourselves and our engineering blog. The pattern is consistent. We prefer controls that reduce future work instead of creating new rituals.

When a cluster has too many broad bindings, the cost shows up as audit time, incident response time, and the quiet fear that nobody really knows who can touch what. That is a business risk, not just a platform smell. If you need help with a focused access review, you can apply for an engagement; the application takes ten minutes. For a single bounded outcome, a Sprint is often enough to ship a clean RBAC audit and a remediation plan.