ledger: gate 1 for the operating stack upgrade, starting from my own bad call

Yesterday I rejected grafana 13.x on a number I had misread. Seventy against a
hundred and sixty-two high findings is not a comparison when the two images do
not contain the same things: 12.4.9 bundles no plugins at all, 13.2.0 bundles
thirteen, and every one of those findings sits in a plugin binary. The 13.2.0
core is clean where 12.4.9 carries the one critical still on our books.

Size M, so no design document — the schema reserves those for L, and raising the
class to reach a nicer template is the same trick as redefining a criterion to
pass it. Gate one lives in the ledger instead.

The only real danger here is grafana's database migration, which has no way back.
That is why a verified backup is an acceptance criterion rather than a step.
This commit is contained in:
Thore Cimbal
2026-08-21 12:00:00 +00:00
parent 84585246d8
commit 370a678d4f
@@ -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.