From ae42c3fa42e7a1f793b61a67c6bc02ba896230ad Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Sat, 4 Jul 2026 13:35:31 +0200 Subject: [PATCH 1/4] fix(kubescape): make C-0015 secret-list exceptions take effect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit C-0015 ("List Kubernetes secrets") reported 0/50 passing: its only exception sat under a namespaceSelector, which Kubescape cannot apply to RBAC-based findings (keyed on the Role/ClusterRole/binding, not a namespace), so every secret-reader — including legitimate ones like cert-manager — stayed flagged. Move C-0015 to a dedicated secret-reader-rbac.yaml matching the ~65 legitimate secret-reading controllers/operators/databases by their RBAC object (the proven wildcard-rbac.yaml kind+name pattern), remove the inert entry from controller-rbac.yaml, and mirror the change into the Headlamp exceptions ConfigMap. Genuinely over-privileged/admin identities (unused tenant `edit` SAs, crossview's wildcard read, the cluster-admin/crossplane admin groups) are deliberately left flagged so the control keeps working. Scanner-suppression only — grants and removes no privileges. Validated: ksail workload validate (local + prod, 500 files each); new CSE passes the live Kubescape CRD schema. Co-Authored-By: Claude Opus 4.8 --- .../controller-rbac.yaml | 21 +- .../kustomization.yaml | 1 + .../secret-reader-rbac.yaml | 269 ++++++++++ .../config-map-headlamp-exceptions.yaml | 473 +++++++++++++++++- 4 files changed, 752 insertions(+), 12 deletions(-) create mode 100644 k8s/bases/infrastructure/cluster-security-exceptions/secret-reader-rbac.yaml diff --git a/k8s/bases/infrastructure/cluster-security-exceptions/controller-rbac.yaml b/k8s/bases/infrastructure/cluster-security-exceptions/controller-rbac.yaml index cdd396c50..71b1e2fb9 100644 --- a/k8s/bases/infrastructure/cluster-security-exceptions/controller-rbac.yaml +++ b/k8s/bases/infrastructure/cluster-security-exceptions/controller-rbac.yaml @@ -23,8 +23,6 @@ spec: posture: - controlID: C-0053 action: ignore - - controlID: C-0015 - action: ignore - controlID: C-0007 action: ignore - controlID: C-0037 @@ -37,13 +35,18 @@ spec: action: ignore - controlID: C-0035 action: ignore - # NOTE: C-0187 (wildcard RBAC, CIS-5.1.3) is handled in wildcard-rbac.yaml, - # not here — a namespaceSelector exception does not suppress RBAC findings - # (Kubescape keys them on the Role/ClusterRole/binding object, so a namespace - # match never applies; proven: the namespaced velero-server Role kept failing - # despite `velero` being listed below). Headlamp is fixed at the root (SA - # scoped to read-only cluster-reader); Flux and Velero are exempted by-design - # in wildcard-rbac.yaml via an explicit kind+name resources match. + # NOTE: RBAC controls are NOT suppressed by this namespaceSelector — Kubescape + # keys them on the Role/ClusterRole/binding object, so a namespace match never + # applies (proven: the namespaced velero-server Role kept failing despite + # `velero` being listed below). They are handled by an explicit kind+name + # `match.resources` in a sibling CR instead: + # - C-0187 (wildcard RBAC, CIS-5.1.3) → wildcard-rbac.yaml + # - C-0015 (list Kubernetes secrets) → secret-reader-rbac.yaml + # Headlamp is fixed at the root (SA scoped to read-only cluster-reader); Flux + # and Velero are exempted by-design in wildcard-rbac.yaml. + # The other RBAC controls still listed here (C-0053, C-0007, C-0037, C-0031, + # C-0002, C-0063, C-0035, C-0188) have the same namespaceSelector limitation and + # should migrate to kind+name matching too — tracked separately. - controlID: C-0188 action: ignore match: diff --git a/k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml b/k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml index 13479eced..0afb2fad0 100644 --- a/k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml +++ b/k8s/bases/infrastructure/cluster-security-exceptions/kustomization.yaml @@ -10,6 +10,7 @@ resources: - image-verification.yaml - infrastructure-privileged.yaml - pod-security-mutations.yaml + - secret-reader-rbac.yaml - service-account-tokens.yaml - talos-cis-control-plane-false-positives.yaml - talos-cis-worker-false-positives.yaml diff --git a/k8s/bases/infrastructure/cluster-security-exceptions/secret-reader-rbac.yaml b/k8s/bases/infrastructure/cluster-security-exceptions/secret-reader-rbac.yaml new file mode 100644 index 000000000..e9ce53bd6 --- /dev/null +++ b/k8s/bases/infrastructure/cluster-security-exceptions/secret-reader-rbac.yaml @@ -0,0 +1,269 @@ +--- +# Secret-reader RBAC exception (Kubescape C-0015, "List Kubernetes secrets") for +# the controllers, operators and databases that legitimately read Secrets BY +# DESIGN. +# +# Why this is a separate CR and not a `namespaceSelector` entry in +# controller-rbac.yaml: a namespaceSelector does NOT suppress C-0015. Like +# C-0187 (see wildcard-rbac.yaml), C-0015 is an RBAC control — Kubescape attaches +# the finding to the RBAC object graph (the ServiceAccount subject plus its +# Role/ClusterRole and RoleBinding/ClusterRoleBinding), not to a namespaced +# workload. The kubescape CRD exceptions getter turns a namespaceSelector into a +# bare `{namespace: X}` designator, and the suppressible objects here are almost +# all cluster-scoped (a ClusterRole/ClusterRoleBinding has no namespace), so the +# namespace never matches and the exception is inert. Proven live: origin-ca-issuer +# is in controller-rbac.yaml's selected `cert-manager` namespace yet still fails +# C-0015. Matching the specific RBAC objects by kind+name is the mechanism that +# actually works (opa-utils exceptionprocessor.go re-wraps each related object and +# compares its top-level kind+name) — the same pattern wildcard-rbac.yaml uses. +# +# Match the permission-bearer (the Role/ClusterRole that grants the secrets verb), +# and — for the cluster-admin holders whose secret access comes from the shared +# `cluster-admin` ClusterRole — the specific ClusterRoleBinding (as wildcard-rbac.yaml +# does), so a NEW cluster-admin binding still trips C-0015. +# +# Deliberately NOT exempted (kept flagged so the control keeps doing its job): +# - The unused tenant SAs `wedding-app` and `ascoachingogvaner`, bound to the +# broad built-in `ClusterRole/edit`: their pods run as the `default` SA, so +# these edit-bound SAs are dormant namespace-wide secret grants = genuine +# over-privilege to remove, not to silence. +# - `crossview-sa` (`crossview-role` grants `*/* get,list,watch`, i.e. reads all +# Secret contents for a topology viewer) — tighten upstream in the crossview +# chart, don't exempt. +# - The break-glass admin groups `system:masters` (cluster-admin) and +# `crossplane:masters` (crossplane-admin): surfacing the highest-privilege +# identities is the control working as intended. +# - `longhorn-support-bundle` (an on-demand diagnostic SA bound to cluster-admin) +# — same treatment as in wildcard-rbac.yaml. +# +# Keep this list and the Headlamp mirror +# (controllers/kubescape/config-map-headlamp-exceptions.yaml) in sync by hand. +apiVersion: kubescape.io/v1beta1 +kind: ClusterSecurityException +metadata: + name: secret-reader-rbac +spec: + reason: >- + Controllers, operators and databases that read Kubernetes Secrets by design + (cert-manager, External Secrets, CloudNativePG + Barman backups, Crossplane + and its providers, Kyverno, Flux/tofu, KEDA, Longhorn, Cilium, the Kubescape + operator, the built-in kube-controller-manager controllers, and the tenant + databases). Matched by the specific RBAC object (Role/ClusterRole, or the + binding for cluster-admin holders) so a new/accidental secret-reader + elsewhere still trips C-0015. Over-privileged or admin identities + (unused tenant `edit` SAs, crossview's wildcard read, the cluster-admin / + crossplane admin groups) are intentionally left flagged. + posture: + - controlID: C-0015 + action: ignore + match: + resources: + # Flux GitOps & tofu-controller + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: crd-controller-flux-system + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: tf-runner-role + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: tofu-cluster-reconciler-role + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: tofu-manager-role + # Cluster-admin holders (Flux reconcilers, Velero) — matched by binding, mirroring wildcard-rbac.yaml + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRoleBinding + name: cluster-reconciler-flux-system + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRoleBinding + name: flux-operator + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRoleBinding + name: velero-server + # cert-manager (TLS/CA secret management) + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cert-manager-cainjector + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cert-manager-controller-certificates + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cert-manager-controller-challenges + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cert-manager-controller-clusterissuers + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cert-manager-controller-issuers + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cert-manager-controller-orders + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: origin-ca-issuer-controller + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: simply-dns-webhook:secret-access + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: cert-manager-webhook:dynamic-serving + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: trust-manager + # CloudNativePG operator + tenant databases & Barman backups + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cloudnative-pg + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: plugin-barman-cloud + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: backstage-db + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: coroot-db + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: coroot-db-barman-cloud + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: umami-db + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: umami-db-barman-cloud + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: wedding-db + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: wedding-db-barman-cloud + # External Secrets Operator + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: external-secrets-cert-controller + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: external-secrets-controller + # Crossplane + upjet providers (reconcile provider-credential Secrets) + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: crossplane + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: crossplane:provider:provider-aws-iam-ae66959c4138:system + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: crossplane:provider:provider-family-aws-1bcdce25f1e9:system + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: crossplane:provider:provider-upjet-github-04d509bb9f6f:system + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: crossplane:provider:provider-upjet-unifi-553bd95aeec2:system + # Kyverno policy engine + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: kyverno:admission-controller + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: kyverno:background-controller + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: kyverno:cleanup-controller + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: kyverno:reports-controller + # Observability & monitoring + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: coroot-cluster-agent + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: coroot-operator + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kube-prometheus-stack-grafana-clusterrole + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kube-prometheus-stack-kube-state-metrics + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kube-prometheus-stack-operator + # Storage (Longhorn, Hetzner CSI) + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: hcloud-csi-controller + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: longhorn-role + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: longhorn + # Cilium CNI & Gateway (TLS secrets) + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cilium-operator + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: cilium-gateway-secrets + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: cilium-tlsinterception-secrets + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: hubble-generate-certs + # KEDA autoscaler + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: keda-operator + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: keda-operator-certs + # Kubernetes control-plane (kube-controller-manager) built-in controllers + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:controller:generic-garbage-collector + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:controller:namespace-controller + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:controller:resourcequota-controller + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:kube-controller-manager + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: system:controller:bootstrap-signer + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: system:controller:token-cleaner + # Kubescape operator/scanner + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kubescape + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: operator + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: operator + # Other platform controllers (flagger, reloader, ksail-operator, OpenBao) + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: flagger + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: ksail-operator + - apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: reloader-reloader-role + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: vault-config + - apiGroup: rbac.authorization.k8s.io + kind: Role + name: velero-server diff --git a/k8s/bases/infrastructure/controllers/kubescape/config-map-headlamp-exceptions.yaml b/k8s/bases/infrastructure/controllers/kubescape/config-map-headlamp-exceptions.yaml index da70b5a5d..80f9e7029 100644 --- a/k8s/bases/infrastructure/controllers/kubescape/config-map-headlamp-exceptions.yaml +++ b/k8s/bases/infrastructure/controllers/kubescape/config-map-headlamp-exceptions.yaml @@ -66,9 +66,6 @@ data: { "controlID": "^C-0053$" }, - { - "controlID": "^C-0015$" - }, { "controlID": "^C-0007$" }, @@ -434,5 +431,475 @@ data: "controlID": "^C-0187$" } ] + }, + { + "name": "secret-reader-rbac", + "policyType": "postureExceptionPolicy", + "actions": [ + "alertOnly" + ], + "reason": "Controllers, operators and databases that read Secrets by design; matched by RBAC object (Role/ClusterRole, or binding for cluster-admin holders) so a new secret-reader still trips C-0015. Unused tenant edit SAs, crossview wildcard read, and the cluster-admin/crossplane admin groups are intentionally left flagged.", + "resources": [ + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^crd-controller-flux-system$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^tf-runner-role$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^tofu-cluster-reconciler-role$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^tofu-manager-role$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRoleBinding$", + "name": "^cluster-reconciler-flux-system$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRoleBinding$", + "name": "^flux-operator$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRoleBinding$", + "name": "^velero-server$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^cert-manager-cainjector$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^cert-manager-controller-certificates$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^cert-manager-controller-challenges$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^cert-manager-controller-clusterissuers$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^cert-manager-controller-issuers$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^cert-manager-controller-orders$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^origin-ca-issuer-controller$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^simply-dns-webhook:secret-access$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^cert-manager-webhook:dynamic-serving$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^trust-manager$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^cloudnative-pg$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^plugin-barman-cloud$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^backstage-db$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^coroot-db$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^coroot-db-barman-cloud$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^umami-db$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^umami-db-barman-cloud$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^wedding-db$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^wedding-db-barman-cloud$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^external-secrets-cert-controller$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^external-secrets-controller$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^crossplane$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^crossplane:provider:provider-aws-iam-ae66959c4138:system$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^crossplane:provider:provider-family-aws-1bcdce25f1e9:system$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^crossplane:provider:provider-upjet-github-04d509bb9f6f:system$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^crossplane:provider:provider-upjet-unifi-553bd95aeec2:system$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^kyverno:admission-controller$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^kyverno:background-controller$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^kyverno:cleanup-controller$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^kyverno:reports-controller$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^coroot-cluster-agent$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^coroot-operator$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^kube-prometheus-stack-grafana-clusterrole$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^kube-prometheus-stack-kube-state-metrics$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^kube-prometheus-stack-operator$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^hcloud-csi-controller$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^longhorn-role$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^longhorn$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^cilium-operator$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^cilium-gateway-secrets$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^cilium-tlsinterception-secrets$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^hubble-generate-certs$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^keda-operator$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^keda-operator-certs$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^system:controller:generic-garbage-collector$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^system:controller:namespace-controller$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^system:controller:resourcequota-controller$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^system:kube-controller-manager$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^system:controller:bootstrap-signer$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^system:controller:token-cleaner$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^kubescape$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^operator$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^operator$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^flagger$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^ksail-operator$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^ClusterRole$", + "name": "^reloader-reloader-role$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^vault-config$" + } + }, + { + "designatorType": "Attributes", + "attributes": { + "kind": "^Role$", + "name": "^velero-server$" + } + } + ], + "posturePolicies": [ + { + "controlID": "^C-0015$" + } + ] } ] From e602406f609261cfce95d2641e3db2e07a7e9eaa Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Sat, 4 Jul 2026 19:33:06 +0200 Subject: [PATCH 2/4] fix(kubescape): match Crossplane provider revision hashes with a regex --- .../kubescape/config-map-headlamp-exceptions.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/k8s/bases/infrastructure/controllers/kubescape/config-map-headlamp-exceptions.yaml b/k8s/bases/infrastructure/controllers/kubescape/config-map-headlamp-exceptions.yaml index c36f78b7c..8dc26daa7 100644 --- a/k8s/bases/infrastructure/controllers/kubescape/config-map-headlamp-exceptions.yaml +++ b/k8s/bases/infrastructure/controllers/kubescape/config-map-headlamp-exceptions.yaml @@ -732,28 +732,28 @@ data: "designatorType": "Attributes", "attributes": { "kind": "^ClusterRole$", - "name": "^crossplane:provider:provider-aws-iam-ae66959c4138:system$" + "name": "^crossplane:provider:provider-aws-iam-[0-9a-f]+:system$" } }, { "designatorType": "Attributes", "attributes": { "kind": "^ClusterRole$", - "name": "^crossplane:provider:provider-family-aws-1bcdce25f1e9:system$" + "name": "^crossplane:provider:provider-family-aws-[0-9a-f]+:system$" } }, { "designatorType": "Attributes", "attributes": { "kind": "^ClusterRole$", - "name": "^crossplane:provider:provider-upjet-github-04d509bb9f6f:system$" + "name": "^crossplane:provider:provider-upjet-github-[0-9a-f]+:system$" } }, { "designatorType": "Attributes", "attributes": { "kind": "^ClusterRole$", - "name": "^crossplane:provider:provider-upjet-unifi-553bd95aeec2:system$" + "name": "^crossplane:provider:provider-upjet-unifi-[0-9a-f]+:system$" } }, { From bfe0171a57e5aa11a0df69cd060f47287e5a5d9c Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Sat, 4 Jul 2026 19:33:14 +0200 Subject: [PATCH 3/4] fix(kubescape): match Crossplane provider revision hashes with a regex in the CSE --- .../cluster-security-exceptions/secret-reader-rbac.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/k8s/bases/infrastructure/cluster-security-exceptions/secret-reader-rbac.yaml b/k8s/bases/infrastructure/cluster-security-exceptions/secret-reader-rbac.yaml index e9ce53bd6..4a30815d4 100644 --- a/k8s/bases/infrastructure/cluster-security-exceptions/secret-reader-rbac.yaml +++ b/k8s/bases/infrastructure/cluster-security-exceptions/secret-reader-rbac.yaml @@ -153,16 +153,16 @@ spec: name: crossplane - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: crossplane:provider:provider-aws-iam-ae66959c4138:system + name: ^crossplane:provider:provider-aws-iam-[0-9a-f]+:system$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: crossplane:provider:provider-family-aws-1bcdce25f1e9:system + name: ^crossplane:provider:provider-family-aws-[0-9a-f]+:system$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: crossplane:provider:provider-upjet-github-04d509bb9f6f:system + name: ^crossplane:provider:provider-upjet-github-[0-9a-f]+:system$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: crossplane:provider:provider-upjet-unifi-553bd95aeec2:system + name: ^crossplane:provider:provider-upjet-unifi-[0-9a-f]+:system$ # Kyverno policy engine - apiGroup: rbac.authorization.k8s.io kind: Role From 8e9fc59f85af6d0f35f4c03bbe5a1e0255a681f7 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Sat, 4 Jul 2026 23:42:03 +0200 Subject: [PATCH 4/4] fix(kubescape): anchor the literal secret-reader CSE name matchers Kubescape matches ClusterSecurityException resource names as unanchored regexes, so a literal like 'operator' or 'longhorn' could silently suppress C-0015 on future RBAC objects whose names merely contain it. Anchoring every literal (the crossplane hash entries were already regex-shaped) also brings the CSE in line with the Headlamp mirror, which was anchored all along. Co-Authored-By: Claude Fable 5 --- .../secret-reader-rbac.yaml | 122 +++++++++--------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/k8s/bases/infrastructure/cluster-security-exceptions/secret-reader-rbac.yaml b/k8s/bases/infrastructure/cluster-security-exceptions/secret-reader-rbac.yaml index 4a30815d4..5aa454ace 100644 --- a/k8s/bases/infrastructure/cluster-security-exceptions/secret-reader-rbac.yaml +++ b/k8s/bases/infrastructure/cluster-security-exceptions/secret-reader-rbac.yaml @@ -61,96 +61,96 @@ spec: # Flux GitOps & tofu-controller - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: crd-controller-flux-system + name: ^crd-controller-flux-system$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: tf-runner-role + name: ^tf-runner-role$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: tofu-cluster-reconciler-role + name: ^tofu-cluster-reconciler-role$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: tofu-manager-role + name: ^tofu-manager-role$ # Cluster-admin holders (Flux reconcilers, Velero) — matched by binding, mirroring wildcard-rbac.yaml - apiGroup: rbac.authorization.k8s.io kind: ClusterRoleBinding - name: cluster-reconciler-flux-system + name: ^cluster-reconciler-flux-system$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRoleBinding - name: flux-operator + name: ^flux-operator$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRoleBinding - name: velero-server + name: ^velero-server$ # cert-manager (TLS/CA secret management) - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: cert-manager-cainjector + name: ^cert-manager-cainjector$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: cert-manager-controller-certificates + name: ^cert-manager-controller-certificates$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: cert-manager-controller-challenges + name: ^cert-manager-controller-challenges$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: cert-manager-controller-clusterissuers + name: ^cert-manager-controller-clusterissuers$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: cert-manager-controller-issuers + name: ^cert-manager-controller-issuers$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: cert-manager-controller-orders + name: ^cert-manager-controller-orders$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: origin-ca-issuer-controller + name: ^origin-ca-issuer-controller$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: simply-dns-webhook:secret-access + name: ^simply-dns-webhook:secret-access$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: cert-manager-webhook:dynamic-serving + name: ^cert-manager-webhook:dynamic-serving$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: trust-manager + name: ^trust-manager$ # CloudNativePG operator + tenant databases & Barman backups - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: cloudnative-pg + name: ^cloudnative-pg$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: plugin-barman-cloud + name: ^plugin-barman-cloud$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: backstage-db + name: ^backstage-db$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: coroot-db + name: ^coroot-db$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: coroot-db-barman-cloud + name: ^coroot-db-barman-cloud$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: umami-db + name: ^umami-db$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: umami-db-barman-cloud + name: ^umami-db-barman-cloud$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: wedding-db + name: ^wedding-db$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: wedding-db-barman-cloud + name: ^wedding-db-barman-cloud$ # External Secrets Operator - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: external-secrets-cert-controller + name: ^external-secrets-cert-controller$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: external-secrets-controller + name: ^external-secrets-controller$ # Crossplane + upjet providers (reconcile provider-credential Secrets) - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: crossplane + name: ^crossplane$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: ^crossplane:provider:provider-aws-iam-[0-9a-f]+:system$ @@ -166,104 +166,104 @@ spec: # Kyverno policy engine - apiGroup: rbac.authorization.k8s.io kind: Role - name: kyverno:admission-controller + name: ^kyverno:admission-controller$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: kyverno:background-controller + name: ^kyverno:background-controller$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: kyverno:cleanup-controller + name: ^kyverno:cleanup-controller$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: kyverno:reports-controller + name: ^kyverno:reports-controller$ # Observability & monitoring - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: coroot-cluster-agent + name: ^coroot-cluster-agent$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: coroot-operator + name: ^coroot-operator$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: kube-prometheus-stack-grafana-clusterrole + name: ^kube-prometheus-stack-grafana-clusterrole$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: kube-prometheus-stack-kube-state-metrics + name: ^kube-prometheus-stack-kube-state-metrics$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: kube-prometheus-stack-operator + name: ^kube-prometheus-stack-operator$ # Storage (Longhorn, Hetzner CSI) - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: hcloud-csi-controller + name: ^hcloud-csi-controller$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: longhorn-role + name: ^longhorn-role$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: longhorn + name: ^longhorn$ # Cilium CNI & Gateway (TLS secrets) - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: cilium-operator + name: ^cilium-operator$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: cilium-gateway-secrets + name: ^cilium-gateway-secrets$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: cilium-tlsinterception-secrets + name: ^cilium-tlsinterception-secrets$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: hubble-generate-certs + name: ^hubble-generate-certs$ # KEDA autoscaler - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: keda-operator + name: ^keda-operator$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: keda-operator-certs + name: ^keda-operator-certs$ # Kubernetes control-plane (kube-controller-manager) built-in controllers - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: system:controller:generic-garbage-collector + name: ^system:controller:generic-garbage-collector$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: system:controller:namespace-controller + name: ^system:controller:namespace-controller$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: system:controller:resourcequota-controller + name: ^system:controller:resourcequota-controller$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: system:kube-controller-manager + name: ^system:kube-controller-manager$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: system:controller:bootstrap-signer + name: ^system:controller:bootstrap-signer$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: system:controller:token-cleaner + name: ^system:controller:token-cleaner$ # Kubescape operator/scanner - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: kubescape + name: ^kubescape$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: operator + name: ^operator$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: operator + name: ^operator$ # Other platform controllers (flagger, reloader, ksail-operator, OpenBao) - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: flagger + name: ^flagger$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: ksail-operator + name: ^ksail-operator$ - apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: reloader-reloader-role + name: ^reloader-reloader-role$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: vault-config + name: ^vault-config$ - apiGroup: rbac.authorization.k8s.io kind: Role - name: velero-server + name: ^velero-server$