Back

K03: Overly Permissive RBAC Configurations - Overview

What is Overly Permissive RBAC?

Role-Based Access Control (RBAC) is the primary authorization system in Kubernetes. Every request to the API server—whether it comes from a human with a kubeconfig, a controller, or a Pod using its mounted ServiceAccount token—is authenticated, then checked against a set of Roles and ClusterRoles bound to that identity. RBAC decides whether the request is allowed. K03 Overly Permissive RBAC is the failure mode where those roles grant far more than the identity actually needs.

The danger is not abstract. RBAC is additive and purely allow-based: there are no deny rules, so every permission you grant is a permission that stays granted until someone explicitly removes the binding. A single over-broad rule—a wildcard verb, a cluster-admin binding on a ServiceAccount, the ability to create Pods in a namespace that also holds privileged tokens—turns a minor foothold (one compromised container) into full control of the cluster. Because the flaw lives in a YAML manifest rather than in application code, it is invisible to code review, survives every redeploy, and is copied wherever the manifest is reused.

Core Concept

Least-privilege RBAC:
  Subject      -> one ServiceAccount per workload, automount disabled if unused
  Scope        -> namespaced Role, not a cluster-wide ClusterRole
  verbs        -> only what the workload calls (e.g. ["get","list","watch"])
  resources    -> the specific kinds it touches (e.g. ["configmaps"])
  resourceNames-> named objects where practical (e.g. ["app-config"])
  apiGroups    -> the exact group ("" for core, "apps", ...)
  bindings     -> RoleBinding to that one SA, reviewed and audited

Overly permissive RBAC:
  Subject      -> default ServiceAccount, token auto-mounted everywhere
  Scope        -> ClusterRole granting access in every namespace
  verbs        -> ["*"]  (create, delete, escalate, bind, impersonate...)
  resources    -> ["*"]  (pods, secrets, nodes, rolebindings, ...)
  resourceNames-> none    (applies to every object of the kind)
  apiGroups    -> ["*"]   (every API group, current and future)
  bindings     -> cluster-admin bound to a SA or a wide group

Why It's Critical for Kubernetes

Kubernetes concentrates several conditions that make an over-broad role especially dangerous:

Why Does This Matter?

Business Impact

Technical Impact

Technical Context

How RBAC Objects Fit Together

ObjectWhat it isScope
RoleA set of permission rules (verbs on resources)One namespace
ClusterRoleA set of permission rules, reusable cluster-wideCluster (or any namespace via a RoleBinding)
RoleBindingGrants a Role or ClusterRole to subjects in one namespaceOne namespace
ClusterRoleBindingGrants a ClusterRole to subjects across all namespacesCluster-wide
SubjectA User, Group, or ServiceAccount the binding applies to—

A rule is the triple apiGroups × resources × verbs (optionally narrowed by resourceNames). Permissions are the union of every rule in every bound role. There is no way to subtract a permission with another rule—the only way to reduce access is to change or delete the grant.

The Dangerous Grants

1. Wildcards

rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]

This is the single most dangerous rule in Kubernetes. It grants every verb on every resource in every API group—including RBAC objects, Secrets, and Nodes—and automatically covers any Custom Resource Definition installed later. Bound cluster-wide, it is equivalent to cluster-admin.

2. cluster-admin bound to a ServiceAccount or wide group

roleRef:
  kind: ClusterRole
  name: cluster-admin        # the built-in god-mode role
subjects:
- kind: ServiceAccount       # a workload identity, not a human break-glass account
  name: default
  namespace: apps
# or:
- kind: Group
  name: system:authenticated # EVERY authenticated identity in the cluster

Binding cluster-admin to a workload's ServiceAccount means compromising that one Pod is compromising the cluster. Binding any role to system:authenticated or system:unauthenticated grants it to essentially everyone.

3. The escalation verbs

Verb / resourceWhy it is dangerous
escalate on roles/clusterrolesBypasses the escalation-prevention check—lets a subject write a role granting permissions it does not currently hold.
bind on roles/clusterrolesLets a subject create a RoleBinding to any role (including cluster-admin), granting itself that role.
impersonate on users/groups/serviceaccountsAct as any other identity, inheriting all of its permissions—including system:masters.
create on pods (or Deployments, Jobs, DaemonSets)Schedule a Pod that mounts a more privileged ServiceAccount token or the host filesystem.
create on pods/exec, pods/attachRun commands inside existing running containers, including privileged ones.
get on nodes/proxyReach the kubelet API to read other Pods' secrets and exec into them.
create on serviceaccounts/tokenTokenRequest API—mint fresh tokens for any ServiceAccount in the namespace.
get/list on secretsRead every credential, token, and key stored in the namespace (or cluster).
get/update on certificatesigningrequests/approvalApprove CSRs to issue client certs for arbitrary identities, including group system:masters.

4. system:masters

# A client certificate whose Organization (O) field is system:masters
# is hard-wired to cluster-admin and BYPASSES RBAC entirely.
Subject: CN=attacker, O=system:masters

