issues: the two blind spots both AARs ended on, #0108 and #0109

Each AAR today closed with the same shape of gap: something was broken and
nothing said so. A permission list goes stale when a chart moves an internal
target, and the delivery path stops without a word. Both were found by accident.

#0109 is cut differently than its AAR proposed. Alerting on the mirror's own
status field would hang a permanent rule off the admin surface of the one
component we treat as temporary. The distance between the canonical head and
what Flux applied covers all three links instead, and survives replacing any of
them.

#0107 gets a note rather than a rewrite: Synapse v1.158 carries the fix for the
defect that produced those accounts, so the check is a net for regressions and
for accounts already damaged, not a standing need. The paragraph that said
otherwise stays as what was true when it was written.
This commit is contained in:
Thore Cimbal
2026-08-21 12:00:00 +00:00
parent 05140cf702
commit 3749aa6d3d
6 changed files with 263 additions and 17 deletions
+5 -3
View File
@@ -2,9 +2,9 @@
<!-- Generated by scripts/gen_status.py — do not edit. -->
## Issues (48 open, 53 closed)
## Issues (50 open, 53 closed)
Verteilung: M2 16 · M3 4 · M4 11 · M5 16 · M6 1
Verteilung: M2 16 · M3 4 · M4 11 · M5 18 · M6 1
Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md).
@@ -54,12 +54,13 @@ Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md).
| [0100](docs/issues/0100-threadnet-web-13-asset-pfade-tragen-weiterhin-element-themes-e.md) | low | open | Asset-Pfade tragen weiterhin "element" (themes/element/…) |
| [0101](docs/issues/0101-threadnet-call-4-kaputtes-paket-0-19-2-threadnet-6-in-der-regi.md) | low | open | Kaputtes Paket 0.19.2-threadnet.6 in der Registry — Herkunft ungeklärt |
### M5 (16)
### M5 (18)
| Issue | Priorität | Status | Title |
|---|---|---|---|
| [0051](docs/issues/0051-cve-remediation-pass.md) | high | in-progress | CVE-Remediation-Pass: Schwachstellen-Report abarbeiten |
| [0065](docs/issues/0065-gitops-25-k3s-api-security-hardening.md) | high | open | K3s API security hardening |
| [0109](docs/issues/0109-der-weg-vom-commit-ins-cluster-meldet-seinen-stillstand-nicht.md) | high | open | Der Weg vom Commit ins Cluster meldet seinen Stillstand nicht |
| [0058](docs/issues/0058-gitops-14-web-application-firewall-waf.md) | medium | open | Web Application Firewall (WAF) |
| [0059](docs/issues/0059-gitops-16-pod-security-admission-restricted.md) | medium | open | Pod Security Admission (Restricted) |
| [0062](docs/issues/0062-gitops-21-renovate-dependabot-for-chart-and-image-updat.md) | medium | open | Renovate/Dependabot for chart and image updates |
@@ -71,6 +72,7 @@ Bedeutung der Meilensteine: siehe [roadmap.md](roadmap.md).
| [0069](docs/issues/0069-gitops-29-crowdsec-integration.md) | medium | open | CrowdSec integration |
| [0070](docs/issues/0070-gitops-30-falco-runtime-monitoring.md) | medium | open | Falco runtime monitoring |
| [0107](docs/issues/0107-aktives-konto-ohne-profil-zeile-faellt-nur-durch-beschwerde-auf.md) | medium | open | Ein aktives Konto ohne Profil-Zeile fällt nur durch eine Beschwerde auf |
| [0108](docs/issues/0108-erlaubnisliste-veraltet-still-wenn-das-chart-die-verdrahtung-ver.md) | medium | open | Eine Erlaubnisliste veraltet still, wenn das Chart die Verdrahtung verschiebt |
| [0071](docs/issues/0071-gitops-31-trivy-image-scanning-for-cves.md) | low | open | Trivy image scanning for CVEs |
| [0089](docs/issues/0089-gitops-58-eigene-images-sind-unsigniert-beim-deploy-pru.md) | low | open | Eigene Images sind unsigniert — beim Deploy prüft nichts die Herkunft |
| [0090](docs/issues/0090-gitops-59-kein-kubernetes-audit-log-zugriffe-an-der-api.md) | low | open | Kein Kubernetes-Audit-Log — Zugriffe an der API werden nicht protokolliert |
+8 -6
View File
@@ -88,9 +88,11 @@ ruft nach dem Sprung welchen anderen?" war eine `diff`-Zeile entfernt.
- [x] `allow-ingress-haproxy` um `matrix-authentication-service` ergänzt
(`533fcde`), über gitops, mit dem Grund im Manifest.
- [x] Anmeldung wiederhergestellt und belegt: 4× `POST /oauth2/token` 200.
- [ ] **Offen:** Es gibt **keine Prüfung**, die eine Erlaubnisliste gegen die
tatsächliche Verdrahtung hält. Ein Vergleich „welcher Dienst ruft welchen"
gegen die Policies wäre aus dem Rendering ableitbar — gehört als Issue
vorgeschlagen, nicht hier entschieden.
- [ ] **Offen:** Beim nächsten Chart-Sprung gehört „interne Ziele vorher
vergleichen" in die Abnahmeliste, **vor** dem Ausrollen.
- [x] Beide offenen Punkte sind als
[#0108](../issues/0108-erlaubnisliste-veraltet-still-wenn-das-chart-die-verdrahtung-ver.md)
angelegt (M5, sorb am 2026-08-21 zugestimmt): die Abnahme-Zeile vor dem
Ausrollen als sofort wirksamer Teil, der abgeleitete Abgleich als der
eigentliche Befund.
- [ ] **Offen bis #0108 läuft:** Die Abnahme-Zeile „welche internen Ziele haben
sich verschoben?" gilt ab sofort für jeden Chart-Sprung — sie kostet einen
`diff` und braucht kein Werkzeug.
+9 -8
View File
@@ -93,11 +93,12 @@ den Cluster gerettet und zugleich verdeckt, dass draußen etwas kaputt war.
- [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.
- [x] Beide offenen Punkte sind als
[#0109](../issues/0109-der-weg-vom-commit-ins-cluster-meldet-seinen-stillstand-nicht.md)
angelegt (M5, priority high, sorb am 2026-08-21 zugestimmt).
⚠️ **Anders zugeschnitten als hier vorgeschlagen:** Eine Regel auf
`update_status` hinge an der Verwaltungsoberfläche von git.lab — und die
ist bei uns Infrastruktur auf Zeit. Gemessen wird deshalb am Ende der
Kette: der Abstand zwischen kanonischem Stand und dem, was Flux angewandt
hat. Dieselbe Zahl deckt alle drei Glieder ab und überlebt den Austausch
eines davon.
@@ -104,3 +104,25 @@ Konten, die *nie* telefoniert haben; `@clark` hatte 21 Einträge, sämtlich alt.
Maßgeblich ist das **Datum des jüngsten** Tokens im Vergleich zu einem gesunden
Konto. Wer diese Prüfung baut, sollte das Kürzel im Gedächtnis-Eintrag und im
Runbook mitkorrigieren.
## Nachtrag 2026-08-21: Die Ursache ist seit dem Abend behoben
Das Weglassen der Profil-Zeile bei der Reaktivierung war **kein dauerhaftes
Synapse-Verhalten, sondern ein Fehler** — eingeschleppt in v1.150.0, behoben in
v1.157.0. Mit dem ESS-Sprung auf 26.8.0 läuft hier seit dem 2026-08-21 abends
**Synapse v1.158**. Der Erzeuger neuer Fälle ist damit weg.
⚠️ Das ergänzt diesen Text, es widerlegt ihn nicht — und der Abschnitt „Die
Ursache abstellen" oben bleibt als das stehen, was zum Zeitpunkt des Schreibens
richtig war. Was sich ändert, ist die **Dringlichkeit**, nicht der Zweck:
- Der Fund bleibt sinnvoll für Konten, die **vor** dem Sprung beschädigt wurden.
Sie heilen nicht von selbst; `@clark` fiel vier Tage lang niemandem auf.
- Er bleibt sinnvoll als **Rückfallprüfung**. Der Fehler kam einmal durch ein
Upgrade herein und kann durch ein weiteres wiederkommen — dann wieder
unbemerkt, weil Anmeldung und Chat weiterlaufen.
- Was **entfällt**, ist die Annahme, jeder Verwaltungsvorgang erzeuge laufend
neue Fälle. Die Prüfung ist damit eher Netz als Dauerbedarf.
Wer sie baut, sollte das im Zuschnitt berücksichtigen: eine tägliche Stichprobe
ist dafür immer noch das richtige Maß, ein aufwendigerer Bau nicht.
@@ -0,0 +1,108 @@
---
type: issue
id: "0108"
status: open
created: 2026-08-21
milestone: M5
priority: medium
area: security
host: matrix
projekt: gitops
related:
- "docs/aar/2026-08-21-mas-haproxy-netzregel.md"
- "docs/issues/0088-gitops-56-networkpolicy-ausgehender-verkehr-ist-unbesch.md"
- "docs/adr/0026-pruefziele-werden-abgeleitet-nicht-gepflegt.md"
---
# Eine Erlaubnisliste veraltet still, wenn das Chart die Verdrahtung verschiebt
Unsere NetworkPolicies zählen auf, **welcher Dienst welchen anrufen darf**. Die
Liste ist eine Momentaufnahme der Verdrahtung zu dem Zeitpunkt, an dem sie
geschrieben wurde. Verschiebt ein Chart-Upgrade ein internes Ziel, ist die Liste
falsch — ohne dass sich in unseren Manifesten eine Zeile geändert hätte und ohne
dass irgendetwas es meldet. Unter `default-deny` ist das kein Schönheitsfehler,
sondern ein Ausfall.
## Einmal eingetreten, am Tag der Regel selbst
Am 2026-08-21 wurde vormittags `allow-ingress-haproxy` angelegt (#0088), mit drei
erlaubten Quellen: `kube-system`, `draupnir`, `clamav-http-scanner`. Abends hob
ESS von 26.4.0 auf 26.8.0 — und verschob dabei den Synapse-Endpunkt des
Authentifizierungsdienstes vom direkten Dienst `matrix-stack-synapse-main` auf
den haproxy-Dienst `matrix-stack-synapse`.
MAS stand nicht auf der Liste. Ergebnis: `Connection refused` auf
`upsert_device`, `POST /oauth2/token` → **500**, **keine Anmeldung für niemanden**,
rund zwölf Minuten lang. Hergang und Messung im
[AAR](../aar/2026-08-21-mas-haproxy-netzregel.md).
⚠️ **Es war vorab sichtbar.** Beide Chart-Fassungen lagen als `helm template`-
Rendering vor und wurden verglichen — aber nur daraufhin, ob *unsere*
Anpassungen überleben. Die Frage „welches interne Ziel ruft nach dem Sprung
welches andere?" stand im selben Rendering und wurde nicht gestellt.
## Warum ein zweites Mal wahrscheinlich ist
Der Auslöser ist nichts Außergewöhnliches, sondern der Normalfall: **jedes**
Chart-Upgrade darf interne Ziele verschieben, das ist keine Bruchänderung im
Sinne des Herausgebers. Betroffen sind bei uns alle Namespaces mit
`default-deny` — `matrix`, `authentik`, `monitoring` — und die Liste der
Erlaubnisse wächst mit #0088 weiter.
Hinzu kommt: **Der Fehler sieht nicht nach seiner Ursache aus.** „Anmeldung
kaputt nach Upgrade" führt zuerst zum Chart, zum Schema, zur Konfiguration — die
Netzregel von vor sechs Stunden ist der letzte Ort, an dem man sucht. Genau
deshalb kostete er beim ersten Mal Zeit, obwohl die Behebung eine Zeile war.
## Was zu tun ist
**Zwei Dinge, getrennt zu bewerten — das billige zuerst.**
### 1. Eine Zeile in der Abnahmeliste, vor dem Ausrollen
Vor jedem Chart-Sprung gehört gefragt: *welche internen Ziele haben sich
verschoben?* Die Antwort steht in den beiden Renderings, die für den Sprung
ohnehin erzeugt werden. Das kostet einen `diff` und hätte diesen Ausfall
verhindert. Es ist keine Automatisierung, sondern eine Zeile im Vorgehen —
und es ist der Teil, der sofort wirkt.
### 2. Ein Abgleich, der die Liste gegen die Wirklichkeit hält
Der eigentliche Befund ist, dass **nichts** die Erlaubnisliste gegen die
tatsächliche Verdrahtung hält. Die Richtung dafür steht bereits fest, sie ist
dieselbe wie bei den CVE-Prüfzielen: **ableiten statt pflegen**
([ADR-0026](../adr/0026-pruefziele-werden-abgeleitet-nicht-gepflegt.md)).
Aus dem Rendering ist herleitbar, welcher Dienst welchen internen Namen anruft
— das sind konfigurierte Endpunkte in ConfigMaps, Secrets und Env-Variablen.
Diese abgeleitete Menge gegen die Policies zu halten, ergibt zwei Zahlen:
Ziele ohne Erlaubnis und Erlaubnisse ohne Ziel.
⚠️ **Die Ableitung ist der schwierige Teil und darf nicht im Issue entschieden
werden.** Endpunkte stehen nicht an einem Ort und nicht in einer Form; ein Teil
liegt in SOPS-Secrets, die das Rendering gar nicht zeigt. Ob die Ableitung
belastbar genug wird, um daraus einen Alarm zu bauen, oder ob sie nur einen
Bericht rechtfertigt, gehört ins Design-Gate.
## Abnahmekriterien
1. Ein verschobenes internes Ziel wird **vor dem Ausrollen** bemerkt, nicht
durch einen Nutzer nach dem Ausrollen.
2. Der Abgleich wird **rot vorgeführt**, nicht grün behauptet: eine Erlaubnis
testweise entfernen, Meldung erscheint, Erlaubnis zurück.
3. ⚠️ Ein Rendering, aus dem sich **nichts** ableiten ließ, meldet einen
**Fehler** — nicht „0 fehlende Erlaubnisse". Genau diese Verwechslung ist die
Fehlerklasse
[meldet-erfolg-ist-aber-blind](../wiki/stolpersteine/meldet-erfolg-ist-aber-blind.md).
4. Der Fund nennt Quelle, Ziel und Port, damit die Regel ohne weitere Suche
ergänzt werden kann.
## Nicht Teil davon
- **Die Egress-Richtung.** #0088 hat den ausgehenden Verkehr geschlossen; hier
geht es um die eingehende Erlaubnisliste. Ob derselbe Abgleich beide
Richtungen trägt, ist eine Frage fürs Design, keine Zusage.
- **Policies neu entwerfen.** Das Modell aus #0088 bleibt; hier kommt eine
Prüfung dazu, keine andere Regelform.
- **Namespaces ohne `default-deny`.** Wo nichts gesperrt ist, veraltet auch
keine Erlaubnis.
- Das Homelab und `game-operating`.
@@ -0,0 +1,111 @@
---
type: issue
id: "0109"
status: open
created: 2026-08-21
milestone: M5
priority: high
area: infrastructure
host: cfgmon
related:
- "docs/aar/2026-08-21-spiegel-ausfall.md"
- "docs/issues/0088-gitops-56-networkpolicy-ausgehender-verkehr-ist-unbesch.md"
- "docs/issues/0051-cve-remediation-pass.md"
---
# Der Weg vom Commit ins Cluster meldet seinen Stillstand nicht
Zwischen „gepusht" und „läuft" liegen bei uns drei Glieder: das kanonische Repo,
der Push-Spiegel, Flux. **Fällt eines aus, meldet nichts es.** Alles sieht
weiter gesund aus: der Push gelingt, die Flux-Kustomization steht auf
`Ready=True`, die Quelle auf `Ready=True` — nur eben auf einem alten Stand.
Das ist die Fehlerklasse
[artefakt-existiert-liefert-aber-nichts](../wiki/stolpersteine/artefakt-existiert-liefert-aber-nichts.md):
Jedes Einzelteil bezeugt seine Gesundheit, und die Kette liefert trotzdem nicht.
## Am 2026-08-21 stand die Strecke eine Stunde
Beim gestuften cert-manager-Upgrade (#0051) kam Stufe 2 nie im Cluster an. Die
Kette, Glied für Glied gemessen, steht im
[AAR](../aar/2026-08-21-spiegel-ausfall.md); die Kurzfassung: Der Push-Spiegel
stand auf `to_retry`, weil der öffentliche Web-Zugang zum Spiegelziel während
Firewall-Arbeiten zu war. **Aufgefallen ist es nur, weil ich zufällig in diesem
Fenster ausrollen wollte.**
Zwei Umstände machen es schlimmer, als es klingt:
- **Der Spiegel erholt sich nicht von selbst**, wenn das Ziel zurückkommt. Die
Wartezeit-Erhöhung überlebt Aus- und Wiedereinschalten; es braucht ein echtes
Push-Ereignis. Ein unbemerkter Ausfall bleibt also auch nach dem Ende seiner
Ursache bestehen.
- ⚠️ **Der Cluster hat vom Ausfall nichts gemerkt**, weil seit #0088 ein
CoreDNS-Eintrag den Spiegel-Namen clusterintern auf die private Adresse zeigt.
Der Entwurf dazu warnte vor dem *umgekehrten* Fall; eingetreten ist das
Spiegelbild — öffentlich tot, privat gesund. Der Zeiger hat den Cluster
gerettet und **zugleich verdeckt**, dass draußen etwas kaputt war.
## Warum das mehr ist als eine Unbequemlichkeit
Solange die Strecke steht, sind **alle Sicherheitsbehebungen wirkungslos**, die
über sie ausgeliefert werden — und niemand erfährt es. Genau das ist der Zustand
von #0051: Ein Commit mit −14 CRITICAL im Repo und ein Cluster, der ihn nicht
kennt, sehen von außen identisch aus. Was hier fehlt, ist keine Bequemlichkeit,
sondern die Aussage „das Ausgerollte entspricht dem Beschlossenen".
Hinzu kommt eine zweite Falle für gestufte Vorhaben: Läge der Spiegel und würden
mehrere Stufen auf Vorrat gepusht, wendete Flux nach der Erholung nur den
**letzten** Commit an — und überspränge Zwischenstufen, was cert-manager
ausdrücklich verbietet.
## Was zu tun ist
**Am Ende der Kette messen, nicht in ihrer Mitte.**
Der naheliegende Griff wäre eine Regel auf den Spiegel-Zustand des kanonischen
Repos (`update_status != finished`, oder das Alter des letzten Erfolgs). Der ist
billig — aber er hängt an der Verwaltungsoberfläche genau der Komponente, die
bei uns **Entwicklungs-Infrastruktur auf Zeit** ist. Ein Dauer-Alarm auf eine
Schnittstelle, die verschwinden soll, ist ein Artefakt am falschen Ort.
Belastbar und unabhängig davon, welches Glied bricht, ist der **Abstand zwischen
dem kanonischen Stand und dem, was Flux angewandt hat**. Diese eine Zahl deckt
alle drei Ausfälle ab — Repo, Spiegel, Flux — und überlebt es, wenn ein Glied
ausgetauscht wird. Sie ist auch die Zahl, die uns tatsächlich interessiert:
nicht „ist der Spiegel gesund", sondern „ist ausgerollt, was beschlossen wurde".
Zusätzlich, und davon getrennt zu bewerten: **eine Prüfung des öffentlichen Wegs
zum Spiegelziel von außen.** Der interne Zeiger macht den Cluster gegen dessen
Ausfall unempfindlich und damit blind; nur eine Messung, die den privaten Pfad
nicht benutzt, sieht es.
⚠️ **Was der Vergleich braucht, ist noch offen:** Er muss das kanonische Repo
lesen können, und er läuft in der Überwachung, nicht im Cluster. Ob das ein
Lesezugriff, ein bestehender Exporter oder etwas Drittes wird, gehört ins
Design-Gate — samt der Frage, welche Verzögerung normal ist und ab wann sie
Alarm ist.
## Abnahmekriterien
1. Ein Commit, der nach **einer benannten Frist** nicht im Cluster angewandt
ist, führt zu einer Meldung im Wartungsraum — unabhängig davon, welches Glied
der Kette ihn aufgehalten hat.
2. Die Prüfung wird **rot vorgeführt**: Strecke gezielt unterbrechen, Meldung
erscheint, Strecke zurück, Meldung geht weg.
3. ⚠️ Ein Vergleich, der den kanonischen Stand **nicht lesen konnte**, meldet
einen **Fehler** — nicht „kein Rückstand". Sonst sieht ein blinder Prüfer
genauso aus wie eine gesunde Strecke
([meldet-erfolg-ist-aber-blind](../wiki/stolpersteine/meldet-erfolg-ist-aber-blind.md)).
4. Der öffentliche Weg zum Spiegelziel wird von außen geprüft und meldet sich,
**ohne** dass der interne Zeiger die Antwort liefert.
## Nicht Teil davon
- **Den Spiegel ersetzen oder die Topologie ändern.** Dass git.lab kanonisch ist
und rohana die Flux-Quelle, bleibt so. Hier kommt eine Messung dazu.
- **Automatisches Wiederanstoßen** eines hängenden Spiegels. Erst sehen, dann
entscheiden, ob etwas von selbst heilen soll — ein Automatismus, der einen
unbemerkten Ausfall unbemerkt behebt, nimmt nur die Meldung weg.
- **Die Regel „nicht auf Vorrat pushen"** bei gestuften Upgrades. Die steht im
AAR und ist Vorgehen, nicht Werkzeug.
- Das Homelab und `game-operating`.