diff --git a/docs/ledger/2026-08-22-betriebs-stack-upgrade.md b/docs/ledger/2026-08-22-betriebs-stack-upgrade.md new file mode 100644 index 0000000..c0e5571 --- /dev/null +++ b/docs/ledger/2026-08-22-betriebs-stack-upgrade.md @@ -0,0 +1,114 @@ +--- +type: ledger +date: 2026-08-22 +size: M +status: open +related: + - "docs/issues/0051-cve-remediation-pass.md" + - "docs/wiki/admin/cve-durchgang.md" + - "docs/design/done/2026-08-21-cve-remediation.md" +--- + +# Ledger: Grafana auf 13.x, Loki und Alloy hinterher + +⚠️ **Größenklasse M, deshalb kein Entwurfsdokument.** `schema.yaml` lässt für +`type: design` nur `size: L` zu; die Gate-1-Inhalte stehen darum hier. Die +Klasse auf L zu heben, nur um an die Vorlage zu kommen, wäre dieselbe +Zahlenschieberei, die dieses Projekt sonst anprangert — eine Datei, drei +Fassungszeilen, eine echte Entscheidung ist M. + +## Gate 1 — Umfang, Abnahme, Nicht-Ziele + +**Problem.** Nach dem CVE-Durchgang (#0051) stehen drei Dienste des +Betriebs-Stacks messbar hinter dem Verfügbaren: + +| Dienst | jetzt | Ziel | gemessen | +|---|---|---|---| +| grafana | 12.4.9 | **13.2.0** | 1 CRITICAL → **0** | +| loki | 3.7.1 | **3.7.6** | 41 HIGH → **8** | +| alloy | v1.16.0 | **v1.18.1** | 44 HIGH → **14** | + +Grafana 12.4.9 trägt den **einzigen** CRITICAL, der nach dem Durchgang noch +entschieden werden musste (`GHSA-r277-6w6q-xmqw` in einer mitgelieferten +Go-Abhängigkeit). 13.2.0 hat ihn nicht. + +⚠️ **Die 162 HIGH von 13.2.0 sind kein Rückschritt, und meine gegenteilige +Behauptung vom 2026-08-21 war falsch.** Der Vergleich lautete 70 → 162 und +verglich Bilder mit verschiedenem Inhalt: 12.4.9 bündelt **keine** Plugins +(5 Scan-Ziele), 13.2.0 bündelt **13** (16 Ziele). Alle 162 sitzen in diesen +Plugin-Binaries, **keine einzige im Kern** — dessen Bilanz ist 0/0 gegen 1/3 +bei 12.4.9. 135 davon sind dieselbe Go-stdlib, wiederholt über Binaries, die +Grafana mit einer alten Toolchain gebaut hat; betroffen sind Datenquellen, die +wir nicht benutzen (opentsdb, jaeger, stackdriver, tempo, cloudmonitoring). +Wir fahren Prometheus und Loki, und die sind im Kern. + +**Abnahmekriterien.** + +1. `cve_critical_offen` bleibt **0**, und der Eintrag für `grafana:12.4.9` in + `entscheidungen.json` fällt als `cve_entscheidungen_ohne_befund` auf — er + wird dann entfernt, nicht stehen gelassen. +2. Alle **11** Dashboards laden. ⚠️ Die beiden mit sehr alten Schemas werden + **einzeln angesehen**, nicht mitgezählt: + `operating-docker-host-container-overview` (schemaVersion **12**) und + `k3s-cluster-monitoring` (**32**). Ihr Zustand wird festgehalten, auch wenn + er schlecht ist. +3. Beide Datenquellen antworten, und je ein Panel zeigt **Daten**, nicht nur + einen grünen Test. +4. Loki nimmt weiter Logs an: eine Loki-Serie ist nach dem Sprung **jünger als + fünf Minuten** — Alloy pusht also noch. +5. Nach der nächsten Scan-Runde: Loki ≤ 8 HIGH, Alloy ≤ 14 HIGH, Grafana-Kern + 0 CRITICAL. +6. ⚠️ **Der Rückweg ist vor dem Start geprobt, nicht behauptet:** eine + Sicherung des `grafana_data`-Volumes existiert und ihre Größe ist plausibel. + +**Risiko und Rückweg.** Ein Grafana-Major wandert die SQLite-Datenbank im +Volume, und **ein Downgrade ist nicht vorgesehen**. Ohne Sicherung ist der +Schritt unumkehrbar; mit ihr ist er ein Zurückspielen. Das ist die einzige +echte Gefahr in diesem Vorhaben — Loki und Alloy sind Patch- bzw. +Minor-Sprünge ohne Zustand, der wandern müsste. + +**Nicht-Ziele.** + +- **Die 162 HIGH in Grafanas gebündelten Plugins.** Sie zu beseitigen hieße, + am fremden Image zu schnitzen. Sie gehören benannt, nicht behandelt. +- **Traefik, cadvisor, gitea, portainer-agent** — sie laufen im Portainer-Stack + und nicht aus unserer Compose-Datei. +- **Grafanas Konfiguration** (Anmeldung, RBAC, Provisioning-Format). Nur + Fassungszeilen. +- **HIGH als Kategorie.** Der CRITICAL-first-Zuschnitt aus #0051 gilt weiter; + die HIGH-Gewinne bei Loki und Alloy sind Beifang, kein Ziel. +- Das Homelab und `game-operating`. + +## Gates + +| gate | commit | approval | status | note | +|---|---|---|---|---| +| 1 | PENDING | sorb | DONE | Umfang, sechs Abnahmekriterien, Rückweg benannt; die Ablehnung von 13.x vom Vortag als Fehlvergleich richtiggestellt. | + +## Slices + +| slice | commit | status | note | +|---|---|---|---| + +## Ladder + +| searched | found | outcome | commit | +|---|---|---|---| +| ob eine schlankere Grafana-Variante die 162 HIGH loswird, bevor sie hingenommen werden | `13.2.0-distroless` liefert **exakt dieselben** 0 CRITICAL / 162 HIGH | reused: nichts gebaut — der Befund entkraeftet die naheliegende Vermutung, es seien Betriebssystempakete, und weist auf die gebuendelten Plugins | | +| ob es ein neueres 12.x gibt, bevor der Major gewaehlt wird | 12.4.9 ist das Ende der Reihe (12.4.2 … 12.4.9), kein 12.5 | reused: die Messung statt der Annahme — der Major ist nicht Geschmack, sondern der einzige Weg zu 0 CRITICAL | | +| ob uns die Abschaltung der numerischen Datenquellen-IDs trifft | 702 uid-Objekte, 38 Namens-Strings, **0** Zahlen ueber alle 11 Dashboards | reused: der eigene Bestand als Pruefmassstab statt vorsorglicher Anpassungen (dieselbe Methode wie bei den Authentik-Bruchstellen) | | +| die Bruchstellen von 13.0, bevor gesprungen wird | Image-Renderer ersatzlos entfernt (nutzen wir nicht), `/api` zugunsten `/apis` veraltet, Git-Sync-Datenverlust nur in 13.0.0 | reused: die Herausgeber-Notizen; 13.2.0 laesst den fehlerhaften Zwischenstand aus | | +| ob Trivys eigene Zahl den Vergleich hergibt | nein — die Gesamtzahl vergleicht Images mit verschiedenem Inhalt; erst die Aufteilung nach Fundort (Kern vs. `plugins-bundled`) macht daraus eine Aussage | built: nichts, aber die Auswertung nach Fundort gehoert in den Runbook-Schritt „vor jedem Update das Zielimage scannen" | | + +## Notes + +⚠️ **Dieser Lauf beginnt mit der Korrektur eines eigenen Fehlurteils.** Am +2026-08-21 habe ich 13.x nach einer Zahl verworfen, die ich falsch gelesen +hatte. Der Fehler ist nicht „zu wenig gemessen", sondern **zwei Messungen +verglichen, die nicht vergleichbar waren** — Gesamtzahlen ueber Images mit +verschiedenem Inhalt. Die Lehre gehoert in den Runbook: eine CVE-Zahl ist erst +dann ein Vergleich, wenn beide Seiten dieselbe Menge Dinge enthalten. + +**Kein Issue dahinter.** Dieser Lauf entstand aus sorbs Ansage im Anschluss an +#0051, nicht aus einem Eintrag im Bestand. Ob er einen bekommt, entscheidet +sorb — ohne Zustimmung wird hier keiner angelegt.