system:masters is a built-in super-group wired directly into the API server's authorizer. It is not governed by RBAC and cannot be revoked with an RBAC change—so any permission that can issue certificates or impersonate into that group is a total-compromise permission.

The Default ServiceAccount Trap

Every namespace ships with a default ServiceAccount, and (unless disabled) every Pod that does not name a ServiceAccount is assigned it, with its token auto-mounted. On its own the default SA has almost no permissions—but teams routinely bind roles to it "to make things work," and because every unspecified Pod shares that identity, one over-broad binding on default silently grants those permissions to many unrelated workloads.

# Anti-pattern: a Pod that does not need the API still carries a live token
apiVersion: v1
kind: Pod
spec:
  # no serviceAccountName -> uses "default"
  # no automountServiceAccountToken: false -> token is mounted and stealable
  containers:
  - name: web
    image: nginx

Real-World Impact

Case Study 1: Compromised Pod to Cluster-Admin via a Bound Role (incident class)

Misconfiguration:

Impact:

Root Cause: Cluster-wide Secret read access on a workload identity, combined with a privileged token stored as a Secret. Neither was necessary at the scope granted.

Case Study 2: escalate/bind Self-Promotion (incident class)

Misconfiguration:

Impact:

Root Cause: Granting the meta-permissions that govern RBAC itself, rather than a narrow, named set of bindings the operator was allowed to manage.

Case Study 3: Over-Permissioned default ServiceAccount (incident class)

Misconfiguration:

Impact:

Root Cause: Binding permissions to the shared default identity instead of a dedicated, scoped ServiceAccount, so the grant leaked to unrelated workloads.

Prevalence and Detection

Overly Permissive RBAC is one of the most common findings in Kubernetes security assessments, precisely because RBAC is additive, invisible to application testing, and easy to over-grant when chasing a "forbidden" error. Rather than cite precise counts (which vary by source), the durable picture is:

Note: exact percentages differ between reports and years. Treat any single figure as illustrative; the durable takeaway is that over-broad RBAC is common, cheap to find with kubectl auth can-i and RBAC auditors, and devastating when chained from an initial foothold.

Common Misunderstandings

Myth 1: "RBAC has deny rules, so a broad grant can be fenced off"

Reality: RBAC is allow-only and additive. There are no deny rules. The union of all bound roles is what applies; the only way to remove access is to change or delete the grant itself.

Myth 2: "It's just read access, so it's low risk"

Reality: get/list on Secrets is read access that hands over every credential in scope. Read on nodes/proxy reaches the kubelet. "Read" is not synonymous with "safe."

Myth 3: "The token isn't in the Pod unless we put it there"

Reality: ServiceAccount tokens are auto-mounted by default. Unless you set automountServiceAccountToken: false, any code execution in the container can read the token and use the identity's RBAC.

Myth 4: "cluster-admin on a ServiceAccount is fine for an internal operator"

Reality: A ServiceAccount is a non-human identity with an always-available token. Binding cluster-admin to it makes that single workload a cluster-wide skeleton key that never has to log in.

Myth 5: "Wildcards are convenient and we'll tighten them later"

Reality: Wildcards also grant access to resources that do not exist yet—every future CRD is covered automatically. "Later" rarely comes, and the blast radius keeps growing silently.

Myth 6: "Namespaced Roles can't cause cluster-wide damage"

Reality: A namespaced Role that allows create on Pods can schedule a Pod mounting a more privileged SA, mount the host filesystem, or reach node metadata—escaping the namespace boundary entirely.

How Overly Permissive RBAC Differs from Related Issues

AspectOverly Permissive RBAC (K03)Insecure Workload Config (K01)Missing Network Segmentation (K05)
Root causeOver-broad API authorizationPrivileged/host-exposing Pod specsFlat, unrestricted Pod networking
Where it livesRoles, ClusterRoles, bindingsPod/container securityContextNetworkPolicy (or its absence)
Typical fixLeast-privilege rules, scoped bindingsDrop privileges, restrict host accessDefault-deny NetworkPolicies
Detectionkubectl auth can-i, RBAC auditorsAdmission policy, manifest scanPolicy audit, traffic analysis

Key Takeaways

  1. RBAC is additive and allow-only—every grant persists until removed; there is no deny to fall back on.
  2. Wildcards and cluster-admin bindings are the crown-jewel mistakes—they turn one foothold into total control.
  3. A handful of verbs are escalation primitives—escalate, bind, impersonate, create on Pods/exec, and Secret reads deserve special scrutiny.
  4. ServiceAccount tokens are auto-mounted—a compromised Pod is a compromised identity unless automount is disabled.
  5. Least privilege must be the default—scoped Roles, named resources, dedicated ServiceAccounts, and audited bindings.

How to Identify if You're Vulnerable

Ask these questions about your cluster:

If you answered "yes" or "not sure" to several of these, you likely have exploitable over-permissioning today.

Next Steps