[HIGH] CVE-Alarme: eine Matrix-Nachricht pro CVE flutet den Security-Raum -- Zustellung derzeit stumm #51

Closed
opened 2026-08-01 12:02:36 +00:00 by sorb · 2 comments
Owner

Aus dem Deploy von #47 (2026-08-01). Die Pipeline sammelt Daten, die Alarm-Zustellung ist aber abgeklemmt: in monitoring/alertmanager/alertmanager.yml routet room="security" auf einen Null-Receiver (Commit 2b715ca).

Warum

TrivyCriticalVuln und TrivyHighVuln erzeugen eine Alarm-Instanz pro CVE pro Image. Gemessen am ersten Scan-Durchlauf, bei 14 von 29 Images:

Anzahl
CRITICAL (feuert sofort, kein for:) 59
HIGH (for: 24h) 445

Hochgerechnet auf alle 29 Images grob 120 CRITICAL / 900 HIGH.

group_by: [alertname, instance] legt alle in eine Gruppe -> ein Webhook-POST mit ~120 Alarmen. matrix-alerts.py schickt daraus eine Matrix-Nachricht pro Alarm, sequenziell.

Was es zur Schleife macht

save_state() steht in do_POST hinter der Sende-Schleife. Sobald ein Send fehlschlaegt -- Synapse rate-limitet rc_message per Default nach ~10 Nachrichten mit 429 -- fliegt die Exception, der State wird nicht gespeichert, der Receiver antwortet 502. Alertmanager wiederholt daraufhin die komplette Gruppe, und die Fingerprint-Deduplizierung (if fp in state: continue), die genau das verhindern soll, ist beim Retry noch leer. Das wiederholt sich, statt einmalig durchzulaufen.

Zum Scharfschalten noetig

  1. Zustellung buendeln. Entweder matrix-alerts.py auf eine Sammelnachricht pro Webhook-Batch umbauen (die fuenf Pflichtfelder je CVE als eine Zeile -- bleibt vollstaendig), oder die Regeln auf count by (target, severity) aggregieren und die CVE-Details im Dashboard lassen.
  2. State inkrementell speichern, nach jedem erfolgreichen Send, plus 429-Behandlung mit Retry-After.

Danach die room="security"-Route aus alertmanager.yml entfernen.

