#0078 asked for a CVE reporting path with its own room, metrics, a dashboard and aggregated alerts. ADR-0003 decided it on 2026-08-01 and it was built right after; the issue has described an accomplished state ever since. Measured rather than read: the bot is joined, 173 messages stand in the security room, five rules route by label, the dashboard exists. What the check does not say is which images it never looked at. The target list is hand-maintained and covers 27 of 51 running images — 52 percent. Missing are the web client every user loads, both Traefik layers, the registry itself, the whole observability stack, and the scanner's own image. Two entries are scanned and run nowhere, so the room carries findings about an image no one uses. #0106 carries that on, with sorb's requirement: derive the targets from the stack and the registry, drop the list rather than police it.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
<!-- Generated by scripts/gen_status.py — do not edit. -->
|
||||
|
||||
## Issues (48 open, 51 closed)
|
||||
## Issues (48 open, 52 closed)
|
||||
|
||||
Verteilung: M1 2 · M2 16 · M3 4 · M4 11 · M5 15
|
||||
|
||||
@@ -12,7 +12,7 @@ Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md).
|
||||
|
||||
| Issue | Priorität | Status | Title |
|
||||
|---|---|---|---|
|
||||
| [0078](docs/issues/0078-gitops-45-cve-meldeweg-v2-metriken-grafana-dashboard-al.md) | medium | in-progress | CVE-Meldeweg v2: Metriken, Grafana-Dashboard, Alerts in eigenen Matrix-Raum |
|
||||
| [0106](docs/issues/0106-cve-scan-deckt-nur-die-haelfte-zielliste-ist-handgepflegt.md) | high | open | CVE-Scan deckt 52 % — die Zielliste ist handgepflegt und läuft dem Bestand hinterher |
|
||||
| [0072](docs/issues/0072-gitops-34-dsgvo-datenschutz-compliance-konkretisieren.md) | low | open | DSGVO/Datenschutz-Compliance konkretisieren |
|
||||
|
||||
### M2 (16)
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
---
|
||||
type: issue
|
||||
id: "0078"
|
||||
status: in-progress
|
||||
status: done
|
||||
created: 2026-08-01
|
||||
milestone: M1
|
||||
priority: medium
|
||||
projekt: gitops
|
||||
gitlab_iid: "45"
|
||||
related: []
|
||||
related:
|
||||
- "docs/adr/0003-cve-meldeweg-aggregiert.md"
|
||||
- "docs/issues/0106-cve-scan-deckt-nur-die-haelfte-zielliste-ist-handgepflegt.md"
|
||||
---
|
||||
# CVE-Meldeweg v2: Metriken, Grafana-Dashboard, Alerts in eigenen Matrix-Raum
|
||||
|
||||
@@ -30,4 +32,34 @@ Verweise: #31 (Scan existiert), #22 (release-watch), CFGMON-13 im Backlog (Absen
|
||||
|
||||
---
|
||||
*Migriert aus Gitea `sorb/axion1337.chat-gitops#47` — dort erstellt am 2026-08-01 von sorb.*
|
||||
<!-- gitea-migration: sorb/axion1337.chat-gitops#47 -->
|
||||
<!-- gitea-migration: sorb/axion1337.chat-gitops#47 -->
|
||||
|
||||
## Abschluss — 2026-08-21
|
||||
|
||||
**Das Zielbild ist gebaut und liefert.** Es wurde am 2026-08-01 mit ADR-0003
|
||||
entschieden und offenbar unmittelbar danach umgesetzt; das Issue beschreibt
|
||||
seither einen Zustand, der bereits eingetreten war. Nachgemessen, nicht gelesen:
|
||||
|
||||
| Punkt | Beleg |
|
||||
|---|---|
|
||||
| Eigener Matrix-Raum, `@alerts` eingeladen | Raum `security`, Bot mit `join`, **173 Nachrichten**, letzte 2026-08-20 23:03 |
|
||||
| CVEs als Metriken | `trivy_vuln_info`, `trivy_last_scan_timestamp` — 29 Ziele im laufenden Prometheus |
|
||||
| Grafana-Dashboard | `monitoring/grafana/dashboards/security/cve-overview.json` |
|
||||
| Prometheus-Alertregeln | fünf, sämtlich mit `room: security` |
|
||||
| Raum-Routing im Empfänger | `matrix-alerts.py`: Label `room=<name>` → `MATRIX_ROOM_<NAME>` |
|
||||
| Scan-Ort auf dem Betriebs-Host statt Lab-CI | Compose führt `cve-scan` (Trivy) und `cve-exporter` |
|
||||
| Aggregation statt eine Nachricht pro CVE | `count by (target, target_type, host)`, CRITICAL sofort / HIGH nach 24 h |
|
||||
|
||||
Die im Text noch offene Checkbox „Bot einladen — sorb" war zum Zeitpunkt der
|
||||
Prüfung längst erledigt.
|
||||
|
||||
**Abweichung vom Vorschlag im Issue, bewusst und besser:** Vorgeschlagen war
|
||||
`trivy_image_vulnerabilities{image,severity}`. Gebaut wurde `trivy_vuln_info`
|
||||
mit CVE-ID, Severity, `fixed_version` und `first_seen`, aggregiert erst in der
|
||||
Alarmregel. Damit liegt das Einzel-CVE-Detail im Dashboard, ohne den Raum zu
|
||||
fluten — genau die Konsequenz, die ADR-0003 verlangt.
|
||||
|
||||
⚠️ **Ein Fund aus der Prüfung, der nicht mehr hierher gehört:** Die Zielliste
|
||||
des Scans ist handgepflegt und deckt **52 %** des Bestands — `threadnet-web:v0.6.0`,
|
||||
beide Traefik-Schichten und die Registry selbst werden nicht gescannt.
|
||||
Weitergeführt als **#0106**.
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
type: issue
|
||||
id: "0106"
|
||||
status: open
|
||||
created: 2026-08-21
|
||||
milestone: M1
|
||||
priority: high
|
||||
area: security
|
||||
host: cfgmon
|
||||
related:
|
||||
- "docs/issues/0078-gitops-45-cve-meldeweg-v2-metriken-grafana-dashboard-al.md"
|
||||
- "docs/adr/0003-cve-meldeweg-aggregiert.md"
|
||||
---
|
||||
|
||||
# CVE-Scan deckt 52 % — die Zielliste ist handgepflegt und läuft dem Bestand hinterher
|
||||
|
||||
Der CVE-Meldeweg funktioniert: Trivy scannt, der Exporter macht Metriken daraus,
|
||||
fünf Alarmregeln routen aggregiert in den Security-Raum, das Grafana-Dashboard
|
||||
steht. Alles nachgemessen beim Abschluss von #0078.
|
||||
|
||||
**Er scannt nur die falsche Menge.** Die Ziele stammen aus
|
||||
`monitoring/cve/images.txt` — einer von Hand gepflegten Liste, die beim
|
||||
Ausrollen nicht mitgezogen wird.
|
||||
|
||||
## Gemessen am 2026-08-21
|
||||
|
||||
Quellen: `kube_pod_container_info` (Cluster), `container_last_seen{job="operating_cadvisor"}`
|
||||
(Betriebs-Host), `trivy_last_scan_timestamp` (Scan-Ziele) — alle drei in derselben
|
||||
Prometheus-Instanz. Schreibweisen vor dem Vergleich normalisiert.
|
||||
|
||||
| | Anzahl |
|
||||
|---|---|
|
||||
| Images im Cluster | 39 |
|
||||
| Images auf dem Betriebs-Host | 12 |
|
||||
| **zusammen im Betrieb** | **51** |
|
||||
| davon gescannt | **27** |
|
||||
| **Deckung** | **52 %** |
|
||||
|
||||
**24 laufende Images werden nicht gescannt.** Darunter ausgerechnet:
|
||||
|
||||
- `rohana.axion1337.de/sorb/threadnet-web:v0.6.0` — der Client, den **jeder
|
||||
Nutzer im Browser lädt**
|
||||
- `rancher/mirrored-library-traefik:3.6.10` **und** `traefik:v3.7.9` — beide
|
||||
Ingress-Schichten, die **alles TLS terminieren**
|
||||
- `gitea/gitea:1.27.0` — die **Registry selbst**, zugleich Flux' Quelle
|
||||
- `ghcr.io/requarks/wiki:2.5` — das öffentlich erreichbare Wiki
|
||||
- der gesamte Beobachtungs-Stack: `prom/prometheus`, `grafana/grafana`,
|
||||
`grafana/loki`, `prom/alertmanager`, `grafana/alloy`
|
||||
- `python:3.13-slim` — Basis von `matrix-alerts`, `release-watch` und
|
||||
`cve-exporter`
|
||||
- `aquasec/trivy:0.58.2` — **der Scanner scannt sich selbst nicht**
|
||||
- sechs k3s-Bausteine (`klipper-lb`, `local-path-provisioner`, `coredns`,
|
||||
`metrics-server`, …), `coturn:4.17.2`, `postgres:15-alpine`, `postgres:16-alpine`
|
||||
|
||||
**Zwei Ziele werden gescannt, laufen aber nirgends:** `threadnet-web:v0.3.0`
|
||||
und `coturn/coturn:latest`. Die Meldung vom 2026-08-20 23:03 über HIGH-CVEs in
|
||||
`v0.3.0` betrifft ein Image, das niemand benutzt — Rauschen, das wie Signal
|
||||
aussieht.
|
||||
|
||||
## Warum das zählt
|
||||
|
||||
Es ist die Fehlerklasse „meldet Erfolg, ist aber blind", nur eine Ebene höher:
|
||||
Nicht die Prüfung ist kaputt, sondern ihre **Zielmenge**. Der Raum füllt sich
|
||||
zuverlässig mit Meldungen, das Dashboard ist grün gepflegt — und über die drei
|
||||
am stärksten exponierten Bauteile (Client, Ingress, Registry) steht dort nichts.
|
||||
Ein leerer Befund und ein nie gestellter Befund sind in dieser Darstellung nicht
|
||||
unterscheidbar.
|
||||
|
||||
Die Drift ist außerdem nicht theoretisch: Die Liste zeigt `v0.3.0`, produktiv
|
||||
läuft `v0.6.0`. Zwischen beiden liegen drei Fassungen und ein Upstream-Merge.
|
||||
|
||||
## Anforderung (Entscheidung sorb, 2026-08-21)
|
||||
|
||||
> „Wir können nicht jedes Mal eine Liste aktualisieren, wenn ich den Stack
|
||||
> aktualisiere, das muss alles automatisch passieren. Noch besser, wenn generell
|
||||
> alles aus dem Stack und der Registry gescannt wird, nicht nur eine Liste."
|
||||
|
||||
Die Zielmenge wird also **abgeleitet, nicht gepflegt**. `images.txt` entfällt
|
||||
ersatzlos — eine Regel, die Abweichungen einer Liste meldet, wäre nur eine
|
||||
Krücke für eine Liste, die es nicht geben sollte.
|
||||
|
||||
## Was dafür schon da ist
|
||||
|
||||
Alle Quellen liegen bereits in **einer** Prometheus-Instanz, die der Scanner
|
||||
über das vorhandene Compose-Netz erreicht — kein neuer Dienst, keine neuen
|
||||
Zugangsdaten, kein neuer Netzweg:
|
||||
|
||||
| Quelle | Metrik / Ort |
|
||||
|---|---|
|
||||
| Cluster | `kube_pod_container_info` |
|
||||
| Betriebs-Host | `container_last_seen{job="operating_cadvisor", image!=""}` |
|
||||
| Registry | Gitea auf **demselben Host** wie der Scanner (`10.0.0.3`) |
|
||||
|
||||
⚠️ **`job="gameserver_cadvisor"` (20 Images) ist auszuschließen** — game-operating
|
||||
liegt außerhalb des Auftrags. Die Trennung ist ein Beschriftungsvergleich.
|
||||
|
||||
⚠️ **Die Schreibweisen unterscheiden sich** (`docker.io/library/postgres:…`
|
||||
gegen `clamav/clamav:…`). Ohne Normalisierung meldet jeder Abgleich
|
||||
Scheinlücken.
|
||||
|
||||
⚠️ **Offene Frage für den Entwurf:** Wie weit reicht „alles aus der Registry"?
|
||||
Alle Tags aller Repos kann eine Vielzahl alter Fassungen bedeuten — mit
|
||||
entsprechender Scan-Dauer, Cache-Wachstum und Zugriffszahlen bei Docker Hub.
|
||||
Der Umfang gehört begrenzt und begründet.
|
||||
|
||||
## Abgrenzung
|
||||
|
||||
Nicht Teil davon: die Behebung der gefundenen CVEs (#0051), der Meldeweg selbst
|
||||
(#0078, erledigt) und `release-watch` (#0022).
|
||||
Reference in New Issue
Block a user