Security Findings: Who Does What¶
Several tools touch vulnerability and secret findings. Each one has one job, so a new scanner, dashboard or alert has an obvious place to land and nothing is counted, stored or announced twice.
flowchart LR
subgraph produce["Produce"]
ci["CI scan / secret-scan<br/>(default branch)"]
rt["Runtime scan<br/>(every running image)"]
kb["kube-bench<br/>(CIS, per node)"]
dast["DAST: ZAP, Nuclei<br/>(CI image, live edge)"]
end
glue["Windmill<br/>(stateless glue)"]
dd[("DefectDojo<br/>the record")]
vm["VictoriaMetrics<br/>numbers"]
graf["Grafana<br/>supply-chain dashboard"]
am["Alertmanager<br/>record integrity"]
bs["Backstage<br/>per-entity card"]
ci --> glue
rt --> glue
kb --> glue
dast --> glue
glue -->|re-import| dd
dd -->|counts| glue
glue -->|metrics| vm
vm --> graf
vm --> am
graf -->|drill-down| dd
bs -->|read-only proxy| dd
| Tool | Its job | Not its job |
|---|---|---|
CI scan / secret-scan jobs |
Produce Grype and gitleaks reports for every image the estate builds | Deciding what is accepted |
Runtime scan (f/security/pod_image_cve_scan) |
Scan every third-party image the cluster runs, a rotating batch four times a day | Images the estate builds (their CI scan is the record) and platform images |
| kube-bench | Produce the CIS benchmark report of each node | — |
DAST: CI dast-baseline job (ci-templates /dast.yml) |
ZAP's passive baseline against the image the pipeline just built, run as a service | The edge in front of the app (proxy, WAF, ingress headers) |
DAST: scheduled edge scan (fleet dast/, daily) |
ZAP's passive baseline and Nuclei's TLS checks against each live public host, through the ingress, the WAF and the SSO | Active attacks: those target the Services behind the WAF |
| DefectDojo | The record: deduplication, lifecycle (open → mitigated), risk acceptances with an owner and an expiry, SLA dates, KEV flags | Paging anyone |
| Windmill | Stateless glue: re-imports every report (f/security/defectdojo_grype_sync, daily) and reads the record back as numbers (f/security/defectdojo_metrics, hourly) |
Holding state of its own |
| VictoriaMetrics | The numbers, written only by defectdojo_metrics |
A second copy of the findings |
Grafana (Security / Supply chain) |
The estate-wide view; every DefectDojo panel links into the record | Triage |
| Alertmanager | Record integrity only: a feed went stale, the metrics cannot be read, an automatic risk acceptance was not renewed, a human risk-acceptance decision is due | "A CVE exists" — that is news, not an outage |
| Pushover digest (grype curator) | CVE news: one daily message with what is new and fixable | — |
| Backstage | The per-entity lens: what the entity's CI scan found, and what the images its pods run carry, with links into DefectDojo and Grafana | Its own copy of the numbers |
| OpenObserve | Events (logs, traces) | Findings |
| GitLab | Code, CI, merge requests; every import carries the commit, ref and job that produced it | Tracking the findings |
The rules behind the map¶
- The default branch is the record. The CI feeds and both ignore-list
curators read only pipelines of the project's default branch. A newer scan
of an unmerged merge request never replaces it, so the record describes
what ships and does not flap between a branch and
main. - One naming rule for running images. The runtime scan records each image
under its repository (product type
mdapi-runtime). The Backstage catalog sync applies the same rule to the pods of each entity's namespace and writes the result into thedefectdojo.org/runtime-productsannotation, so the card names exactly the products the scan records. - Won't-fix lives in DefectDojo. A finding with no upstream fix is held by a risk acceptance with an expiry, renewed while it stays unfixable; a human decision gets an owner and a due date that Alertmanager watches.
- Only passive scans cross the WAF. The edge scan runs from inside the
cluster, and the WAF alerting trusts internal sources: every request the WAF
blocks from there raises a false-positive alert. The edge scan therefore
spiders and reads (ZAP baseline) and checks TLS handshakes (Nuclei
ssl), which the WAF never blocks. Attack payloads target the Services directly, behind the WAF. The CI scan sees the app alone, the edge scan sees what a visitor meets: each one covers what the other cannot. - Every import is traceable. Each test carries
commit_hash,branch_tagandbuild_id(the CI job URL); secret findings link to the exact line of the commit that was scanned.
See Supply Chain Security for the scanners themselves and CIS Kubernetes Benchmark for kube-bench.