verfahren: Deploy-Uebergabe als Standardverfahren, AAR zu gitops#47
Nach dem Deploy der CVE-Pipeline (gitops#47) als Verfahren festgehalten. Der Stand war korrekt und gelintet; der Blocker entstand erst aus der Datenmenge, gegen die er lief -- eine Alarm-Instanz pro CVE, real 126 CRITICAL und 1222 HIGH. So etwas faellt in keinem Diff auf, nur beim Messen vor dem Deploy. Neu: - .gitea/ISSUE_TEMPLATE/deploy-uebergabe.yaml -- Uebergabe-Issue mit Pflichtfeldern Mengengeruest, vollstaendiges Deploy-Kommando, Verifikation im laufenden Dienst, Aussenwirkung samt Not-Aus, Rollback - verfahren/deploy-uebergabe.md -- Ablauf und Pruefliste - verfahren/aar-vorlage.md -- AAR-Vorlage - verfahren/aar/2026-08-01-cve-pipeline-gitops47.md -- der ausloesende AAR Abgrenzung im README ergaenzt: hosts/ und shared/ halten offene Punkte, verfahren/ haelt, wie wir arbeiten. Die Uebergabe-Issues laufen bewusst hier statt im Projekt-Repo, weil das Verfahren repo-uebergreifend gilt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0b6060339e
commit
3e81f40178
@@ -0,0 +1,107 @@
|
||||
name: "Deploy-Übergabe"
|
||||
about: "Ein gebauter, noch nicht ausgerollter Stand wird zum Deploy übergeben"
|
||||
title: "[DEPLOY] "
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Für die Übergabe „ich habe gebaut — du rollst aus".
|
||||
Ausführlich: [verfahren/deploy-uebergabe.md](../src/branch/main/verfahren/deploy-uebergabe.md)
|
||||
|
||||
Die Felder sind die Punkte, an denen Übergaben real schiefgegangen sind.
|
||||
Wo nichts zutrifft, `-` eintragen statt das Feld zu löschen.
|
||||
|
||||
- type: input
|
||||
id: stand
|
||||
attributes:
|
||||
label: Stand
|
||||
description: Repo, Branch und Commit, der ausgerollt werden soll
|
||||
placeholder: "sorb/threadnet-operating @ main, b6007c5"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: testtiefe
|
||||
attributes:
|
||||
label: Testtiefe
|
||||
description: Ehrlich einordnen — „ungetestet" ist eine brauchbare Angabe, „läuft" ohne Beleg nicht
|
||||
options:
|
||||
- "ungetestet — nur gelintet / statisch geprüft"
|
||||
- "teilweise getestet — Details unten"
|
||||
- "getestet gegen echte Daten"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: mengengeruest
|
||||
attributes:
|
||||
label: Mengengerüst
|
||||
description: |
|
||||
Wenn der Stand irgendetwas erzeugt (Nachrichten, Alarme, Zeitreihen, Dateien, Requests):
|
||||
Wie viel davon beim ersten Lauf? Geschätzt oder gemessen — bitte dazuschreiben, was von beidem.
|
||||
Genau hier entstehen die Überraschungen: „ein Alarm pro Fund" ist harmlos bei 5 Funden und ein Ausfall bei 126.
|
||||
placeholder: |
|
||||
Alarme: ~1 pro CVE pro Image. An 3 von 29 Images gemessen: 27 CRITICAL / 126 HIGH.
|
||||
Zeitreihen: ~2000. Matrix-Nachrichten: 1 pro Alarm.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: kommando
|
||||
attributes:
|
||||
label: Vollständiges Deploy-Kommando
|
||||
description: |
|
||||
Inklusive aller Reload-, Restart- und Recreate-Schritte.
|
||||
Ein `up -d`, das „Running" meldet und nichts tut, ist der häufigste stille Fehlschlag.
|
||||
render: bash
|
||||
placeholder: |
|
||||
cd /opt/<repo> && git pull
|
||||
cd <stack> && docker compose up -d
|
||||
docker compose up -d --force-recreate <dienste-mit-geaenderter-config>
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: verifikation
|
||||
attributes:
|
||||
label: Woran erkennt man, dass es wirklich greift
|
||||
description: |
|
||||
Konkrete Prüfung **dort, wo der Dienst liest** — im Container, in der API, in der laufenden Config.
|
||||
Ein grüner Linter belegt, dass die Datei gültig ist, nicht dass sie geladen wurde.
|
||||
render: bash
|
||||
placeholder: |
|
||||
docker exec prometheus grep -c axion-cve /etc/prometheus/alerts.yml # erwartet: 1
|
||||
curl -s localhost:9090/api/v1/rules | grep -c axion-cve # erwartet: >0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: aussenwirkung
|
||||
attributes:
|
||||
label: Außenwirkung und Not-Aus
|
||||
description: |
|
||||
Was verlässt beim ersten Lauf das System — Matrix-Räume, Mails, Webhooks, fremde APIs?
|
||||
Und wie schaltet man **nur diesen Kanal** stumm, ohne den ganzen Deploy zu verschieben?
|
||||
Datensammlung und Zustellung getrennt scharf zu schalten ist fast immer möglich und
|
||||
macht aus einer Blockade einen normalen Deploy.
|
||||
placeholder: |
|
||||
Kanal: Matrix-Raum „Security" über Label room=security.
|
||||
Stumm: in alertmanager.yml route room="security" -> receiver "null".
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: rollback
|
||||
attributes:
|
||||
label: Rollback
|
||||
description: Was tun, wenn es schiefgeht — und was davon ist *nicht* zurückholbar (gesendete Nachrichten, externe Writes)?
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: offen
|
||||
attributes:
|
||||
label: Bewusst offen gelassen
|
||||
description: Bekannte Lücken, Nebenfunde, Abgrenzungen. Verhindert, dass die Gegenseite Zeit mit Nachweisen von etwas verbringt, das schon bekannt ist.
|
||||
validations:
|
||||
required: false
|
||||
@@ -9,6 +9,7 @@ Chat-Historie oder einem Kopf verschwindet.
|
||||
```
|
||||
hosts/ ein File pro Host, benannt nach dem Hostnamen
|
||||
shared/ Themen, die mehrere Hosts betreffen (DNS-Zone, Mail-Policy)
|
||||
verfahren/ wiederkehrende Abläufe zwischen Personen und Hosts, plus AARs
|
||||
```
|
||||
|
||||
Faustregel für die Einordnung: **Der Eintrag gehört dorthin, wo die Arbeit
|
||||
@@ -31,6 +32,23 @@ auf CFGMON, dessen Ursache ein blockierter Port auf dem Gameserver ist, gehört
|
||||
|---|---|
|
||||
| DNS-Zone `axion1337.de` und Mail-Policy (IONOS) | [shared/zone-axion1337.md](shared/zone-axion1337.md) |
|
||||
|
||||
## Verfahren
|
||||
|
||||
`hosts/` und `shared/` halten **offene Punkte**, [verfahren/](verfahren/) hält
|
||||
**wie wir arbeiten** — Abläufe, die zwischen Personen oder über mehrere Hosts
|
||||
hinweg gelten und deshalb an kein einzelnes Projekt-Repo gehören.
|
||||
|
||||
| Verfahren | Inhalt |
|
||||
|---|---|
|
||||
| [Deploy-Übergabe](verfahren/deploy-uebergabe.md) | „einer baut, ein anderer rollt aus": Issue-Vorlage, Prüfliste, AAR |
|
||||
|
||||
Zur Deploy-Übergabe gehört die Issue-Vorlage
|
||||
`.gitea/ISSUE_TEMPLATE/deploy-uebergabe.yaml` — sie erscheint beim Anlegen eines
|
||||
Issues in diesem Repo als **Deploy-Übergabe**. Das ist die eine Ausnahme von der
|
||||
Regel unter „Verhältnis zu Gitea-Issues": die Übergabe-Issues laufen hier, weil
|
||||
das Verfahren repo-übergreifend gilt; der fachliche Inhalt bleibt im jeweiligen
|
||||
Projekt-Repo.
|
||||
|
||||
## Konventionen
|
||||
|
||||
**IDs** sind pro Datei fortlaufend mit einem Präfix, das den Ort benennt:
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Verfahren
|
||||
|
||||
Wiederkehrende Abläufe zwischen Personen und Hosts — dort festgehalten, wo sie
|
||||
nicht an einem einzelnen Projekt-Repo hängen.
|
||||
|
||||
| Datei | Inhalt |
|
||||
|---|---|
|
||||
| [deploy-uebergabe.md](deploy-uebergabe.md) | Ablauf und Prüfliste für „einer baut, ein anderer rollt aus" |
|
||||
| [aar-vorlage.md](aar-vorlage.md) | Vorlage für den After Action Report nach einem Deploy |
|
||||
| [aar/](aar/) | Abgelegte AARs, benannt `JJJJ-MM-TT-<vorhaben>.md` |
|
||||
|
||||
Die zugehörige Issue-Vorlage liegt unter
|
||||
`.gitea/ISSUE_TEMPLATE/deploy-uebergabe.yaml` und erscheint beim Anlegen eines
|
||||
Issues in diesem Repo als **Deploy-Übergabe**.
|
||||
|
||||
Abgrenzung zum Rest des Repos: `hosts/` und `shared/` halten **offene Punkte**,
|
||||
dieses Verzeichnis hält **wie wir arbeiten**. Ein Verfahren wird hier nur
|
||||
aufgenommen, wenn es mindestens einmal an einem echten Vorfall gescheitert
|
||||
oder bewährt ist — der auslösende AAR wird jeweils verlinkt.
|
||||
@@ -0,0 +1,45 @@
|
||||
# AAR — <Vorhaben> <Issue-Referenz>
|
||||
|
||||
**Datum:** JJJJ-MM-TT · **Host/Stack:** … · **Auftrag:** …
|
||||
|
||||
## 1. Ergebnis
|
||||
|
||||
Was ist live und verifiziert. Was ist bewusst **nicht** live, und warum.
|
||||
Diese Trennung steht ganz oben — sie ist die einzige Angabe, die jemand
|
||||
braucht, der nur eine Zeile liest.
|
||||
|
||||
## 2. Befunde
|
||||
|
||||
| # | Befund | Schwere | Status |
|
||||
|---|---|---|---|
|
||||
| 1 | … | HIGH / MEDIUM / LOW | abgefangen / behoben / notiert · Issue |
|
||||
|
||||
Schwere nach Auswirkung, nicht nach Aufwand. Zu jedem Befund gehört, **wie er
|
||||
sichtbar wurde** — falls das nicht offensichtlich ist, siehe Abschnitt 4.
|
||||
|
||||
## 3. Verdachtsfälle mit Entwarnung
|
||||
|
||||
Was geprüft und **nicht** bestätigt wurde, mit dem Messwert. Genauso wichtig
|
||||
wie die Befunde: verhindert, dass dieselbe Vermutung beim nächsten Mal erneut
|
||||
Zeit kostet.
|
||||
|
||||
## 4. Was die Befunde ermöglicht hat
|
||||
|
||||
Die Methode, nicht die Chronologie. Wenn ein Befund nur durch eine bestimmte
|
||||
Prüfung sichtbar wurde, gehört genau die hierher — das ist der Teil, der beim
|
||||
nächsten Deploy wiederverwendbar ist.
|
||||
|
||||
## 5. Offen
|
||||
|
||||
Was bleibt, wer entscheidet, was blockiert. Mit Issue-Referenz statt
|
||||
wiederholtem Inhalt.
|
||||
|
||||
---
|
||||
|
||||
Regeln:
|
||||
|
||||
- Nicht verifizierte Aussagen als solche kennzeichnen — eine Vermutung, die wie
|
||||
ein Befund aussieht, kostet später mehr Zeit als sie spart (Konvention aus
|
||||
der [README](../README.md)).
|
||||
- Zahlen statt Adjektive. „Viele Alarme" ist keine Angabe, „126 CRITICAL" ist eine.
|
||||
- Kurz. Ein AAR, der nicht gelesen wird, hat keinen Wert.
|
||||
@@ -0,0 +1,66 @@
|
||||
# AAR — CVE-Pipeline `gitops#47`
|
||||
|
||||
**Datum:** 2026-08-01 · **Host/Stack:** CFGMON, `/opt/threadnet-operating/monitoring`
|
||||
**Auftrag:** Deploy eines gebauten, als UNGETESTET übergebenen Stands (Trivy-Scanner,
|
||||
Exporter, Alert-Regeln, Grafana-Dashboard)
|
||||
|
||||
## 1. Ergebnis
|
||||
|
||||
**Live und verifiziert:** Scanner (29/29 Images gescannt), Exporter, Prometheus-Job
|
||||
`cve_exporter`, Regelgruppe `axion-cve`, Grafana-Ordner *Security* mit CVE-Dashboard.
|
||||
|
||||
**Bewusst nicht live:** die Alarm-Zustellung nach Matrix. `room="security"` routet in
|
||||
`alertmanager.yml` auf einen Null-Receiver (Commit `2b715ca` in
|
||||
`sorb/threadnet-operating`). Grund siehe Befund 1.
|
||||
|
||||
## 2. Befunde
|
||||
|
||||
| # | Befund | Schwere | Status |
|
||||
|---|---|---|---|
|
||||
| 1 | Eine Matrix-Nachricht pro CVE. 126 CRITICAL landen in **einer** Alertmanager-Gruppe, nach 24 h kommen 1222 HIGH dazu. Dazu steht `save_state()` in `do_POST` hinter der Sende-Schleife: bricht ein Send ab (Synapse rate-limitet nach ~10 mit 429), wird kein State gespeichert, der Receiver antwortet 502, Alertmanager wiederholt die komplette Gruppe — mit leerer Deduplizierung | HIGH | abgefangen, `gitops#51` |
|
||||
| 2 | `docker compose up -d` aktiviert geänderte Configs nicht. Einzeldatei-Mounts hängen am Inode, `git pull` benennt um. Prometheus lief nach dem Deploy mit alten Regeln — `promtool` fand 9, Prometheus kannte 6, kein Fehler im Log | MEDIUM | behoben via `--force-recreate`, `gitops#52` |
|
||||
| 3 | `TrivyScanStale` kann ein nie erfolgreich gescanntes Image nicht melden — ohne ersten Report existiert keine Serie, an der `time() - trivy_last_scan_timestamp` hängen könnte | LOW | notiert in `gitops#51` |
|
||||
| 4 | Der Exporter prunt den First-Seen-State bei **jedem** Scrape. Ein transienter Lesefehler (`except: continue`) löscht die Erstfund-Zeitstempel des Targets dauerhaft | LOW | notiert in `gitops#51` |
|
||||
| 5 | Grafana-Provisioning für den Security-Ordner fehlte — das Dashboard wäre nie erschienen | — | vom Autor selbst behoben (`cdfadc0`), bevor ausgerollt wurde |
|
||||
|
||||
Gemessene Gesamtlage über alle 29 Images: **126 CRITICAL, 1222 HIGH**, 2710 MEDIUM,
|
||||
1316 LOW. Spitzenreiter `goauthentik/server:2026.2.3` mit 369 CRITICAL+HIGH.
|
||||
|
||||
## 3. Verdachtsfälle mit Entwarnung
|
||||
|
||||
| Vermutung | Messung | Ergebnis |
|
||||
|---|---|---|
|
||||
| Exporter parst 29 JSONs je Scrape → Timeouts bei 15 s Intervall | `collect()` gegen echte Reports | 0,4 s für 29 Reports, ~3100 Zeilen — unkritisch |
|
||||
| Private Registry `rohana.axion1337.de` braucht Credentials für Trivy | Anonymer Pull | zieht anonym, keine Credentials nötig |
|
||||
| Zwei down-Targets könnten Folge des Deploys sein | `avg_over_time(up[3h])` | 0.00 — schon 3 h vorher tot, in `hosts/game.md` erfasst |
|
||||
|
||||
`promtool check rules`, `amtool check-config`, `amtool config routes test`,
|
||||
`docker compose config` und `py_compile` liefen alle sauber.
|
||||
|
||||
## 4. Was die Befunde ermöglicht hat
|
||||
|
||||
Befund 1 wäre in keinem Lint aufgefallen — der Code ist korrekt, das Problem entsteht
|
||||
erst aus der **Datenmenge**, gegen die er läuft. Sichtbar wurde er durch Messen vor dem
|
||||
Deploy: Trivy lokal über drei repräsentative Images ergab 27 CRITICAL / 126 HIGH auf 3
|
||||
von 29, also die richtige Größenordnung. Die spätere Realität (126 CRITICAL) bestätigte
|
||||
die Entscheidung. `amtool config routes test` belegte danach, dass die Stummschaltung
|
||||
nur `room=security` trifft und den normalen Alarmweg unangetastet lässt.
|
||||
|
||||
Befund 2 wurde nur sichtbar, weil die Config **im Container** geprüft wurde
|
||||
(`docker exec prometheus grep …`) statt auf der Platte. Auf der Platte sah alles richtig
|
||||
aus, `up -d` meldete `Running`, und ein SIGHUP-Reload lud klaglos den alten Inhalt.
|
||||
|
||||
Diese beiden Punkte sind als Verfahren festgehalten:
|
||||
[../deploy-uebergabe.md](../deploy-uebergabe.md).
|
||||
|
||||
## 5. Offen
|
||||
|
||||
Richtungsentscheidung zu `gitops#51`, bevor die Alarme scharf gehen: entweder
|
||||
`matrix-alerts.py` auf eine Sammelnachricht pro Webhook-Batch umbauen (die fünf
|
||||
Pflichtfelder je CVE als eine Zeile, bleibt vollständig), oder die Regeln auf
|
||||
`count by (target, severity)` aggregieren und die CVE-Details im Dashboard lassen.
|
||||
In beiden Fällen zusätzlich: State inkrementell speichern, 429 mit `Retry-After`
|
||||
behandeln. Danach die `room="security"`-Route entfernen.
|
||||
|
||||
Nebenbefund ohne Handlungsbedarf von hier: `coturn/coturn:latest` ist das einzige
|
||||
ungepinnte Image (bereits in `gitops#47` notiert).
|
||||
@@ -0,0 +1,78 @@
|
||||
# Verfahren: Deploy-Übergabe
|
||||
|
||||
Für die Konstellation „einer baut, ein anderer rollt aus". Zweck ist nicht mehr
|
||||
Prozess, sondern **weniger Rückfragen und weniger stille Fehlschläge**.
|
||||
|
||||
Eingeführt am 2026-08-01 nach dem Deploy der CVE-Pipeline (`gitops#47`), siehe
|
||||
[aar/2026-08-01-cve-pipeline-gitops47.md](aar/2026-08-01-cve-pipeline-gitops47.md).
|
||||
|
||||
## Ablauf
|
||||
|
||||
1. Wer baut, öffnet ein Issue aus der Vorlage **Deploy-Übergabe**
|
||||
(`.gitea/ISSUE_TEMPLATE/deploy-uebergabe.yaml`).
|
||||
2. Wer ausrollt, arbeitet die Prüfliste unten ab und deployt.
|
||||
3. Wer ausrollt, hängt den **AAR** als Kommentar an dasselbe Issue
|
||||
(Vorlage: [aar-vorlage.md](aar-vorlage.md)). Bei Befunden ab MEDIUM
|
||||
zusätzlich als Datei unter [aar/](aar/).
|
||||
|
||||
## Die vier Punkte, die den Unterschied machen
|
||||
|
||||
### 1. Mengengerüst vor dem Deploy
|
||||
|
||||
Bei allem, was etwas erzeugt — Nachrichten, Alarme, Zeitreihen, Requests —
|
||||
gehört die erwartete Anzahl beim **ersten** Lauf in die Übergabe. Geschätzt ist
|
||||
in Ordnung, gemessen ist besser; welches von beidem, muss dabeistehen.
|
||||
|
||||
Der Grund: „ein Alarm pro Fund" ist eine völlig unauffällige Zeile im Code und
|
||||
harmlos bei 5 Funden. Bei 126 ist es ein Ausfall. Der Unterschied steht nirgends
|
||||
im Diff — er ergibt sich erst aus den Daten, gegen die das Ding läuft.
|
||||
|
||||
Eine Stichprobe reicht: drei repräsentative Elemente von 29 messen und
|
||||
hochrechnen kostet Minuten und liefert die Größenordnung.
|
||||
|
||||
### 2. Verifikation dort, wo der Dienst liest
|
||||
|
||||
Ein grüner Linter belegt, dass eine Datei **gültig** ist — nicht, dass sie
|
||||
**geladen** wurde. Diese beiden Aussagen sind bei Bind-Mounts, Caches und
|
||||
Reload-Semantiken regelmäßig verschieden.
|
||||
|
||||
Also im Container prüfen, in der laufenden API, im tatsächlich geladenen
|
||||
Regelwerk. Ein Blick auf die Platte beweist nichts über den Prozess.
|
||||
|
||||
### 3. Deploy-Kommando vollständig übergeben
|
||||
|
||||
Inklusive Reload-, Restart- und Recreate-Schritten. Ein `docker compose up -d`,
|
||||
das `Running` meldet und dabei nichts aktiviert, ist der häufigste stille
|
||||
Fehlschlag: kein Fehler, kein Log, falscher Zustand.
|
||||
|
||||
Konkret auf dem Monitoring-Stack (CFGMON): Einzeldatei-Mounts hängen am Inode,
|
||||
`git pull` benennt beim Schreiben um und erzeugt damit einen neuen — der
|
||||
Container zeigt danach weiter auf die alte Datei. Es braucht
|
||||
`--force-recreate`. Details: `gitops#52`.
|
||||
|
||||
### 4. Zustellwege stumm schalten statt Deploy verschieben
|
||||
|
||||
Datensammlung und Außenwirkung lassen sich fast immer getrennt scharf schalten.
|
||||
Wenn der Zustellweg das Risiko ist, wird **er** abgeklemmt — nicht der ganze
|
||||
Deploy verschoben.
|
||||
|
||||
So läuft die Datensammlung ab sofort, das Dashboard steht, echte Zahlen
|
||||
ersetzen die Schätzung, und die Entscheidung über die Zustellung fällt auf
|
||||
Basis von Messwerten statt Vermutungen. Wichtig: die Stummschaltung gehört
|
||||
committet und dokumentiert, sonst ist sie in zwei Wochen ein Rätsel.
|
||||
|
||||
## Prüfliste für den Ausrollenden
|
||||
|
||||
- [ ] Diff gelesen, nicht nur die Beschreibung
|
||||
- [ ] Mengengerüst plausibel? Bei Zweifel an einer Stichprobe selbst messen
|
||||
- [ ] Configs mit den jeweiligen Werkzeugen validiert (`promtool`, `amtool`,
|
||||
`compose config`, `py_compile` …)
|
||||
- [ ] Außenwirkung identifiziert — was verlässt beim ersten Lauf das System?
|
||||
- [ ] Nach dem Deploy **im Container** verifiziert, dass die neue Config aktiv ist
|
||||
- [ ] Geprüft, ob vorher gesunde Dinge noch gesund sind (keine stille Regression)
|
||||
- [ ] AAR geschrieben, Folge-Issues angelegt, Stummschaltungen dokumentiert
|
||||
|
||||
## Abgrenzung
|
||||
|
||||
Das Verfahren gilt für Übergaben zwischen Personen. Wer baut **und** ausrollt,
|
||||
braucht kein Issue — der AAR lohnt trotzdem, sobald es Befunde ab MEDIUM gab.
|
||||
Reference in New Issue
Block a user