Skip to content

Build1 publisher2 min readPublished

A four-question RBAC pass runs against the Kubernetes API you already have

A dev.to walkthrough pins the first pass of a least-privilege review on four questions the API server already answers, and it puts create pods above get secrets in the escalation order. Aggregated roles decide how far that pass gets.

The Engineer · Build desk

Illustration accompanying A four-question RBAC pass runs against the Kubernetes API you already have

What happened

  • Kubernetes exposes every RBAC object through its standard API, and the dev.to post says the cluster will tell you exactly who can do what without any additional tooling.
  • The suggested first pass asks four questions: who is bound to cluster-admin, who can read Secrets cluster-wide, who can create or modify workload objects, and which bindings reference system:authenticated or system:unauthenticated.
  • Creating a Pod is effectively the ability to obtain any service account token in that namespace, because the subject can mount the token, run code and use whatever permissions that account holds.
  • The default view, edit and admin ClusterRoles are built by aggregation label, so what edit actually grants depends on which other ClusterRoles in the cluster carry the matching label.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint An audit that reads only the role named in a binding understates the grant, so the no-extra-tooling path still costs the work of following aggregation labels and recording the union.
  • decision Teams that gate get secrets in review while waving through create deployments have the risk ordering backwards, per the post, and that changes which findings get triaged first.
  • exposure A binding to system:authenticated hands its grant to every authenticated identity in the cluster, so a single leaked token inherits it.
  • cost Deleting a broad binding a workload depends on causes an outage, and the re-grant that follows is usually broader than the original.

According to the dev.to write-up, most clusters still have subjects that can read every secret in every namespace, and most of those grants were never deliberately made [13]. The post does not cite a measurement for that. Its account of how the grants arrive is specific: a debugging session produces a temporary ClusterRoleBinding that nobody removes, a default service account gets a role because a workload failed without it, and a Helm chart ships a role broader than the application needs and is upgraded rather than reviewed [14]. In my view nothing in a delivery schedule creates pressure to narrow a role that is already working.

Two of the four questions are name lookups and two are not [1]. A binding to cluster-admin can be found by matching a string, and it grants every verb on every resource in every namespace [3]. The same goes for bindings that reference system:authenticated or system:unauthenticated: those are subject names in the binding object [4]. Cluster-wide secret read and workload creation are questions about verbs on resources, so a subject can hold them through a contributing role one step behind the binding [1].

Workload creation is wider than the pods resource. Creating a Deployment, a DaemonSet, a StatefulSet or a CronJob all result in Pods, and so does creating a Job [7].

A RoleBinding to a service account is a grant to every Pod that mounts it, so a broad role on an account many workloads share makes the blast radius of any single compromise the union of that role's permissions [11]. Workloads that do not specify a service account use default, which means a grant to default in a namespace with a non-trivial role lands on all of them [12].

Automounting is the control next to that. Since Kubernetes 1.24 service account token volumes are projected and time-limited, and automountServiceAccountToken can be set to false on the service account or on the Pod; a workload that does not call the API server does not need a token at all [15].

Flag any rule with resources: ["*"] or verbs: ["*"], whichever subject holds it [16]. A RoleBinding is namespace-scoped and a ClusterRoleBinding is not, and a cluster-scoped grant made for a namespace-scoped need is usually a mistake [17]. The inventory should separate human identities from service accounts, because the remediation paths differ [18]. If nobody recorded an owner and a justification for a grant, remove it [19].

What to watch

  • A measured survey of how many clusters actually have cluster-wide secret readers would test the post's claim that most do.
  • Any new default ClusterRole shipping with an existing aggregation label changes what edit grants without any binding changing.
  • A future Kubernetes release that changes default automount behaviour would alter how many workloads hold a token at all.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories