## Summary The weekly Prowler IaC scan reported 6 critical findings against `argocd/manifests/`. They split cleanly into two patterns: - **Legitimate-by-design RBAC → mute with new compensating controls** - `external-secrets-controller`, `external-secrets-cert-controller` manage `secrets` (KSV-0041) and the cert-controller mutates its own webhook configurations (KSV-0114). This is what the operator is *for*. New CC: `operator-purpose-bound-rbac`. - `kube-state-metrics` (both `minikube-indri` and `k3s-ringtail`) holds `list/watch` on secrets to expose `kube_secret_info` and `kube_secret_labels` metrics. KSM's metric schema only reads metadata, never the `data:` field. New CC: `kube-state-metrics-metadata-only`. - **Over-broad RBAC → fix** - `grafana-clusterrole` had `get/watch/list` on `secrets` because the dashboard-sidecar config used `RESOURCE=both` (ConfigMaps + Secrets). Nothing in the cluster labels Secrets with `grafana_dashboard=1`, so this was unused power. Switched both sidecar instances to `RESOURCE=configmap` and removed `secrets` from the ClusterRole. The IaC cronjob also did not previously pass `--mutelist-file`, which is why every IaC finding reported as unmuted regardless of mutelist configuration. The new `mutelist/iac.yaml` is bundled into the existing `prowler-mutelist` ConfigMap and mounted via `items:` selector. ## Test plan - [ ] `kubectl --context=minikube-indri kustomize argocd/manifests/prowler/` — already passes locally - [ ] `kubectl --context=minikube-indri kustomize argocd/manifests/grafana/` — already passes locally - [ ] Deploy from this branch via `argocd app set prowler --revision prowler-iac-mutelist && argocd app sync prowler` and same for `grafana` - [ ] Manually trigger the IaC cronjob and verify `MUTED=True` on the 6 critical findings (`kubectl --context=minikube-indri -n prowler create job --from=cronjob/prowler-iac-scan prowler-iac-test`) - [ ] Restart grafana pod and confirm dashboards still render (sidecar still finds them via ConfigMap watch) - [ ] After verify, `argocd app set <app> --revision main && argocd app sync <app>` post-merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: #340
54 lines
1.8 KiB
YAML
54 lines
1.8 KiB
YAML
---
|
|
apiVersion: batch/v1
|
|
kind: CronJob
|
|
metadata:
|
|
name: prowler-iac-scan
|
|
namespace: prowler
|
|
spec:
|
|
schedule: "0 2 * * 6" # Saturday 2am
|
|
concurrencyPolicy: Forbid
|
|
jobTemplate:
|
|
spec:
|
|
ttlSecondsAfterFinished: 604800 # Auto-delete after 7 days
|
|
template:
|
|
spec:
|
|
securityContext:
|
|
seccompProfile:
|
|
type: RuntimeDefault
|
|
containers:
|
|
- name: prowler
|
|
image: registry.ops.eblu.me/blumeops/prowler:kustomized
|
|
command: ["/bin/sh", "-c"]
|
|
# Prowler's --mutelist-file is a no-op for the IaC provider
|
|
# (it delegates to Trivy). The Prowler image's trivy shim
|
|
# injects --ignorefile $TRIVY_IGNOREFILE when set; see
|
|
# containers/prowler/Dockerfile.
|
|
env:
|
|
- name: TRIVY_IGNOREFILE
|
|
value: /mutelist/trivyignore.yaml
|
|
args:
|
|
- |
|
|
DATEDIR=/reports/prowler-iac/$(date +%Y-%m-%d)
|
|
mkdir -p "$DATEDIR"
|
|
prowler iac \
|
|
--scan-repository-url https://forge.ops.eblu.me/eblume/blumeops.git \
|
|
-z \
|
|
--output-formats html csv json-ocsf \
|
|
--output-directory "$DATEDIR"
|
|
volumeMounts:
|
|
- name: reports
|
|
mountPath: /reports
|
|
- name: mutelist
|
|
mountPath: /mutelist
|
|
readOnly: true
|
|
restartPolicy: OnFailure
|
|
volumes:
|
|
- name: reports
|
|
persistentVolumeClaim:
|
|
claimName: prowler-reports
|
|
- name: mutelist
|
|
configMap:
|
|
name: prowler-mutelist
|
|
items:
|
|
- key: trivyignore.yaml
|
|
path: trivyignore.yaml
|