Document review matrix and drift checks

This commit is contained in:
2026-06-26 08:29:32 +02:00
parent ad9bb40b95
commit 5fbda4989d
15 changed files with 282 additions and 11 deletions
+1
View File
@@ -23,6 +23,7 @@ Diese Datei enthaelt bewusst **keinen** Arbeitsstand mehr — Status nur in
4. bei Service-Fragen `docs/SERVICE_CATALOG.md`
5. bei Restore/DR `docs/DISASTER_RECOVERY.md` und `docs/RESTORE_MATRIX.md`
6. bei "warum ist das so?"-Fragen `docs/DECISIONS.md`
7. bei periodischen Reviews `docs/HOMELAB_REVIEW_MATRIX.md`
## Harte Regeln
+7
View File
@@ -45,6 +45,8 @@ buendelt das an **einem** Ort und **verlinkt** auf die Quellen statt zu kopieren
| `n8n.kaleschke.info` | Keine pauschale Authelia (native) | Webhook-Endpunkte `/webhook/*` | Ausnahmen-Tabelle; ⚠ Middleware-Abweichung lt. policy-check |
| `plex.kaleschke.info` | Keine Authelia (native Plex) | File-Provider-Route; WAN-Port 32400 + Remote Access aus | DECISIONS 2026-05-28 |
| `home.kaleschke.info` (homeassistant) | Keine Authelia (native HA) | Traefik + `smarthome_net`; LAN-Port 8123 | Ausnahmen-Tabelle; ⚠ Middleware-Abweichung lt. policy-check |
| `dawarich.kaleschke.info` (UI) | **two_factor** | `authelia@file,secure-headers@file` (Router `dawarich`, `priority=10`) | `apps/dawarich/docker-compose.yml` Labels; Standortdaten hinter Authelia |
| `dawarich.kaleschke.info` (API-Key-Ingest-Pfade) | **Bypass/native** (App-API-Key, kein 2FA) | Router `dawarich-api` (`priority=100`) nur `secure-headers@file`, Pfade `/api/v1/{health,settings,points,tracks,owntracks,overland,traccar,...}` | `apps/dawarich/docker-compose.yml` Labels; OwnTracks/Overland/Traccar-Tracking muss ohne ForwardAuth pushen koennen (analog n8n-Webhook) |
| AdGuard-Admin | **Tailscale-only**, nicht oeffentlich | Host-Bind `100.80.98.33:8082`, kein Traefik | DECISIONS 2026-05-26 |
| `influxdb3-core` :8181 | **LAN-only** Writer (HA) | Host-Port, kein Traefik, nicht in `frontend_net` | dokumentierte Ausnahme |
@@ -60,6 +62,11 @@ buendelt das an **einem** Ort und **verlinkt** auf die Quellen statt zu kopieren
`homeassistant` sind erwartbar (native Ausnahmen). `grafana` steht **nicht** in
der Ausnahmen-Tabelle und ist als Catch-all-`two_factor` gefuehrt — die
abweichende Middleware ist live zu bestaetigen (offen).
- **Dawarich API-Key-Pfade**: Der `dawarich-api`-Router umgeht Authelia bewusst
fuer die Tracking-Ingest-Pfade (hochsensible Standortdaten). Schutz liegt allein
im Dawarich-App-API-Key. Review-Trigger = neue oeffentliche API-Pfade in der
Router-Regel oder veraendertes Risikoprofil der Standortdaten. Begruendung jetzt
auch in `HOMELAB_ARCHITECTURE_MASTER_V2.md` §10.
## Pflege
+3 -2
View File
@@ -18,11 +18,12 @@ Dieses Dokument beschreibt externe Anbieter und Konten, von denen Betrieb, Recov
| GitHub Mirror | Externer Repo-Mirror `michaelkaleschke-spec/homelab-infra` (privat) | mittel/hoch | Gitea-Verlust abfederbar, aber Bare-Metal-Bootstrap braucht Read-Zugang (PAT oder SSH-Deploy-Key); ohne diesen ist der Mirror im DR nicht klonbar | GitHub-Konto; Push-PAT liegt in Gitea-Mirror-Settings; **Read-PAT/Deploy-Key fuer DR muss zusaetzlich offline im DR-Kit liegen** | Mirror-Status regelmaessig pruefen; lokalen Clone als zweite Kopie behalten; Read-PAT mit Scope `repo:read` separat erzeugen und im DR-Kit ablegen |
| Tailscale | Remote-/Operator-Zugang | hoch | Remote-Zugriff erschwert, lokale Bedienung bleibt | Tailnet-Konto; Node `Kallilabcore`, IPv4 `100.80.98.33` | Break-glass per LAN und physischem Zugriff; Tailnet-Recovery-Codes sichern |
| GMX SMTP | Authelia Notifier, Vaultwarden-Einladungen, Ops-Report-Mail | mittel | Mail-Notifier und Vaultwarden-Einladungen fallen aus; Login selbst nicht zwingend | GMX-Konto; SMTP-Secrets liegen hostseitig | ntfy/zweiter SMTP als Fallback pruefen |
| OpenAI API | Paperless-GPT LLM und Vision-OCR | mittel | Automatische Dokument-Titel, Tags, Korrespondenten und LLM-OCR fallen aus; Paperless selbst laeuft weiter | OpenAI-Projekt/API-Key ausserhalb Repo | Key in Vaultwarden/Komodo sichern, bei Offenlegung rotieren; Kosten/Usage im OpenAI-Projekt beobachten |
| OpenAI API | Paperless-GPT LLM/Vision-OCR (Dokumenttext/-bilder) **und** n8n Mail->LLM->Gitea-Workflow (GMX-Mailinhalt bis ~8000 Zeichen) | mittel | Automatische Dokument-Titel/Tags/Korrespondenten/LLM-OCR und die n8n-Mail-Extraktion fallen aus; Paperless und n8n laufen sonst weiter | je eigener OpenAI-API-Key ausserhalb Repo (Paperless-GPT Stack-ENV; n8n Credentials Store) | Keys in Vaultwarden/Komodo sichern, bei Offenlegung rotieren; Kosten/Usage im OpenAI-Projekt beobachten. **Datenklasse/Retention/Loeschpfad je Egress-Pfad noch offen** (`docs/HOMELAB_REVIEW_MATRIX.md` Domaene 12, `docs/MASTER_TODO.md`) |
| Let's Encrypt | TLS-Zertifikate | hoch | Cert-Erneuerung faellt aus | automatisch via Traefik und Cloudflare DNS-Challenge | Cert-Expiry Alert einrichten; Cloudflare-Token und Traefik-Storage pruefen |
| Container Registries | Image Pulls von Docker Hub, GHCR, LSCR, Gitea Registry u. a. | mittel | Redeploy/Update blockiert | ueberwiegend oeffentlich; keine produktiven Registry-Tokens im Repo | Gepinnte Digests und lokale Runtime helfen kurzfristig; Updates geplant und einzeln deployen |
| Plex Konto | Plex native Auth, Claim und Client-Zugriff ueber `plex.kaleschke.info` | mittel | Plex-Web/App-Login und Clients koennen ausfallen; LAN-Medienpfade bleiben lokal | Plex-Konto ausserhalb Repo; `PLEX_CLAIM` nur fuer Setup | Plex Remote Access bleibt aus; externer Zugriff laeuft ueber Traefik/443. Konto-Recovery separat sichern |
| Mobile Push | ntfy und ggf. mobile Plattform-Pushes | niedrig/mittel | Alerts erreichen Mobilgeraete ggf. nicht | App-/Device-seitig | Kritische Alerts zusaetzlich in Grafana/Glance sichtbar halten |
| Mobile Push | ntfy (self-hosted) und ggf. mobile Plattform-Pushes; Egress = Alert-Payloads/Topic-Namen an Upstream-Push | niedrig/mittel | Alerts erreichen Mobilgeraete ggf. nicht | App-/Device-seitig | Kritische Alerts zusaetzlich in Grafana/Glance sichtbar halten; Payloads/Topics ohne PII/Pfade/Secrets halten (Naming-Regel offen, `docs/HOMELAB_REVIEW_MATRIX.md` Domaene 12) |
| healthchecks.io (Cloud) | Externer Dead-Man's-Switch fuer Host-down-/Backup-Stillstand: Borg-Pre-Hook, baerchen-Nearline-Pull, geplanter Monitoring-Watchdog (#8); interne Job-Checks laufen self-hosted | mittel | Stiller Ausfall von Borg-/Nearline-Lauf wird nicht extern sichtbar; Backups selbst laufen weiter | healthchecks.io-Account; Ping-/Capability-URLs als Host-Secrets (`docs/SECRETS_MAP.md`) | Datenklasse = operative Metadaten (Check-Name/Timing); Naming ohne PII/Pfade/Secrets. Skripte sind endpoint-agnostisch -> bei Bedarf auf self-hosted `hc.kaleschke.info` umstellbar. Bewusste Architektur (DECISIONS 2026-06-23): Host-down-Waechter bleiben extern |
| Operator-DR-Workstation | Bare-Metal-Recovery-Arbeitsplatz (Gaming-PC Windows, lokaler Repo-Clone `G:\Gitea_Clone\homelab-infra`) | kritisch | Ohne Workstation kein Borg-Extract, kein Hetzner-Zugriff, kein Repo-Bootstrap; der Unraid-Host ist im Bare-Metal-Fall gerade weg | Operator-PC, WSL2 + Borg-Client, SSH-Key fuer Hetzner Storage Box, Offline-Kopie der Borg-Passphrase | Setup als bewusste DR-Vorbedingung pflegen (siehe Abschnitt "DR-Workstation Bare-Metal-Kit") |
## Kritische Secrets ausserhalb des Repos
+141
View File
@@ -0,0 +1,141 @@
# Homelab Review Matrix
Typ: Inventar/Review-Landkarte - Stand: 2026-06-26 - Status: aktiv
Diese Matrix erzwingt Abdeckung, nicht Methode. Jede Domaene wird
threat-model-first und mit echtem Ist-Zustand geprueft: Repo, Compose,
Runbooks, Host-Checks, Docker Inspect, API-Exports und Restore-Belege.
Generische Best-Practice-Listen sind hier nur Hilfsmittel, nicht das Ziel.
## Ritual
1. Aelteste oder sicherheitskritische Domaene aus dem Review-Log waehlen.
2. Genau diese eine Domaene tief pruefen.
3. Repo-Soll und Live-Ist getrennt halten: "belegt", "nicht belegt",
"offene Host-Pruefung".
4. Keine Secret-Werte lesen, zitieren oder ins Repo schreiben.
5. Konkrete Befunde in die passende Heimat ueberfuehren:
`MASTER_TODO.md` fuer offene Arbeit, `DECISIONS.md` fuer Entscheidungen,
Zielbild in Architecture/Inventare/Service Catalog, Ablauf in Runbooks.
Kadenz-Vorschlag: eine Domaene alle zwei Wochen. Sicherheitskritisch haeufiger:
Exposure, Identity, Backup-Restore, Data Privacy/Egress, GitOps-Control-Plane.
## Review-Log
| # | Domaene | Reifegrad (1-5) | Zuletzt geprueft | Befund / offene Punkte |
|---|---|:---:|:---:|---|
| 1 | Exposure & Ingress | ? | - | |
| 2 | Identity & Access | ? | - | Authelia-Ausnahmen und native Auth regelmaessig gegen Live-Routen testen |
| 3 | Secrets & Key-Management | ? | in Umsetzung | SOPS+age-Migration/Rotation offen; keine Secret-Werte in Git |
| 4 | Netzwerk-Segmentierung & Blast Radius | ? | - | |
| 5 | Container- & Host-Haertung | ? | - | |
| 6 | Supply Chain | ? | teilweise | Digest-Pinning belegt; Signatur-Verifikation/SBOM/CVE-Gate offen |
| 7 | Backup != Restore | ? | - | Borg->Hetzner belegt; Restore-Drills/Immutability weiter rotieren |
| 8 | Datenintegritaet | ? | - | |
| 9 | Observability-Luecken | ? | - | Alert-on-Absence/Dead-Man-Switch belegt, weiter beweisen |
| 10 | Exit & Portierbarkeit | ? | - | |
| 11 | Update- & Patch-Hygiene | ? | teilweise | Renovate belegt; Host/Engine/Auth-Layer separat betrachten |
| 12 | Data Privacy / Egress / Datenklassifikation | 2 | 2026-06-26 | OpenAI-/Mail-/Healthchecks-/ntfy-/Borg-Egress kartiert; Retention/Loeschpfade und Dawarich-Abdeckung offen |
| 13 | GitOps-Control-Plane & Drift | 3 | 2026-06-26 | Repo-Soll stark; Live-Abgleich fuer Komodo/Runtime/Traefik/Authelia offen; Self-Stack und manuelle Sync-Ausnahmen sind hoechster Hebel |
## 12 - Data Privacy / Egress / Datenklassifikation
**Bedrohung:** Personenbezogene oder sensible Daten verlassen das Lab
unkontrolliert: falscher Dienst, falscher Token, keine Retention, kein
Loesch-/Exportpfad.
**Leitfragen**
- Welche Dienste verarbeiten personenbezogene oder sensible Daten?
- Welche Daten verlassen das Lab an externe Dritte, ueber welchen Pfad und mit
welchem Token/Account?
- Welche Retention gilt beim Dritten? Gibt es Loeschung, Export und Opt-out?
- Gibt es pro Dienst eine Datenklasse und eine erlaubte Egress-Klasse?
- Driftet die reale Datenverarbeitung von `SERVICE_CATALOG.md`,
`EXTERNAL_DEPENDENCIES.md`, Architecture oder Restore-Doku ab?
**Messpunkte**
```bash
rg -n "OPENAI|api\.openai|ANTHROPIC|api_key|API_KEY|webhook|https?://" -g "docker-compose.y*ml" -g "*.env*"
rg -ni "openai|gpt|external|cloud|telemetry|analytics" apps/ ops/ monitoring/
rg -n "httpRequest|emailReadImap|webhook|openai|Authorization|api/v1" apps/n8n/workflows -g "*.json"
rg -n "Dawarich|dawarich|OpenAI|healthchecks.io|ntfy.sh|GitHub Mirror|Hetzner|GMX" docs HOMELAB_ARCHITECTURE_MASTER_V2.md
```
**Befund 2026-06-26**
| Pfad | Belegt | Risiko |
|---|---|---|
| Paperless-GPT -> OpenAI | `apps/paperless-gpt/docker-compose.yml` nutzt OpenAI fuer LLM/Vision OCR | Dokumenttext/Bilder/Metadaten koennen extern verarbeitet werden; Retention/Loeschpfad nicht im Repo dokumentiert |
| n8n Mail -> OpenAI -> Gitea | Workflow-JSON im Repo, Export war inaktiv; live nicht verifiziert | Mailinhalt bis 8000 Zeichen kann an OpenAI gehen; Live-Status und Retention offen |
| GMX IMAP/SMTP | n8n, Vaultwarden, Authelia/Mailpfade dokumentiert | Mailprovider-Retention und Scope nicht als Matrix erfasst |
| Borg -> Hetzner | `EXTERNAL_DEPENDENCIES.md`, Borg-Scope | Verschluesselte Offsite-Kopie vieler Datenklassen; Immutability/Retention weiter beweisen |
| ntfy/Healthchecks | self-hosted + externe Cloud-Waechter dokumentiert | Alert-/Checknamen koennen operative Metadaten leaken |
| Dawarich | Service Catalog + Compose vorhanden | Standortdaten sind hochsensibel; Architecture/Auth/Restore/Backup-Abdeckung war nicht konsistent sichtbar |
**Naechste Optimierungen**
- OpenAI-Retention, Datenkontrollen, Loesch-/Exportpfad und erlaubte Datenklassen
fuer Paperless-GPT und n8n dokumentieren.
- Paperless-GPT nur ueber Tag-/Allowlist oder klare Ausschlussregel auf
Dokumente anwenden.
- Dawarich in Architecture/Auth/Restore/Backup-Scope konsistent eintragen oder
bewusst als Ausnahme dokumentieren.
- Healthchecks/ntfy-Naming-Regel: keine PII, keine Pfade, keine Secrets, keine
aussagekraeftigen internen Namen in Payloads.
## 13 - GitOps-Control-Plane & Drift
**Bedrohung:** Der Steuerpfad driftet vom deklarierten Sollzustand ab oder wird
kompromittiert. Gitea, Komodo, Webhooks, Traefik dynamic config und Authelia
Host-Config verteilen Fehler auf alle Stacks.
**Leitfragen**
- Stimmen lokaler Clone, Gitea `origin/master`, Komodo Stack Workspace,
Docker Runtime und Host-Dateien ueberein?
- Welche Stacks laufen live ohne Repo-Quelle, und welche Repo-Compose-Dateien
haben keinen Komodo-Stack?
- Welche Stack-ENV-Werte werden live in Komodo gepflegt und sind nicht in Git?
- Wie sind Gitea->Komodo-Webhooks authentifiziert, auf Branch `master`
begrenzt und gegen falsche Ausloeser geschuetzt?
- Wer hat Schreibrechte auf Gitea, Komodo und Bot-/Deploy-Tokens?
- Kann ein Push direkt deployen, oder gibt es technische Branch Protection?
- Ist der Recovery-Pfad ohne laufendes Komodo belegt?
**Messpunkte**
```bash
powershell -ExecutionPolicy Bypass -File .\ops\policy-checks\check_repo.ps1
SEND_NTFY=0 bash /mnt/user/services/homelab-infra/services/posture-check/compose-runtime-drift.sh
SEND_NTFY=0 bash /mnt/user/services/homelab-infra/services/posture-check/komodo-stack-hygiene.sh
bash /mnt/user/services/homelab-infra/services/authelia-diff.sh
rsync -nci --checksum /mnt/user/services/homelab-infra/traefik/dynamic/ /mnt/user/appdata/traefik/dynamic/
```
**Befund 2026-06-26**
| Bereich | Belegt | Risiko |
|---|---|---|
| Repo-Soll | `check_repo.ps1`: 0 Critical; lokaler `HEAD` == `origin/master` | Git-Ebene sauber |
| Runtime-Ist | Aus der Windows-Shell nicht gegen Unraid verifizierbar | Host-Pruefung offen; lokale Docker-Missing-Meldungen nicht als Homelab-Drift werten |
| Komodo Self-Stack | `ops/komodo/docker-compose.yml` ist Spiegel/Recovery-Anker; live inline in Komodo | Repo-Aenderung wirkt nicht live; hoechster Drift-Hebel |
| Stack-ENV | Komodo Stack-ENV bewusst nicht vollstaendig in Git | Git allein ist kein vollstaendiger Sollzustand |
| Traefik dynamic | Manuelle Sync-Ausnahme | Auth-Middlewares/File-Routen koennen vom Repo abweichen |
| Authelia Host-Config | `authelia-diff.sh` vergleicht `access_control` | Live-Host-Datei und OIDC-Clientnamen muessen regelmaessig abgeglichen werden |
| Gitea/Komodo Integritaet | Webhook-Regeln dokumentiert; Branch Protection nicht repo-belegt | Prozess-Gate belegt, technisches Enforcement offen |
**Naechste Optimierungen**
- Auf dem Unraid-Host `compose-runtime-drift.sh` und
`komodo-stack-hygiene.sh` ausfuehren und Ergebnisse in
`/mnt/user/services/posture-check/*.json` bewerten.
- Traefik dynamic Drift-Check analog Authelia-Diff als read-only Check
betreiben (`services/traefik-dynamic-diff.sh` / `traefik_dynamic_drift`).
- Komodo Inline-Compose gegen `ops/komodo/docker-compose.yml` diffen, Secret-
Werte maskieren, nur Variablennamen/Pfade dokumentieren.
- Gitea Branch Protection, aktive Hooks, PATs und Deploy-Keys live
inventarisieren; ungenutzte Zugriffe entfernen.
- Healthchecks-Doku-Widerspruch "Webhook offen" vs "Webhook aktiv" bereinigen.
+2
View File
@@ -25,6 +25,8 @@ Host-Reports (`/mnt/user/backups/restore-reports/`) und in der Git-Historie.
| Restore-Test Tailscale | Operator | State-Validierung + Reconnect nur auf Wegwerf-Host/VM, danach Geraet in Tailscale-Admin entfernen | `ops/restore-tests/tailscale-runbook.md` |
| Authelia OIDC fuer Apps | Operator/Codex | Live: Grafana + Mealie login-verifiziert; Paperless Secret verdrahtet und Service-Smoke am 2026-06-17 gruen, finaler Browser-Login mit Operator-Account offen. Immich + Nextcloud bewusst geparkt bis Family-Onboarding (siehe `docs/DECISIONS.md` 2026-06-06) | `docs/AUTHELIA_OIDC_PLAN.md` |
| Home Assistant Tibber | Operator/Codex | Tibber per HA-UI-Config-Flow verbinden. Danach Energy-Dashboard um echte Kosten/Preisquelle ergaenzen; SolarEdge-PV, Netz und Speicher sind bereits konfiguriert und validiert | `docs/runbooks/smart-home-bootstrap.md`, `docs/DECISIONS.md` |
| Review-Follow-up Data Privacy/Egress | Operator/Codex | (1) Datenklasse + Retention/Loeschpfad je externem Egress-Pfad dokumentieren (OpenAI fuer Paperless-GPT+n8n, GMX, healthchecks.io, ntfy-Upstream, Hetzner, GitHub-Mirror). (2) **Dawarich-Backup-Scope schliessen** (Standortdaten aktuell nicht DR-gesichert): `dawarich.dump` in `pre-backup-dumps.sh`, Pfad in Quellliste + Borg-UI-Mount + `BACKUP_SCOPE.md`, danach `RESTORE_MATRIX.md` Tier-2-Zeile + Reifegrad. Dawarich in Architecture §4.2/§7.4/§10 + `AUTH_MATRIX.md` ist am 2026-06-26 angeglichen. | `docs/HOMELAB_REVIEW_MATRIX.md` Domaene 12 |
| Review-Follow-up GitOps-Control-Plane | Operator/Codex | Auf Unraid `compose-runtime-drift.sh`, `komodo-stack-hygiene.sh`, `authelia-diff.sh` und `traefik-dynamic-diff.sh` laufen lassen; danach Branch-Protection/Hooks/PATs in Gitea live inventarisieren | `docs/HOMELAB_REVIEW_MATRIX.md` Domaene 13 |
| Nearline-Pull Dead-Man's-Switch | Operator | **S4U-Root-Cause 2026-06-21 behoben + verifiziert:** Task `KalliLab H Drive Nearline Pull` von S4U auf LogonType `Interactive` ("Nur wenn Benutzer angemeldet") umgestellt (kein Passwort noetig, da `michi` Dauer-Konsolen-User) -> per Planer mit `0x0` bestaetigt. Spiegel frisch, Exit-Code-Leak gefixt, Heartbeat-Pings gepusht. **Verbleibt (optional, niedrige Dringlichkeit):** je einen Healthchecks-Check anlegen + Capability-URL hinterlegen (baerchen ENV `HEALTHCHECKS_NEARLINE_URL`/Datei; Unraid `/mnt/user/appdata/secrets/healthchecks_borg_url`) | `ops/h-drive-nearline/README.md` |
| Healthchecks self-hosted (interne Jobs) | Operator | **Live seit 2026-06-23** auf `https://hc.kaleschke.info` (Komodo-Stack-ID `6a3acf2ca7867a4fbab9bfc1`, beide Container healthy, Superuser angelegt). Gitea->Komodo-Webhook seit 2026-06-23 aktiv. Projekt `KalliLab CORE` + ntfy-Integration (`homelab-alerts`). **7 interne Jobs verdrahtet + verifiziert (Status `up`):** `posture-check` (stuendlich), `cert-token-check`/`compose-runtime-drift`/`daily-status-report` (taeglich), `komodo-stack-hygiene` (woechentlich), `renovate`/`gitea-bundle-mirror` (alle 6h) - je endpoint-agnostischer Ping via EXIT-Trap, Capability-URL als Host-Secret `healthchecks_<job>_url`. **Bewusst NICHT self-hosted:** Borg-Pre-Hook + Nearline bleiben healthchecks.io-Cloud (Host-down-Erkennung); guarded Restore-Jobs (Vaultwarden/Gitea/Paperless/Authelia/Immich) sind wegen Shell-Guard nicht je Cron-Trigger monitorbar. **Verbleibt nur noch optional:** die 2 externen Cloud-Checks scharfschalten. | `ops/healthchecks/README.md` |
+1
View File
@@ -19,6 +19,7 @@ geloescht (Git-Historie ist das Archiv). Verbindliche Doku-Regeln:
| `WORKFLOW.md` | verbindlicher GitOps-/No-Drift-Ablauf |
| `REPO_MAP.md` | technische Landkarte des Repositories + Doku-Regeln |
| `SERVICE_CATALOG.md` | produktiver Service-Katalog |
| `HOMELAB_REVIEW_MATRIX.md` | periodische Review-Landkarte fuer Security, Drift, Restore und Privacy |
| `DECISIONS.md` | Entscheidungs-Register (ADR-light) |
| `MASTER_TODO.md` | einzige operative Statusliste |
+2
View File
@@ -29,6 +29,7 @@ Details gilt immer die betroffene Compose-Datei oder das jeweilige Runbook.
| `HOMELAB_ARCHITECTURE_MASTER_V2.md` | Architektur, Netzmodell, Ausnahmen |
| `docs/WORKFLOW.md` | vor operativen Aenderungen |
| `docs/SERVICE_CATALOG.md` | Service-Zweck, Pfade, Besonderheiten |
| `docs/HOMELAB_REVIEW_MATRIX.md` | periodische Review-Landkarte fuer Abdeckung, Messpunkte und offene Review-Follow-ups |
| `docs/DISASTER_RECOVERY.md` | echter Wiederanlauf |
| `docs/RESTORE_MATRIX.md` | Restore-Quelle je Dienst |
| `docs/SECRETS_MAP.md` | Secret-Namen und Pfade ohne Werte |
@@ -49,6 +50,7 @@ Details gilt immer die betroffene Compose-Datei oder das jeweilige Runbook.
| `services/posture-check/posture-check.sh` | Host-Posture-Check |
| `services/posture-check/export-prometheus-textfile.sh` | Borg-/Container-/Drift-Metriken |
| `services/authelia-diff.sh` | Authelia ACL Repo-zu-Host-Vergleich |
| `services/traefik-dynamic-diff.sh` | Traefik dynamic Repo-zu-Host-Vergleich |
| `ops/h-drive-nearline/pull-critical-backups.ps1` | H:/ Nearline-Pull |
## Doku-Regeln
+5 -5
View File
@@ -43,8 +43,8 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und
| `immich_machine_learning` | Immich ML | `apps/immich/docker-compose.yml` | intern | `immich_default`, `immich_egress` | `model-cache` | rebuildbar | nein | keine Traefik-Route; `immich_egress` (nicht-internal) nur fuer Modell-Download zu huggingface, sonst scheitert Smart Search/Gesichtserkennung an DNS |
| `mealie` | Rezeptverwaltung | `apps/mealie/docker-compose.yml` | `https://mealie.kaleschke.info` | `mealie-postgres`, Traefik | `/mnt/user/appdata/mealie/data` | Tier 2, Borg + `mealie.dump` | ja | App + DB in internem Netz getrennt |
| `mealie-postgres` | Mealie-Datenbank | `apps/mealie/docker-compose.yml` | intern | `mealie_internal` | `/mnt/user/appdata/mealie/postgres18`, archivierter Rollback-Altstand `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/mealie-postgres17`, `mealie_postgres_password.txt` | Dump `mealie.dump` | nein | interne DB; PostgreSQL 18 |
| `dawarich_app` | Standort-Historie / Google-Timeline-Ersatz | `apps/dawarich/docker-compose.yml` | `https://dawarich.kaleschke.info` | eigene PostGIS-DB, eigene Redis, Traefik + Authelia, optional Home Assistant Push | `/mnt/user/appdata/dawarich/{postgres17,redis,shared,public,watched,storage}`, `dawarich_*.txt` Secrets | Tier 2, Borg + `dawarich.dump` | ja + Authelia | UI hinter Authelia; API-Key-Tracking-Endpunkte fuer OwnTracks/Overland/Traccar ohne ForwardAuth priorisiert. App und Sidekiq nutzen `freikin/dawarich:1.8.1`; Prometheus-Scrape nach aktueller Dawarich-Doku ueber `dawarich_app:3000/metrics`, Sidekiq-Metriken intern ueber `:9394`. |
| `dawarich_db` | Dawarich PostGIS-Datenbank | `apps/dawarich/docker-compose.yml` | intern | `backend_net` | `/mnt/user/appdata/dawarich/postgres17`, `dawarich_postgres_password.txt`, `dawarich_grafana_ro_password.txt` | Dump `dawarich.dump`; raw DB nur bei gleichem PG/PostGIS und sauberem Shutdown | nein | PostGIS 17-3.5 Alpine; Grafana-Read-only-User `dawarich_grafana_ro` per Init-Script |
| `dawarich_app` | Standort-Historie / Google-Timeline-Ersatz | `apps/dawarich/docker-compose.yml` | `https://dawarich.kaleschke.info` | eigene PostGIS-DB, eigene Redis, Traefik + Authelia, optional Home Assistant Push | `/mnt/user/appdata/dawarich/{postgres17,redis,shared,public,watched,storage}`, `dawarich_*.txt` Secrets | Tier 2 (Ziel); **Backup-Scope noch offen** - `dawarich.dump` + Appdata sind weder in `ops/borg-ui/BACKUP_SCOPE.md` noch in der Quellliste/`pre-backup-dumps.sh`; bis dahin Standortdaten **nicht** DR-gesichert (siehe `docs/MASTER_TODO.md`) | ja + Authelia | UI hinter Authelia; API-Key-Tracking-Endpunkte fuer OwnTracks/Overland/Traccar ohne ForwardAuth priorisiert (Auth-Sicht: `docs/AUTH_MATRIX.md`, Ausnahme: Architecture §10). App und Sidekiq nutzen `freikin/dawarich:1.8.1`; Prometheus-Scrape nach aktueller Dawarich-Doku ueber `dawarich_app:3000/metrics`, Sidekiq-Metriken intern ueber `:9394`. |
| `dawarich_db` | Dawarich PostGIS-Datenbank | `apps/dawarich/docker-compose.yml` | intern | `backend_net` | `/mnt/user/appdata/dawarich/postgres17`, `dawarich_postgres_password.txt`, `dawarich_grafana_ro_password.txt` | Dump `dawarich.dump` **geplant** (noch nicht in `pre-backup-dumps.sh`); raw DB nur bei gleichem PG/PostGIS und sauberem Shutdown | nein | PostGIS 17-3.5 Alpine; Grafana-Read-only-User `dawarich_grafana_ro` per Init-Script |
| `dawarich_redis` | Dawarich Cache/Queue-Backend | `apps/dawarich/docker-compose.yml` | intern | `backend_net` | `/mnt/user/appdata/dawarich/redis`, `dawarich_redis_password.txt` | Teil von Dawarich-Restore, aber aus DB/Appdaten rekonstruierbar | nein | Redis 8.8 Alpine, keine Host-Ports |
| `mail-archiver` | Mail-Archivierung | `apps/mail-archiver/docker-compose.yml` | `https://mail.kaleschke.info` | PostgreSQL 18, Internet/IMAP, Traefik, Authelia | `/mnt/user/appdata/mailarchiver/data-protection-keys` | Tier 2, `postgresql17-mailarchiver.dump` | ja + Authelia | Hybrid-Dienst: `frontend_net` fuer Internet, `backend_net` fuer DB; App-eigene Auth bleibt zusaetzliche Schutzschicht; Dump-Dateiname behaelt den historischen Cluster-Namen |
| `nextcloud` | Datei-/Cloud-Dienst | `apps/nextcloud/docker-compose.yml` | `https://cloud.kaleschke.info` | eigene PostgreSQL, eigene Redis, Traefik | `/mnt/user/appdata/nextcloud/html`, `/mnt/user/documents/nextcloud-data` | Tier 2, `nextcloud.dump` + Share | ja | native App-Auth ohne zentrale ForwardAuth; WebDAV/CardDAV beachten |
@@ -60,7 +60,7 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und
| Service | Zweck | Autoritativer Pfad | URL / Zugang | Abhaengigkeiten | Datenpfade | Backup / Restore | Traefik | Besonderheiten / TODOs |
|---|---|---|---|---|---|---|---|---|
| `glance` | einziges Homelab-Uebersichts-/Status-Dashboard | `ops/glance/docker-compose.yml`, `ops/glance/config/glance.yml` | `https://glance.kaleschke.info` | Traefik + Authelia, interne HTTP-Checks, Immich API, AdGuard API, Speedtest API, interner Docker-Socket-Proxy | Repo-Konfiguration; keine kritische Persistenz | Tier 3, rebuildbar | ja + Authelia | Zeigt aktive Dienste, Immich-Community-Widget, Internet-/DNS-/VPN-Monitore, AdGuard-DNS-Stats, Speedtest-Livewerte, Docker-Containergruppen, Server-Stats, Zeitfortschritt, Bookmarks und eine Infrastruktur-Seite; Docker-API nur ueber `glance-docker-socket-proxy` auf internem Netz |
| `komodo-core` | GitOps UI/API/Stack-Manager | `ops/komodo/docker-compose.yml` | `https://komodo.kaleschke.info` | Mongo, Gitea, Traefik | `/mnt/user/appdata/komodo/core`, `komodo_keys` | Tier 1 | ja, native Auth | keine pauschale Authelia-ForwardAuth; Gitea DNS override |
| `komodo-core` | GitOps UI/API/Stack-Manager | `ops/komodo/docker-compose.yml` | `https://komodo.kaleschke.info` | Mongo, Gitea, Traefik | `/mnt/user/appdata/komodo/core`, `komodo_keys` | Tier 1 | ja, native Auth | keine pauschale Authelia-ForwardAuth; Gitea DNS override; **Self-Stack ist inline in Komodo verwaltet** (`repo=""`, `webhook_enabled=false`, kein GitOps-Push), `ops/komodo/docker-compose.yml` ist nur Spiegel/Recovery-Anker - Repo-Aenderungen wirken nicht automatisch live (DECISIONS 2026-05-04 / 2026-06-23); IP-Allowlist statt public |
| `komodo-mongo` | Komodo Datenbank | `ops/komodo/docker-compose.yml` | intern | `komodo_net` | `/mnt/user/appdata/komodo/mongo`, `komodo_mongo_password.txt` | Tier 1, `komodo-mongo.archive.gz` | nein | Dump am 2026-05-04 bestaetigt; nach Major-Upgrades pruefen |
| `komodo-periphery` | Komodo Host-Agent | `ops/komodo/docker-compose.yml` | intern Core -> Periphery | Docker socket, `/mnt/user/services`, `frontend_net`, `komodo_net` | `/mnt/user/appdata/komodo/periphery`, `komodo_keys` | Tier 1 | nein | Docker-Socket-Ausnahme; `/mnt/user/services` Mount fuer Stack-Workspaces |
| `borg-ui` | Borg Backup-/Restore UI | `ops/borg-ui/docker-compose.yml` | `https://borg.kaleschke.info` | Traefik + Authelia, Borg repo credentials | `/mnt/user/appdata/borg-ui/data`, `/mnt/user/backups/borg/dumps`, Restore-Ziel | Tier 3 / Backup kritisch, `borg-ui.sqlite` | ja + Authelia | breite Mounts bewusst; `/local/secrets` im DR-Scope; Nextcloud-Daten werden read-only nach `/local/nextcloud/data` eingebunden |
@@ -82,7 +82,7 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und
| `hermes-gateway` | Hermes Agent Gateway/API intern | `ops/hermes-agent/docker-compose.yml` | intern `8642` auf `hermes_net` | SSH Runner (VM 192.168.178.143), LLM Provider, optional Home Assistant | `/mnt/user/appdata/hermes-agent/data`, SSH key path | Tier 3, Borg/Share | nein | NAS-Stack bleibt deaktiviert, solange die separate Hermes-VM/Runner-Seite nicht wiederhergestellt ist; kein Docker-Socket |
| `hermes-dashboard` | Hermes Dashboard | `ops/hermes-agent/docker-compose.yml` | `https://hermes.kaleschke.info` via `${HERMES_DASHBOARD_HOST}` | `hermes-gateway`, Traefik + Authelia | shared read-only data mount | Tier 3, Borg/Share | ja + Authelia | Compose-Profil `dashboard`; aktuell VM-seitig offen, nicht Teil des NAS-Finalstarts |
| `n8n` | Workflow-Automation; aktuell genutzt fuer Mail->LLM->Gitea-Issue (Inbox `Micha/mails`) | `apps/n8n/docker-compose.yml`, `apps/n8n/workflows/*.json` | `https://n8n.kaleschke.info` | Traefik (ohne pauschale Authelia, analog Komodo/Nextcloud), GMX IMAP, OpenAI API, Gitea API | `/mnt/user/appdata/n8n/data` (SQLite, Credentials, Workflows) | Tier 2, Borg + `n8n-data` (Credentials sind nur mit `N8N_ENCRYPTION_KEY` entschluesselbar) | ja, native Auth | Wegen Webhook-Endpunkten (`/webhook/*`) bewusst ohne `authelia@file`; eigene Login-/Owner-Auth bleibt Pflicht; `N8N_ENCRYPTION_KEY` ist Stack-ENV-Pflichtsecret, Verlust macht Credentials unbrauchbar. |
| `healthchecks` | Self-hosted Cron-/Job-Heartbeat-Monitor (Dead-Man's-Switch) fuer interne Jobs/Scripte | `ops/healthchecks/docker-compose.yml`, `ops/healthchecks/README.md` | `https://hc.kaleschke.info` | Traefik (native Auth, ohne pauschale Authelia), `healthchecks-postgres`, ntfy | keine kritische App-Persistenz (Check-Metadaten in der DB) | Tier 3, rebuildbar | ja, native Auth | Hub fuer INTERNE Checks; die externen Host-down-/Backup-Waechter (Borg-Pre-Hook, Nearline-Pull, Monitoring-Watchdog #8) bleiben bewusst auf healthchecks.io-Cloud (ein On-Host-Waechter kann Host-Down nicht melden). Ping-/API-Endpunkte ohne ForwardAuth (analog n8n). Stack-ENV: `HEALTHCHECKS_SECRET_KEY`, `HEALTHCHECKS_DB_PASSWORD`, `HEALTHCHECKS_SUPERUSER_EMAIL/PASSWORD`. **Live seit 2026-06-23** (Komodo-Stack-ID `6a3acf2ca7867a4fbab9bfc1`, deployt via API; Superuser angelegt). Offen: Gitea->Komodo-Webhook noch manuell anzulegen |
| `healthchecks` | Self-hosted Cron-/Job-Heartbeat-Monitor (Dead-Man's-Switch) fuer interne Jobs/Scripte | `ops/healthchecks/docker-compose.yml`, `ops/healthchecks/README.md` | `https://hc.kaleschke.info` | Traefik (native Auth, ohne pauschale Authelia), `healthchecks-postgres`, ntfy | keine kritische App-Persistenz (Check-Metadaten in der DB) | Tier 3, rebuildbar | ja, native Auth | Hub fuer INTERNE Checks; die externen Host-down-/Backup-Waechter (Borg-Pre-Hook, Nearline-Pull, Monitoring-Watchdog #8) bleiben bewusst auf healthchecks.io-Cloud (ein On-Host-Waechter kann Host-Down nicht melden). Ping-/API-Endpunkte ohne ForwardAuth (analog n8n). Stack-ENV: `HEALTHCHECKS_SECRET_KEY`, `HEALTHCHECKS_DB_PASSWORD`, `HEALTHCHECKS_SUPERUSER_EMAIL/PASSWORD`. **Live seit 2026-06-23** (Komodo-Stack-ID `6a3acf2ca7867a4fbab9bfc1`, deployt via API; Superuser angelegt). Gitea->Komodo-Webhook seit 2026-06-23 aktiv (Status: `docs/MASTER_TODO.md`) |
| `healthchecks-postgres` | Healthchecks-Datenbank | `ops/healthchecks/docker-compose.yml` | intern | `healthchecks_internal` | `/mnt/user/appdata/healthchecks/postgres18`, `healthchecks_postgres_password.txt` | Check-Metadaten, rebuildbar | nein | interne DB; PostgreSQL 18; nie `frontend_net` |
## Smart Home
@@ -96,7 +96,7 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und
| Service | Zweck | Autoritativer Pfad | URL / Zugang | Abhaengigkeiten | Datenpfade | Backup / Restore | Traefik | Besonderheiten / TODOs |
|---|---|---|---|---|---|---|---|---|
| `posture-check` | Host-Posture-Audit fuer Filesystem, Mover-Drift, NVMe-SMART, Fuellstand und Authelia-Repo<->Host-Drift | `services/posture-check/posture-check.sh` | Unraid User-Script / Cron / Borg Pre-Hook | `findmnt`, `df`, `nvme`, optional `curl` fuer ntfy; ruft `services/authelia-diff.sh` fuer `authelia_config_drift` auf | `/mnt/user/services/posture-check/last.json` | Repo-Skript + letzter JSON-Status | nein | Muss auf dem Unraid-Host bei Boot, stuendlich und vor Borg laufen; Disk1-NTFS ist nach Disk1 Phase 2 nicht mehr erlaubt (`ALLOW_DISK1_NTFS=0` Standard); Warning/Critical alarmieren via ntfy nur bei neuer Ursache oder nach `ALERT_REPEAT_SECONDS`. Authelia-Drift-Check braucht einen Repo-Spiegel unter `/mnt/user/services/homelab-infra/` (siehe `docs/WORKFLOW.md` Sektion "Ausnahme: Authelia configuration.yml") |
| `posture-check` | Host-Posture-Audit fuer Filesystem, Mover-Drift, NVMe-SMART, Fuellstand, Authelia-Repo<->Host-Drift und Traefik-dynamic-Repo<->Host-Drift | `services/posture-check/posture-check.sh` | Unraid User-Script / Cron / Borg Pre-Hook | `findmnt`, `df`, `nvme`, `rsync`, optional `curl` fuer ntfy; ruft `services/authelia-diff.sh` fuer `authelia_config_drift` und `services/traefik-dynamic-diff.sh` fuer `traefik_dynamic_drift` auf | `/mnt/user/services/posture-check/last.json` | Repo-Skript + letzter JSON-Status | nein | Muss auf dem Unraid-Host bei Boot, stuendlich und vor Borg laufen; Disk1-NTFS ist nach Disk1 Phase 2 nicht mehr erlaubt (`ALLOW_DISK1_NTFS=0` Standard); Warning/Critical alarmieren via ntfy nur bei neuer Ursache oder nach `ALERT_REPEAT_SECONDS`. Authelia- und Traefik-dynamic-Drift-Checks brauchen einen Repo-Spiegel unter `/mnt/user/services/homelab-infra/` |
| `docker-critical-events` | Live-Alarmierung fuer Docker `die`/`oom`/`kill` Events | `services/posture-check/docker-critical-events.sh`, Supervisor `services/posture-check/docker-critical-events-supervisor.sh` | Unraid User-Script / Hintergrundprozess | Docker CLI, ntfy | `/mnt/user/services/posture-check/docker-critical-events-last.log`, PID/Outfile unter `/mnt/user/services/posture-check/` | Repo-Skript + letzter Event-Log | nein | Optional als Unraid User-Script `at array start` starten; Supervisor kann `start`, `stop`, `status`, `smoke`; sendet nach `homelab-alerts` |
## Backup- und Restore-Hinweise
+7 -1
View File
@@ -262,6 +262,7 @@ Diese Ausnahme bleibt bewusst bestehen. Der File-Provider wird weiterhin nur fue
| `traefik/dynamic/middlewares.yml` | `/mnt/user/appdata/traefik/dynamic/middlewares.yml` |
| `traefik/dynamic/tls.yml` | `/mnt/user/appdata/traefik/dynamic/tls.yml` |
| `traefik/dynamic/dashboards.yml` | `/mnt/user/appdata/traefik/dynamic/dashboards.yml` |
| `traefik/dynamic/plex.yml` | `/mnt/user/appdata/traefik/dynamic/plex.yml` |
### Pflicht-Workflow bei Aenderungen an Traefik Dynamic Config
@@ -269,10 +270,15 @@ Diese Ausnahme bleibt bewusst bestehen. Der File-Provider wird weiterhin nur fue
2. Commit + Push
3. Datei manuell auf den Host kopieren
4. Traefik laedt dynamic config automatisch neu
5. Aenderung testen
5. `services/traefik-dynamic-diff.sh` muss `exit 0` liefern
6. Aenderung testen
> **Merksatz:** Git-Commit allein reicht hier nicht. Ohne den manuellen Kopier-Schritt wirkt die Aenderung nicht.
Der Posture-Check (`services/posture-check/posture-check.sh`) ruft
`services/traefik-dynamic-diff.sh` als Check `traefik_dynamic_drift` auf und
meldet Repo-zu-Host-Drift als Warning via ntfy.
---
## Ausnahme: Authelia configuration.yml