Kleinere Punkte aus demselben Review

  • TrivyScanStale kann ein Image, das nie erfolgreich gescannt wurde, nicht melden: ohne ersten Report gibt es keine Serie, an der time() - trivy_last_scan_timestamp haengen koennte. Ein dauerhaft fehlschlagendes Image bleibt still; TargetDown deckt nur den toten Exporter ab.
  • Der Exporter prunt den First-Seen-State bei jedem Scrape. Ein transienter Lesefehler (except: continue) loescht die Erstfund-Zeitstempel des betroffenen Targets dauerhaft.
  • coturn/coturn:latest ist als einziges Image ungepinnt (schon in #47 notiert).

Nicht betroffen

Scanner, Exporter, Scrape-Job und Dashboard laufen und sind verifiziert -- Exporter-Last 0,4 s pro Scrape fuer 29 Reports, unkritisch bei 15 s Intervall. Details im monitoring/README.md.

Aus dem Deploy von #47 (2026-08-01). Die Pipeline sammelt Daten, **die Alarm-Zustellung ist aber abgeklemmt**: in `monitoring/alertmanager/alertmanager.yml` routet `room="security"` auf einen Null-Receiver (Commit `2b715ca`). ## Warum `TrivyCriticalVuln` und `TrivyHighVuln` erzeugen eine Alarm-Instanz **pro CVE pro Image**. Gemessen am ersten Scan-Durchlauf, bei 14 von 29 Images: | | Anzahl | |---|---| | CRITICAL (feuert sofort, kein `for:`) | 59 | | HIGH (`for: 24h`) | 445 | Hochgerechnet auf alle 29 Images grob 120 CRITICAL / 900 HIGH. `group_by: [alertname, instance]` legt alle in *eine* Gruppe -> ein Webhook-POST mit ~120 Alarmen. `matrix-alerts.py` schickt daraus **eine Matrix-Nachricht pro Alarm**, sequenziell. ## Was es zur Schleife macht `save_state()` steht in `do_POST` **hinter** der Sende-Schleife. Sobald ein Send fehlschlaegt -- Synapse rate-limitet `rc_message` per Default nach ~10 Nachrichten mit 429 -- fliegt die Exception, der State wird **nicht** gespeichert, der Receiver antwortet 502. Alertmanager wiederholt daraufhin die komplette Gruppe, und die Fingerprint-Deduplizierung (`if fp in state: continue`), die genau das verhindern soll, ist beim Retry noch leer. Das wiederholt sich, statt einmalig durchzulaufen. ## Zum Scharfschalten noetig 1. **Zustellung buendeln.** Entweder `matrix-alerts.py` auf eine Sammelnachricht pro Webhook-Batch umbauen (die fuenf Pflichtfelder je CVE als eine Zeile -- bleibt vollstaendig), oder die Regeln auf `count by (target, severity)` aggregieren und die CVE-Details im Dashboard lassen. 2. **State inkrementell speichern**, nach jedem erfolgreichen Send, plus 429-Behandlung mit `Retry-After`. Danach die `room="security"`-Route aus `alertmanager.yml` entfernen. ## Kleinere Punkte aus demselben Review - `TrivyScanStale` kann ein Image, das **nie** erfolgreich gescannt wurde, nicht melden: ohne ersten Report gibt es keine Serie, an der `time() - trivy_last_scan_timestamp` haengen koennte. Ein dauerhaft fehlschlagendes Image bleibt still; `TargetDown` deckt nur den toten Exporter ab. - Der Exporter prunt den First-Seen-State bei **jedem** Scrape. Ein transienter Lesefehler (`except: continue`) loescht die Erstfund-Zeitstempel des betroffenen Targets dauerhaft. - `coturn/coturn:latest` ist als einziges Image ungepinnt (schon in #47 notiert). ## Nicht betroffen Scanner, Exporter, Scrape-Job und Dashboard laufen und sind verifiziert -- Exporter-Last 0,4 s pro Scrape fuer 29 Reports, unkritisch bei 15 s Intervall. Details im `monitoring/README.md`.
Author
Owner

Entscheidung sorb (2026-08-01): Option „aggregierte Regeln" — umgesetzt in threadnet-operating ff87cb2:

  • TrivyCriticalVulns/TrivyHighVulns als count by (target, target_type, host) — eine Alarm-Instanz pro Image+Severity (Obergrenze ~58 statt ~1200), Summary mit Zähler + Dashboard-Link; trivy_vuln_info bleibt unverändert (Dashboard = Detail-Sicht mit den Pflichtfeldern)
  • Alle drei AAR-Befunde adressiert: State wird inkrementell nach jedem Alarm gespeichert, 1-s-Sende-Drossel (Synapse rc_message), recent_resolved-Dedup verhindert doppelte Fallback-Haken beim Batch-Retry; Teilfehler → 502 liefert nur den Rest nach
  • Stumm-Route + Null-Receiver entfernt — Zustellung wieder scharf (nach Deploy)

Deploy nach neuem Verfahren: Übergabe-Issue mit Mengengerüst/Not-Aus/Rollback liegt im Backlogs-Repo. Follow-up notiert (sorb-Wunsch): CVE-Dashboard als Matrix-Widget im Security-Raum einbetten (Grafana allow_embedding + Lese-Zugang) — eigenes Issue bei Angehen.

**Entscheidung sorb (2026-08-01): Option „aggregierte Regeln"** — umgesetzt in threadnet-operating `ff87cb2`: - `TrivyCriticalVulns`/`TrivyHighVulns` als `count by (target, target_type, host)` — eine Alarm-Instanz pro Image+Severity (Obergrenze ~58 statt ~1200), Summary mit Zähler + Dashboard-Link; `trivy_vuln_info` bleibt unverändert (Dashboard = Detail-Sicht mit den Pflichtfeldern) - **Alle drei AAR-Befunde adressiert:** State wird inkrementell nach jedem Alarm gespeichert, 1-s-Sende-Drossel (Synapse `rc_message`), `recent_resolved`-Dedup verhindert doppelte Fallback-Haken beim Batch-Retry; Teilfehler → 502 liefert nur den Rest nach - Stumm-Route + Null-Receiver entfernt — Zustellung wieder scharf (nach Deploy) **Deploy nach neuem Verfahren:** Übergabe-Issue mit Mengengerüst/Not-Aus/Rollback liegt im Backlogs-Repo. **Follow-up notiert (sorb-Wunsch):** CVE-Dashboard als Matrix-Widget im Security-Raum einbetten (Grafana `allow_embedding` + Lese-Zugang) — eigenes Issue bei Angehen.
Author
Owner

Migriert nach git.lab: axion1337.chat/axion1337.chat-gitops#49 (nur im Lab bzw. via VPN erreichbar — das Lab ist seit 2026-08-01 die Quelle der Wahrheit, siehe gitops#48). Weiterarbeit dort; dieses Gitea-Issue bleibt als Verweis stehen.

**Migriert nach git.lab**: [axion1337.chat/axion1337.chat-gitops#49](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/issues/49) (nur im Lab bzw. via VPN erreichbar — das Lab ist seit 2026-08-01 die Quelle der Wahrheit, siehe gitops#48). Weiterarbeit dort; dieses Gitea-Issue bleibt als Verweis stehen.
sorb closed this issue 2026-08-01 14:26:16 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sorb/axion1337.chat-gitops#51