You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
CKV2_K8S_5 ("No ServiceAccount/Node should be able to read all secrets") is intended to fail when a ServiceAccount/Node is bound (via RoleBinding/ClusterRoleBinding) to a Role/ClusterRole that grants get/list/watch (or *) on secrets (or *) with no resourceNames restriction.
The check's "safe" condition currently evaluates rules.resourceNamesexists as an attribute over the entireRole/ClusterRole object — i.e. "does any rule block in this object have resourceNames?" — rather than requiring that the same rule block which grants the risky secrets access also has resourceNames.
As a result, if a ClusterRole has:
Rule A: broad, unrestricted access to secrets (get, list, watch, etc., no resourceNames)
Rule B: a separate, legitimately scoped rule for secrets with resourceNames: [...] (e.g. reading a specific pull secret)
...the presence of Rule B's resourceNames appears to satisfy the check for the whole object, and CKV2_K8S_5passes even though Rule A still grants unrestricted read/write access to every Secret in scope. This is effectively a false negative for a pattern I'd expect this check to be designed to catch — a controller with both a scoped, least-privilege grant and a separate broad grant in the same object.
This appears related to (but distinct from) #7110 and #6765, which both point at the same underlying limitation in how CKV2_K8S_1-5 correlate attributes across a rules list rather than per rule entry.
Check: CKV2_K8S_5: "No ServiceAccount/Node should be able to read all secrets"
PASSED for resource: ClusterRoleBinding.default.manager-rolebinding
File: /test.yaml:...
Expected Result
Should FAIL, since the first rule block grants unrestricted secrets access (create/delete/get/list/patch/update/watch, no resourceNames) regardless of the second, unrelated, scoped rule.
Additional context
This is a very common real-world pattern for Kubernetes operators: they often need resourceNames-scoped access to one or two known Secrets (e.g. a pull secret) and broad create/manage access to Secrets they generate dynamically with names unknown ahead of time. Because that broad access genuinely can't use resourceNames, this combination is likely to appear in many legitimate operator ClusterRoles — making this a meaningful blind spot rather than a rare edge case.
I understand fixing this properly likely means converting CKV2_K8S_5 from a declarative YAML graph check into a Python-based graph check that iterates rules entries individually (similar to how WildcardRoles.py / CKV_K8S_49 iterates conf.get("rules")), while still preserving the RoleBinding/ClusterRoleBinding → Role/ClusterRole graph traversal. Happy to attempt a PR for this, but wanted to check preference first:
Description
CKV2_K8S_5("No ServiceAccount/Node should be able to read all secrets") is intended to fail when aServiceAccount/Nodeis bound (viaRoleBinding/ClusterRoleBinding) to aRole/ClusterRolethat grantsget/list/watch(or*) onsecrets(or*) with noresourceNamesrestriction.The check's "safe" condition currently evaluates
rules.resourceNamesexistsas an attribute over the entireRole/ClusterRoleobject — i.e. "does any rule block in this object haveresourceNames?" — rather than requiring that the same rule block which grants the riskysecretsaccess also hasresourceNames.As a result, if a
ClusterRolehas:secrets(get,list,watch, etc., noresourceNames)secretswithresourceNames: [...](e.g. reading a specific pull secret)...the presence of Rule B's
resourceNamesappears to satisfy the check for the whole object, andCKV2_K8S_5passes even though Rule A still grants unrestricted read/write access to every Secret in scope. This is effectively a false negative for a pattern I'd expect this check to be designed to catch — a controller with both a scoped, least-privilege grant and a separate broad grant in the same object.This appears related to (but distinct from) #7110 and #6765, which both point at the same underlying limitation in how
CKV2_K8S_1-5correlate attributes across aruleslist rather than per rule entry.Reproduction
Actual Result
Expected Result
Should FAIL, since the first rule block grants unrestricted
secretsaccess (create/delete/get/list/patch/update/watch, noresourceNames) regardless of the second, unrelated, scoped rule.Additional context
This is a very common real-world pattern for Kubernetes operators: they often need
resourceNames-scoped access to one or two known Secrets (e.g. a pull secret) and broad create/manage access to Secrets they generate dynamically with names unknown ahead of time. Because that broad access genuinely can't useresourceNames, this combination is likely to appear in many legitimate operatorClusterRoles — making this a meaningful blind spot rather than a rare edge case.I understand fixing this properly likely means converting
CKV2_K8S_5from a declarative YAML graph check into a Python-based graph check that iteratesrulesentries individually (similar to howWildcardRoles.py/CKV_K8S_49iteratesconf.get("rules")), while still preserving theRoleBinding/ClusterRoleBinding→Role/ClusterRolegraph traversal. Happy to attempt a PR for this, but wanted to check preference first:CKV2_K8S_5in place with per-rule-entry correlation (my preference, for consistency with how CKV2_K8S_5 fails whenresources: ["secrets"]even ifresourceNamesare specified #7110 was resolved), orCKV2_K8S_1-5family (given the overlap with CKV2_K8S_{1-5} do not checkapiGroupsof ClusterRoleBindings #6765).Checkov Version: 3.2.334 (reproduced against the current
ReadAllSecrets.yamldefinition onmain)