docs: cert-manager is on v1.21.1, and the mirror outage has its AAR

Seven minors in sequence as the documentation requires, each rolled out and
verified before the next was pushed: three deployments on the new version and
fifteen certificates Ready every time. Measured on the target images first, so
the point was known before the work: eight critical findings become zero and a
hundred and twenty-eight high become twenty-four.

Two candidates were measured and deliberately left alone. Wiki.js runs a
floating tag that points at a newer build than the release tags that look newer
by number — upgrading to 2.5.277 would have tripled its critical findings from
twelve to forty. Draupnir has no newer release at all, which sharpens what pile
A means: a package having a fix is not the same as an image existing that
carries it.

The mirror outage gets its own review. Between step one and two the pipeline
stood for an hour because git.lab could not reach the operating host on 443
while its firewall was being changed. The cluster never noticed, because the
CoreDNS pointer added yesterday sends the name down the private path — the
design doc warned about the opposite failure, and the mirror image of it is what
happened.
This commit is contained in:
Thore Cimbal
2026-08-21 12:00:00 +00:00
parent 3f634bf5cc
commit 13aecc8da0
3 changed files with 165 additions and 1 deletions
+2 -1
View File
@@ -120,7 +120,7 @@ Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md).
| [0026](docs/adr/0026-pruefziele-werden-abgeleitet-nicht-gepflegt.md) | accepted | ADR-0026: Prüfziele werden abgeleitet, nicht gepflegt — und das Ausbleiben der Herleitung alarmiert |
| [0027](docs/adr/0027-zuletzt-eigener-meilenstein.md) | accepted | ADR-0027: „Zuletzt" wird ein eigener Meilenstein (M6) |
## Open AARs (8)
## Open AARs (9)
- [AAR — Alle geplanten Prüfungen waren dauerhaft rot und meldeten damit nichts mehr](docs/aar/2026-08-18-alle-pruefungen-dauerhaft-rot.md)
- [AAR — Nach der Freischaltung sendete Safari ungefiltert weiter](docs/aar/2026-08-18-safari-sendete-ungefiltert.md)
@@ -130,6 +130,7 @@ Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md).
- [AAR — rohana lief voll, der ThreadNet-Web-Spiegel riss](docs/aar/2026-08-20-rohana-platte-voll-spiegel-gerissen.md)
- [AAR: Clarks Calls und Identitäts-Reset — vier Fehldiagnosen bis zur bekannten Ursache](docs/aar/2026-08-21-clark-calls-reset-vier-fehldiagnosen.md)
- [AAR: Deploy der abgeleiteten CVE-Zielmenge (#0106)](docs/aar/2026-08-21-cve-zielmenge-deploy.md)
- [AAR: Die Ausrollstrecke stand eine Stunde — der Push-Spiegel kam nicht durch](docs/aar/2026-08-21-spiegel-ausfall.md)
## Fehlerklassen (18)
+103
View File
@@ -0,0 +1,103 @@
---
type: aar
status: open
date: 2026-08-21
related:
- "docs/design/2026-08-21-cve-remediation.md"
- "docs/issues/0051-cve-remediation-pass.md"
---
# AAR: Die Ausrollstrecke stand eine Stunde — der Push-Spiegel kam nicht durch
**Schwere:** MEDIUM (kein Produktionsausfall; die Auslieferung neuer Stände war
blockiert) · **Dauer:** ~15:52 bis ~16:57
## What was planned / expected
cert-manager sollte in sieben Fassungssprüngen von v1.14.0 auf v1.21.1 gebracht
werden (#0051). Erwartet war: Commit nach git.lab → Push-Spiegel nach rohana →
Flux zieht binnen einer Minute → Prüfung → nächste Stufe.
## What happened
Stufe 1 (v1.15.5) lief planmäßig; letzter erfolgreicher Spiegel **15:51:56**.
Stufe 2 (v1.16.5) wurde gepusht und **kam nie im Cluster an**. Die Warteschleife
lief sechs Minuten ins Leere, bevor sie abbrach.
Die Kette, Glied für Glied gemessen:
| Prüfung | Ergebnis |
|---|---|
| Commit auf git.lab? | ja, `d90861e` |
| Flux-Kustomization gesund? | `Ready=True`, angewandte Revision `93155c2` |
| GitRepository-Quelle? | `Ready=True`, Artefakt bei `93155c2` |
| Hat **rohana** den Commit? | **nein**`93155c2` |
| Push-Spiegel auf git.lab? | **`to_retry`**, Fehler: *„unable to access … port 443 after 134551 ms: Could not connect to server"* |
Damit war die Ursache benannt: **git.lab erreichte rohana auf 443 nicht.**
Nachgemessen aus drei Netzen: Von sorbs Netz **und** aus dem Hetzner-Cluster war
`188.245.193.243:443` tot, während `:2248` (SSH) antwortete und Gitea über den
**privaten** Pfad `10.0.0.3` gesund war (Version 1.27.0, 0,068 s). Traefik auf
dem Host lief zu dem Zeitpunkt seit **sieben Tagen** durch — es war kein
Dienstausfall.
**Ursache laut sorb:** Auf dem Betriebs-Host wurde an `ufw` und `iptables`
gearbeitet. Der öffentliche Web-Zugang war währenddessen zu.
**Nach der Wiederherstellung des Netzwegs lief der Spiegel trotzdem nicht.**
GitLab hatte nach den Fehlschlägen die Wartezeit hochgesetzt; weder
`enabled=true` noch Aus- und Wiedereinschalten setzte sie zurück. Erst ein
**echtes Push-Ereignis** (ein leerer Commit) stieß ihn an — 15 Sekunden später
`finished`, Flux zog nach, Stufe 2 rollte aus.
## Why the difference
**Routing-Klasse: spec issue** — an der Annahme, nicht am Code.
Der Entwurf zu #0051 kannte den Rückweg jeder Stufe, aber nicht die
Voraussetzung, dass die Strecke überhaupt trägt. Zwischen „Commit gepusht" und
„im Cluster wirksam" liegen bei uns **drei** Glieder — git.lab, der
Push-Spiegel, Flux — und keines davon wird vor einem mehrstufigen Vorhaben
geprüft.
⚠️ Erschwerend, und das ist die eigentliche Pointe: **Der Cluster hat vom
Ausfall nichts gemerkt.** Seit dem 2026-08-21 (#0088) zeigt ein CoreDNS-Eintrag
`rohana.axion1337.de` clusterintern auf `10.0.0.3`. Der Entwurf dazu warnte
ausdrücklich vor dem **umgekehrten** Fall: *„Fällt 10.0.0.3 aus, ist rohana aus
dem Cluster nicht erreichbar, obwohl der öffentliche Weg funktionieren würde."*
Eingetreten ist das Spiegelbild — öffentlich tot, privat gesund. Der Zeiger hat
den Cluster gerettet und zugleich verdeckt, dass draußen etwas kaputt war.
## Learnings
- ⚠️ **Vor einem mehrstufigen Ausrollvorhaben gehört die Strecke selbst
geprüft**, nicht nur der Rückweg. Ein Commit, der git.lab erreicht, ist noch
lange nicht ausgerollt.
- **Ein Push-Spiegel erholt sich nicht von selbst, wenn das Ziel zurückkommt.**
GitLabs Wartezeit-Erhöhung überlebt `enabled=true` und das Aus-/Einschalten;
es braucht ein Push-Ereignis. Ein leerer Commit ist dafür das sauberste
Werkzeug — er ändert den Baum nicht, überspringt also keine Stufe.
- ⚠️ **Bei gestuften Upgrades darf nicht auf Vorrat gepusht werden.** Läge der
Spiegel und stünden fünf Stufen gestapelt im Repo, wendete Flux nach der
Erholung nur den **letzten** Commit an — und übersprang fünf Minor-Fassungen,
was cert-manager ausdrücklich verbietet. Die Regel lautet: erst ausrollen und
prüfen, dann die nächste Stufe pushen.
- **Ein redundanter Pfad verdeckt den Ausfall des anderen**, wenn nichts den
ungenutzten prüft. Der CoreDNS-Zeiger ist richtig und bleibt — aber niemand
merkt, wenn der öffentliche Weg wegbricht.
## Actions
- [x] Spiegel wieder in Betrieb (leerer Commit `5507f13`), Flux zog nach.
- [x] cert-manager in sieben Stufen bis v1.21.1 abgeschlossen, jede Stufe
einzeln geprüft.
- [ ] **Offen:** Es gibt **keine Prüfung**, die einen hängenden Push-Spiegel
meldet. Er stand eine Stunde, und aufgefallen ist es nur, weil ich zufällig
in dem Fenster ausrollen wollte. Eine Regel auf `update_status != finished`
oder auf das Alter von `last_successful_update_at` wäre billig — gehört
als Issue vorgeschlagen, nicht hier entschieden.
- [ ] **Offen:** Ebenso wenig meldet etwas, wenn rohanas **öffentlicher** Weg
wegbricht, solange der private trägt. Der CoreDNS-Zeiger macht den Cluster
unempfindlich und damit blind.
+60
View File
@@ -437,3 +437,63 @@ neun Kommentarzeilen, also am **Diff vor dem Commit**, nicht am Ergebnis.
Soll-Menge") steht kurz vor seinem Nachweis: Die Herleitung läuft stündlich,
die letzte lag vor dem Upgrade. Erscheint `2026.8.0` von selbst, ist das
letzte offene Kriterium von #0106 erfüllt.
### Haufen A, zweiter Posten: cert-manager v1.14.0 → v1.21.1 (sieben Stufen)
**Recherche zuerst.** Die Anleitung lässt nur zwei Wege: *„one minor version at a
time, always choosing the latest patch version"* — oder vollständige
Deinstallation samt Neuinstallation. Gewählt: die sieben Stufen.
In sieben Fassungssprüngen gibt es **zwei** potenziell brechende Änderungen,
beide gegen unseren Stand geprüft und **gegenstandslos**:
| Bruchstelle | Stufe | Bei uns |
|---|---|---|
| ACME-Metriken: `path`-Label entfällt zugunsten von `action` | 1.18→1.19 | `certmanager_acme*` wird **nirgends** ausgewertet |
| `cert-manager-edit` verliert `create` auf Challenges/Orders | 1.19→1.20 | **null** Bindungen auf diese ClusterRole |
**Durchgeführt, jede Stufe einzeln ausgerollt und geprüft:**
| Stufe | Fassung | Deployments | Zertifikate |
|---|---|---|---|
| 1 | v1.15.5 | 3/3 | 15/15 Ready |
| 2 | v1.16.5 | 3/3 | 15/15 Ready |
| 3 | v1.17.4 | 3/3 | 15/15 Ready |
| 4 | v1.18.6 | 3/3 | 15/15 Ready |
| 5 | v1.19.6 | 3/3 | 15/15 Ready |
| 6 | v1.20.3 | 3/3 | 15/15 Ready |
| 7 | **v1.21.1** | 3/3 | **15/15 Ready** |
**Ergebnis, am Zielimage vorab gemessen:** CRITICAL **8 → 0**, HIGH **128 → 24**
über Controller, Webhook und CAInjector.
**Funktionsprobe nach dem letzten Sprung:** Helm `Ready=True`, null
Controller-Fehler in fünf Minuten, alle 15 Zertifikate mit gesetzter
`renewalTime` (die neue Fassung hat sie also gelesen und eingeplant), 15 Orders
im Zustand `valid`, **null** offene Challenges. Es wird nichts neu ausgestellt.
⚠️ **Unterbrochen von einem Vorfall**, siehe `docs/aar/2026-08-21-spiegel-ausfall.md`:
Zwischen Stufe 1 und 2 stand die Ausrollstrecke rund eine Stunde, weil der
Push-Spiegel nach git.lab → rohana nicht mehr durchkam.
### Zwei Kandidaten, die nach Messung NICHT angefasst wurden
**Wiki.js — das „Update" wäre eine Verschlechterung gewesen.** Wir fahren den
gleitenden Tag `2.5`. Es gibt Release-Tags `2.5.275/276/277`, die nach
Versionsnummer neuer aussehen. Gescannt:
| | CRITICAL | HIGH |
|---|---|---|
| `wiki:2.5` (läuft) | **12** | **114** |
| `wiki:2.5.277` | **40** | **247** |
Der gleitende Tag zeigt auf einen **neueren Build** als das Release-Tag. Wer
nach Nummer geurteilt hätte, hätte die kritischen Befunde verdreifacht. Das ist
der beste Beleg dafür, warum „vor dem Update das Zielimage scannen" ins Runbook
gehört.
**Draupnir**`v3.1.0` ist die neueste Fassung (2026-05-07); `develop` ist kein
Release. Seine 5 als „behebbar" gezählten CRITICAL sind es für uns **nicht**:
Ein Paket-Fix nützt nichts, solange niemand das Image neu baut. ⚠️ Das ist eine
Verfeinerung von Haufen A insgesamt — „behebbar" heißt *Paket hat einen Fix*,
nicht *es gibt ein neueres Image*.