Skip to content

Six posture exceptions in controller-rbac.yaml are structurally inert, and the migrated four have not gone to zero #2823

Description

@devantler

🤖 Generated by the Agentic Engineer

Problem

k8s/bases/infrastructure/cluster-security-exceptions/controller-rbac.yaml suppresses six controls through a match.namespaceSelector. That file already documents why such a selector cannot suppress an RBAC-anchored finding, and says to migrate the six "if they surface failing objects".

They do — all six. Measured 2026-07-27 against admin@prod:

Control Name Failing objects Anchored on an RBAC object Cluster-scoped (empty namespace)
C-0053 Access container service account 155 100% 103
C-0037 CoreDNS poisoning 41 100% 30
C-0188 CIS-5.1.4 minimize access to create pods 20 100% 13
C-0031 Delete Kubernetes events 18 100% 14
C-0063 Portforwarding privileges 9 100% 5
C-0035 Access restriction to infrastructure — admin access 6 100% 5

249 (control, object) pairs over 156 unique objects. Zero are ordinary namespaced workloads; every one carries kubescape.io/rbac-resource: "true". So the namespaceSelector is not merely imprecise on these — it can never match any of them, and all six exceptions are inert while appearing configured.

(Object names are deliberately not listed. An enumeration of which bindings can reach service-account tokens or create pods is a weakness map; the aggregate counts and the anchor analysis are the sanitized minimum needed to review a fix.)

The trap in the data

The summaries are labelled kubescape.io/workload-kind: ServiceAccount with a populated workload-namespace, which makes a namespaceSelector look viable. But matching keys on the kubescape.io/wlid annotation, which reads wlid://cluster-prod/namespace-/clusterrolebinding-<name>binding kind, empty namespace. Any migration must name ClusterRoleBinding/RoleBinding kinds, not ServiceAccount.

Also note for anyone re-measuring: the aggregated storage API returns spec-stripped objects on LIST — controls reads null and severities read all-zero across every item. Those numbers are only real when each object is fetched by name. A LIST-based sweep here reports a clean cluster.

What is NOT yet established — read before migrating

The four controls already migrated to explicit kind+name match.resources CRs have not gone to zero:

Migrated control Still failing
C-0015 (list secrets) 70
C-0007 (delete-capable roles) 42
C-0002 (exec into container) 9
C-0187 (wildcard RBAC) 6

They are anchored the same way. This is not evidence the migration approach is broken — the residue may simply fall outside those CRs' named scope, which would be correct behaviour. But it does mean "migrate to kind+name" is currently an unproven remediation, and migrating six more controls on that assumption risks writing six more exceptions that also do not take effect.

Direction — measure before migrating

The first shippable step is verification, not a migration:

  1. For one already-migrated control (C-0187 is smallest at 6), determine whether each still-failing object is inside or outside its CR's named scope. In-scope residue means the mechanism does not work and the whole approach needs rethinking; out-of-scope residue means it works and the CRs are simply incomplete.
  2. Only then migrate the six, kinds named correctly per the wlid finding above.
  3. Re-measure and record before/after counts per control.

Acceptance criteria

  • The in-scope/out-of-scope question above is answered for at least one migrated control, with evidence
  • Each of the six either has a working kind+name exception or a recorded reason it should stay flagged
  • Before/after failing counts recorded per control, measured by per-object GET rather than LIST
  • controller-rbac.yaml no longer carries exception entries that cannot match anything

Rough size: M. Step 1 is small and decides the shape of the rest.

Evidence freshness

Scanner proven alive rather than assumed: kubescape v4.0.10, scheduler CronJob last job Complete, newest summary objects written 2026-07-27T10:08–10:09Z, aggregate scan summary non-zero (212 high / 840 medium / 89 low), and 2206/2206 objects returned populated control maps on direct GET.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status
    📥 Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions