Kubernetes RBAC misconfiguration audit

Four queries: cluster-admin bindings to non-system subjects, Roles and ClusterRoles with wildcard permissions, bindings granting access to all authenticated principals, and service accounts with automounted tokens that have no API access requirement.

Cluster-admin bindings to non-system subjects

Hypothesis: a service account, user, or group has been bound to cluster-admin without a legitimate operational requirement.

kubectl get clusterrolebindings -o json | \
  jq -r '.items[] |
    select(.roleRef.name == "cluster-admin") |
    .metadata.name as $binding |
    .subjects[]? |
    select(
      (.namespace != "kube-system") and
      (.name | startswith("system:") | not)
    ) |
    [$binding, .kind, .name, (.namespace // "cluster-scoped")] |
    @tsv' | \
  column -t

Any subject appearing here warrants documentation of why cluster-admin is needed. Service accounts bound to cluster-admin outside kube-system, and any user account binding, are high priority.

Wildcard permissions in Roles and ClusterRoles

Hypothesis: a Role or ClusterRole grants unrestricted access via wildcard verbs or resources, beyond what any specific workload requires.

# ClusterRoles with wildcard verbs or resources (excluding built-in system roles)
kubectl get clusterroles -o json | \
  jq -r '.items[] |
    select(.metadata.name | startswith("system:") | not) |
    .metadata.name as $role |
    .rules[]? |
    select((.verbs[]? == "*") or (.resources[]? == "*")) |
    [$role, (.verbs | join(",")), (.resources | join(","))] |
    @tsv' | \
  column -t

# namespace-scoped Roles with wildcard permissions
kubectl get roles -A -o json | \
  jq -r '.items[] |
    .metadata.namespace as $ns |
    .metadata.name as $role |
    .rules[]? |
    select((.verbs[]? == "*") or (.resources[]? == "*")) |
    [$ns, $role, (.verbs | join(",")), (.resources | join(","))] |
    @tsv' | \
  column -t

Bindings to system:authenticated or system:unauthenticated

Hypothesis: permissions have been granted cluster-wide to all authenticated or unauthenticated principals, rather than to specific service accounts.

kubectl get clusterrolebindings,rolebindings -A -o json | \
  jq -r '.items[] |
    .metadata.name as $binding |
    (.metadata.namespace // "cluster") as $ns |
    .subjects[]? |
    select(
      .name == "system:authenticated" or
      .name == "system:unauthenticated"
    ) |
    [$ns, $binding, .name] |
    @tsv' | \
  column -t

Service accounts with automounted tokens

Hypothesis: service accounts have not opted out of token automounting, creating mounted credentials in every pod using the account, including pods that make no API calls.

kubectl get serviceaccounts -A -o json | \
  jq -r '.items[] |
    select(
      .automountServiceAccountToken != false and
      .metadata.namespace != "kube-system" and
      (.metadata.name | startswith("system:") | not)
    ) |
    [.metadata.namespace, .metadata.name] |
    @tsv' | \
  column -t

The output includes service accounts that have not explicitly opted out. Many are expected: applications that legitimately call the Kubernetes API. The review question is whether workloads that make no API calls have tokens mounted unnecessarily. Setting automountServiceAccountToken: false on the ServiceAccount object, or on individual pod specs, removes the token from pods that do not use it.

Roles permitting secret access

Hypothesis: more service accounts than expected have been granted permission to read secrets, widening the impact of a pod compromise.

# identify which roles and clusterroles grant secret read access
kubectl get clusterroles,roles -A -o json | \
  jq -r '.items[] |
    .metadata.name as $name |
    (.metadata.namespace // "cluster") as $ns |
    .rules[]? |
    select(
      (any(.resources[]?; . == "secrets" or . == "*")) and
      (any(.verbs[]?; . == "get" or . == "list" or . == "*"))
    ) |
    [$ns, $name] |
    @tsv' | \
  sort -u | column -t

Cross-reference this output with the binding queries above to identify which service accounts hold secret read access in practice, rather than which role definitions include it.