From c3491eb3827f80a6c3333d2651936c4512a916bc Mon Sep 17 00:00:00 2001 From: Micha Date: Sat, 6 Jun 2026 10:58:59 +0200 Subject: [PATCH] tailscale: auf natives Plugin konsolidieren, redundanten Docker-Stack entfernen, ACL-Haertung dokumentieren - host-services/tailscale/ (userspace-only Docker-Stack) entfernt; Komodo stop/destroy durch Operator, danach git rm - Glance-Widget Tailscale-Docker entfernt - HOMELAB_ARCHITECTURE/SERVICE_CATALOG/DISASTER_RECOVERY/CLAUDE/RESTORE_MATRIX: tailscale als natives Unraid-Plugin dokumentiert; Restore-State-Pfad korrigiert auf /boot/config/plugins/tailscale/state (Flash-Backup) - NETWORK_INVENTORY: restriktive tag-basierte grants-ACL (2026-06-06; tag:server/tag:operator, tag:family vorbereitet) und Subnet-Router-Befund dokumentiert Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 2 +- HOMELAB_ARCHITECTURE_MASTER_V2.md | 2 +- docs/DISASTER_RECOVERY.md | 9 +- docs/MASTER_TODO.md | 5 +- docs/NETWORK_INVENTORY.md | 146 +++++++++++++-------- docs/RESTORE_MATRIX.md | 2 +- docs/SERVICE_CATALOG.md | 2 +- host-services/tailscale/docker-compose.yml | 25 ---- ops/glance/config/glance.yml | 6 - 9 files changed, 105 insertions(+), 94 deletions(-) delete mode 100644 host-services/tailscale/docker-compose.yml diff --git a/CLAUDE.md b/CLAUDE.md index dcdabfe..e13f65b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -90,7 +90,7 @@ Wenn Drift vermutet wird, nicht raten. Erst die Pflichtmatrix in `docs/GITOPS_DR - `traefik`: Host-Ports 80/443 - `gitea`: SSH-Port 222 - `AdGuard Home`: DNS-Port 53 und LAN-Admin-Port 8082 -- `tailscale`: `network_mode: host` +- `tailscale`: natives Unraid-Plugin (`tailscale.plg`, Interface `tailscale1`), Subnet-Router fuers LAN; nicht repo-/Komodo-verwaltet. Der frueher repo-verwaltete userspace-Docker-Stack `host-services/tailscale/` wurde am 2026-06-06 entfernt. - `Plex-Media-Server`: historischer Host-Netz-Sonderfall, nicht als Repo-Stack enthalten - `scrutiny`: `privileged: true` fuer SMART/Laufwerkszugriff - `Komodo`: Docker-Socket und native Auth ohne pauschale ForwardAuth diff --git a/HOMELAB_ARCHITECTURE_MASTER_V2.md b/HOMELAB_ARCHITECTURE_MASTER_V2.md index f6c8b28..1cc985a 100644 --- a/HOMELAB_ARCHITECTURE_MASTER_V2.md +++ b/HOMELAB_ARCHITECTURE_MASTER_V2.md @@ -240,7 +240,7 @@ Legende Status: | `AdGuard Home` | ✅ | `dns_net` (172.23.0.3), `frontend_net` | Port 53 DNS direkt, Port 8082 Admin nur auf Tailscale-IP `100.80.98.33` | DNS-Server + Upstream zu unbound; kein Traefik fuer Admin-UI | Admin-Port bleibt bewusst ohne Traefik/2FA, aber nicht mehr auf allen LAN-Interfaces | | `unbound` | ✅ | `dns_net` | intern | Upstream-Resolver für AdGuard, isoliert | — | | `ddns-updater` | ✅ | `frontend_net` | intern | Cloudflare DNS API; bleibt in `frontend_net` | Dokumentierte Ausnahme | -| `tailscale` | ✅ | `host` | VPN-Zugang | Git-Stack (`host-services/tailscale/`) | nutzt `NET_ADMIN`, `NET_RAW` und `/dev/net/tun` als dokumentierte VPN-Ausnahme | +| `tailscale` | ✅ | `host` | VPN-Zugang / Subnet-Router | **Natives Unraid-Plugin** (`tailscale.plg`, Interface `tailscale1`, State `/boot/config/plugins/tailscale/state`) — **nicht** repo-/Komodo-verwaltet | Subnet-Router fuer `192.168.178.0/24`; der redundante userspace-Docker-Stack `host-services/tailscale/` wurde am 2026-06-06 entfernt | ### 7.2 Sicherheit / Identity diff --git a/docs/DISASTER_RECOVERY.md b/docs/DISASTER_RECOVERY.md index a819ac3..222aa07 100644 --- a/docs/DISASTER_RECOVERY.md +++ b/docs/DISASTER_RECOVERY.md @@ -290,7 +290,14 @@ Erfolgskriterium: `docker network ls` zeigt `frontend_net`, `backend_net`, `moni 1. `traefik/` 2. `host-services/Adguard/` -3. `host-services/tailscale/` + +> **Tailscale-Hinweis:** Tailscale laeuft als **natives Unraid-Plugin** +> (`tailscale.plg`, Interface `tailscale1`, State `/boot/config/plugins/tailscale/state`, +> im Flash-Backup gesichert) und ist der Subnet-Router fuer `192.168.178.0/24`. +> Es ist **kein** Compose-/Komodo-Stack mehr und kommt mit dem Host hoch — daher +> nicht in dieser Bootstrap-Liste. Der frueher hier gelistete Docker-Stack +> `host-services/tailscale/` (userspace-only, redundant) wurde am 2026-06-06 +> entfernt (siehe `docs/NETWORK_INVENTORY.md`). **LE-Rate-Limit-Vorsicht:** Wenn `/mnt/user/appdata/traefik/letsencrypt/acme.json` verloren oder unklar ist, zuerst gegen Let's Encrypt Staging ausstellen lassen (`--certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory`). Erst nach gruenem Smoke wieder auf Production-CA. Hintergrund: 50 Zertifikate pro Domain pro Woche reicht bei einem hektischen Wiederanlauf nicht, wenn man die Sub-Domains mehrfach hochzieht. diff --git a/docs/MASTER_TODO.md b/docs/MASTER_TODO.md index 12d10b0..f02b32a 100644 --- a/docs/MASTER_TODO.md +++ b/docs/MASTER_TODO.md @@ -57,7 +57,7 @@ Bewusst nicht jetzt - mit Review-Trigger. | End-to-end-DR-Drill | Komplett-Bootstrap Phase 1-5 auf Wegwerf-Host; realistisch erst mit zweiter Hardware (siehe auch Extern blockiert) | `docs/AUDIT_2026-05-25_TODO.md`, `docs/DISASTER_RECOVERY.md` | | Wiederkehrende Restore-Drills | Vaultwarden, Gitea, Authelia, Komodo, Paperless, Immich, Traefik, PostgreSQL, Mongo, Nextcloud, Mealie, Mail-Archiver nach Matrix-Intervallen rotieren | `docs/RESTORE_MATRIX.md`, `docs/RESTORE_HANDBOOK.md` | | Dedizierter SMB-User `veeam-baerchen` | Optional spaeter, nur wenn Unraid-User-/Share-Rechte bewusst angefasst werden | `ops/windows-reinstall/docs/windows-image-backup-baseline.md` | -| Redundanten Docker-Tailscale-Stack abbauen | **Befund 2026-06-06 (read-only verifiziert):** zwei `tailscaled` auf dem Host. Funktional = native Plugin `kallilabcore` (echtes TUN `tailscale1`, Subnet-Router, State `/boot/config/plugins/tailscale/state` im Flash-Backup, `tag:server`). Redundant = Docker-Stack `kallilab-core` (`host-services/tailscale/`, `--tun=userspace-networking` → kann nicht routen, advertised nichts, nichts haengt dran). **Empfehlung:** Docker-Stack sauber per GitOps abbauen (Komodo stop/destroy → `git rm host-services/tailscale/` → Glance-Widget + DR-Bootstrap + Doku nachziehen, Service-Removal-Checkliste aus `docs/WORKFLOW.md`). Eigener sorgfaeltiger Schritt, nichts ad-hoc. Alter Offline-`baerchen`-Node unabhaengig + trivial entfernbar | `docs/NETWORK_INVENTORY.md`, `host-services/tailscale/docker-compose.yml`, `docs/WORKFLOW.md` | +| Tailnet-Konsole aufraeumen (Rest) | Nach Docker-Stack-Abbau (2026-06-06) nur noch tote Node-Eintraege: `kallilab-core` (down) und alter Offline-`baerchen` in der Tailscale-Admin-Konsole entfernen. Optional State-Pfad `/mnt/user/appdata/tailscale` nach `_archive/`. Trivial, kein Risiko | `docs/NETWORK_INVENTORY.md` | | CrowdSec vor Traefik | Bewusst nicht umgesetzt; einzige WAN-Tuer ist `443/tcp`, Authelia `regulation:` deckt Brute-Force ab. Neu bewerten bei breiterer Attack Surface | `docs/AUDIT_2026-05-25_TODO.md` | | Hermes-Agent | NAS-Stack bleibt deaktiviert; Review-Deadline 2026-07-25 | `docs/AUDIT_2026-05-25_TODO.md`, `docs/SERVICE_CATALOG.md` | | Filebrowser-Mounts | Bei zukuenftigem Hardening-Sprint Mount-Scope reduzieren | `docs/SERVICE_CATALOG.md` | @@ -95,7 +95,8 @@ Wartet auf ein externes Ereignis oder eine Abhaengigkeit. - Docker Critical Events Watcher auf Unraid aktiviert: Host-Clone auf Commit `2f3d184` aktualisiert, User Script `/boot/config/plugins/user.scripts/scripts/docker-critical-events-at-start/script` auf den Supervisor umgestellt, altes Script als `script.bak-20260605-232621` gesichert, `schedule.json` zeigt `frequency: start`, Watcher laeuft mit PID `1681168`. ntfy-Smoke am 2026-06-06 erfolgreich beim Operator angekommen. - Restore-Test AdGuard Home: automatisierter Test `ops/restore-tests/adguard-restore-test.sh` erstellt und am 2026-06-06 auf Unraid erfolgreich ausgefuehrt. Ergebnis: Borg-Config-Restore aus Archiv `Taegliche-Sicherung-2026-06-06T04:30:05.910`, isolierter Container `restoretest-adguard`, HTTP `/control/status` = `401`, DNS-Smoke `git.kaleschke.info -> 192.168.178.58`, 7 Filterlisten-Eintraege, Report `/mnt/user/backups/restore-reports/adguard-2026-06-06.md`. - Restore-Test Redis 8: automatisierter Test `ops/restore-tests/redis-restore-test.sh` erstellt und am 2026-06-06 auf Unraid erfolgreich ausgefuehrt. Ergebnis: Restore aus `/mnt/user/backups/borg/dumps/latest/shared-redis-pre-redis8-20260531-185011`, isolierter Container `restoretest-redis`, `PING` = `PONG`, Redis `8.8.0`, AOF `1`, `DBSIZE` = `1`, Report `/mnt/user/backups/restore-reports/redis-2026-06-06.md`. -- **Tailscale ACL-Policy restriktiv ausgerollt (2026-06-06):** Von Default-Allow auf Tag-basierte `grants`-Policy umgestellt, gemeinsam mit dem Operator in lockout-sicherer Reihenfolge (additiv -> taggen -> Allow-all entfernen), jeder Schritt read-only per SSH verifiziert. Live: `kallilabcore`=`tag:server`, `baerchen-1`+`iphone-14`=`tag:operator`, `tag:family` vorbereitet/schlafend. Subnet-Route `192.168.178.0/24` bleibt via `autoApprovers` approved. Smoke-Tests gruen (Operator-SSH, AdGuard-Admin `HTTP 302` ueber Tailnet, Ping 0%); untagged Nodes (`kallilab-core` Docker-Sidecar, alter `baerchen`) isoliert. Beleg: `docs/NETWORK_INVENTORY.md` Abschnitt "ACL-Policy — ANGEWENDET 2026-06-06". **Folgepunkt:** Befund nachgezogen, dass `kallilab-core` der **repo-verwaltete** Docker-Tailscale-Stack ist (nicht funktionslos) — Zwei-Instanzen-Klaerung als Operator-Entscheidung offen; nur der Offline-`baerchen`-Node ist trivialer Cleanup. Familien-Dienste konkretisieren bei erstem realem Familiengeraet. +- **Tailscale ACL-Policy restriktiv ausgerollt (2026-06-06):** Von Default-Allow auf Tag-basierte `grants`-Policy umgestellt, gemeinsam mit dem Operator in lockout-sicherer Reihenfolge (additiv -> taggen -> Allow-all entfernen), jeder Schritt read-only per SSH verifiziert. Live: `kallilabcore`=`tag:server`, `baerchen-1`+`iphone-14`=`tag:operator`, `tag:family` vorbereitet/schlafend. Subnet-Route `192.168.178.0/24` bleibt via `autoApprovers` approved. Smoke-Tests gruen (Operator-SSH, AdGuard-Admin `HTTP 302` ueber Tailnet, Ping 0%); untagged Nodes (`kallilab-core` Docker-Sidecar, alter `baerchen`) isoliert. Beleg: `docs/NETWORK_INVENTORY.md` Abschnitt "ACL-Policy — ANGEWENDET 2026-06-06". Familien-Dienste konkretisieren bei erstem realem Familiengeraet. +- **Redundanten Docker-Tailscale-Stack entfernt (2026-06-06):** Befund: Host hatte zwei `tailscaled` — die funktionale native Plugin-Instanz `kallilabcore` (echtes TUN `tailscale1`, Subnet-Router, State im Flash-Backup) und den redundanten userspace-only Docker-Stack `kallilab-core` (`host-services/tailscale/`, routet nichts, nichts haengt dran). Sauber per GitOps abgebaut: Operator hat Komodo-Stack `tailscale` gestoppt+destroyed; danach `git rm host-services/tailscale/`, Glance-Widget entfernt, Architektur-/Service-Catalog-/DR-Bootstrap-/CLAUDE-/Restore-Matrix-/Netzwerk-Doku auf "natives Plugin" nachgezogen. Read-only verifiziert: Container weg, nur noch der native `tailscaled`, Subnet-Route + Operator-Zugriff intakt. Rest: tote Node-Eintraege in der Admin-Konsole entfernen (eigener Todo). - DR-Workstation Bare-Metal-Kit abgeschlossen: WSL2 Ubuntu 24.04 auf `baerchen`, Borg 1.2.8, GitHub-Read-DR-Key und Hetzner-DR-Key in WSL, `~/dr-smoke.sh` vorhanden. Finaler Smoke 2026-06-06 erfolgreich: GitHub HEAD `3a263a4...`, Hetzner Storage Box Repos sichtbar, Borg-Repo `hetzner_borg_appdata_critical` gelesen, Repository ID `5dd9b949...`, encrypted `Yes (repokey)`, `DR-Smoke OK (2026-06-06 10:05:30)`. Passphrase wurde nur interaktiv eingegeben und nicht gespeichert. diff --git a/docs/NETWORK_INVENTORY.md b/docs/NETWORK_INVENTORY.md index 6d8c975..cf5f33f 100644 --- a/docs/NETWORK_INVENTORY.md +++ b/docs/NETWORK_INVENTORY.md @@ -55,7 +55,7 @@ Gemessen am 2026-06-05 per read-only SSH auf den Host (`tailscale status`, | Tailscale IPv6 | `fd7a:115c:a1e0::2c01:62b2` (gemessen 2026-06-05) | | Exit Node | **Nein.** `Self.ExitNodeOption: false` und `Self.ExitNode: false` — Host bietet keinen Exit Node an und nutzt keinen. Entspricht dem Ziel (Operator-Zugang ist eingehend, nicht als Internet-Ausgang). | | Subnet Router | **Ja, aktiv.** Host advertised und ist Primary fuer `192.168.178.0/24` (`Self.PrimaryRoutes: ["192.168.178.0/24"]`, ebenfalls in `AllowedIPs`). Das LAN ist also fuer das gesamte Tailnet ueber diesen Subnet-Router erreichbar — bewusst gemessener Ist-Zustand, **kein** "keine Route" wie zuvor vermutet. | -| ACL-Policy extern dokumentiert | **Operator-Entscheidung offen** — siehe eigener Block unten; durch den aktiven Subnet-Router ist die ACL-Frage sicherheitsrelevanter als zuvor angenommen. | +| ACL-Policy extern dokumentiert | **Angewendet 2026-06-06** — restriktive Tag-basierte `grants`-Policy live (`tag:server`/`tag:operator`, `tag:family` schlafend). Default-Allow entfernt, verifiziert. Details im Block unten. | ### Tailnet-Geraete (Snapshot 2026-06-05) @@ -65,13 +65,37 @@ Gemessen am 2026-06-05 per read-only SSH auf den Host (`tailscale status`, | `100.78.133.37` | baerchen-1 | windows | aktiv (aktuelle Operator-Workstation, direct) | | `100.105.203.21` | baerchen | windows | offline, zuletzt vor ~1 Tag gesehen (Alt-Node) | | `100.73.83.55` | iphone-14 | iOS | bekannt | -| `100.112.0.90` | kallilab-core | linux | gelistet, kein aktiver Verkehr — **moeglicher Alt-/Dubletten-Node**, separat pruefen | +| `100.112.0.90` | kallilab-core | linux | **am 2026-06-06 entfernt.** War der redundante userspace-only `Tailscale-Docker`-Stack (`host-services/tailscale/`). Komodo-Stack gestoppt+destroyed, Repo-Pfad per `git rm` entfernt, Container weg (read-only verifiziert). Node-Eintrag in der Admin-Konsole noch zu entfernen. | -> Hygiene-Hinweis (kein Secret): Es existieren zwei linux-Nodes mit aehnlichem -> Namen (`kallilabcore` und `kallilab-core`) sowie zwei `baerchen`-Nodes -> (`baerchen-1` aktiv, `baerchen` offline). Bei Gelegenheit in der -> Tailscale-Admin-Konsole pruefen, ob die inaktiven Eintraege stillgelegt werden -> koennen. Das ist Aufraeumarbeit, kein akutes Risiko. +> **Befund 2026-06-06 (read-only auf dem Host ermittelt):** Der Host hat **zwei** +> `tailscaled`-Prozesse: +> +> 1. **Native Unraid-Plugin** = `kallilabcore` (100.80.98.33). Prozess +> `/usr/local/sbin/tailscaled -statedir /boot/config/plugins/tailscale/state +> -tun tailscale1`. **Echtes TUN-Interface `tailscale1`, ist der Subnet-Router +> fuer `192.168.178.0/24`**, laeuft seit 24. Mai, installiert via +> `tailscale.plg` + `unraid-tailscale-utils`. State unter +> `/boot/config/plugins/tailscale/state` → ueber das **Flash-Backup** gesichert. +> Im ACL-Rollout `tag:server`. **Das ist die funktionale, kanonische Instanz.** +> 2. **Docker-Stack** = `kallilab-core` (100.112.0.90), `host-services/tailscale/`. +> Prozess `tailscaled --tun=userspace-networking` → **nur Userspace, kann +> technisch nicht routen / kein Subnet-Router/Exit-Node sein**, advertised +> nichts, kein Container teilt seinen Namespace, seit 31. Mai. State unter +> `/mnt/user/appdata/tailscale`. Im ACL-Rollout untagged → isoliert. +> **Hochwahrscheinlich redundant.** +> +> **Umgesetzt 2026-06-06:** Der redundante Docker-Stack `host-services/tailscale/` +> wurde sauber per GitOps abgebaut — Komodo-Stack `tailscale` gestoppt+destroyed +> (Operator), `git rm host-services/tailscale/`, Glance-Widget entfernt, und +> Architektur-/Service-Catalog-/DR-/CLAUDE-Doku auf "natives Plugin" nachgezogen. +> Read-only verifiziert: Container weg, nur noch der native `tailscaled` mit +> `tailscale1`, Subnet-Route + Operator-Zugriff intakt. Offen: Node-Eintraege +> `kallilab-core` und alter `baerchen` in der Admin-Konsole entfernen; State-Pfad +> `/mnt/user/appdata/tailscale` bei Gelegenheit nach `_archive/` (kein Sofort-Loeschen). +> +> **Doku-Korrektur erledigt:** `docs/RESTORE_MATRIX.md` zeigt jetzt auf den +> funktionalen State `/boot/config/plugins/tailscale/state` (im Flash-Backup) +> statt auf den entfernten userspace-Docker-Pfad. ### Subnet-Router-Konsequenz @@ -91,34 +115,22 @@ tailscale ip -4 tailscale ip -6 ``` -### ACL-Policy — Entwurf und Rollout-Plan (Stand 2026-06-05, NICHT angewendet) +### ACL-Policy — ANGEWENDET 2026-06-06 (restriktive Tag-basierte grants) -Die Tailnet-ACL wird in der Tailscale-Admin-Konsole unter `Access controls` -verwaltet (kein Wert/Secret gehoert ins Repo). Aktueller Live-Stand ist -Default-Allow (`src: ["*"] -> dst: ["*:*"]`), d. h. jedes Tailnet-Geraet darf -alles inklusive der LAN-Subnet-Route. +**Status: live und verifiziert.** Die restriktive Policy wurde am 2026-06-06 +gemeinsam mit dem Operator in der lockout-sicheren Reihenfolge ausgerollt und +read-only verifiziert (siehe "Rollout-Protokoll" unten). Ausgangspunkt war die +**unveraenderte Default-Policy** im **`grants`-Schema** (eine Allow-all-Regel, +keine Groups/Tags/`autoApprovers`); es gab also keinen eigenen Bestand zu +erhalten. -**Abgestimmte Richtung (Operator-Entscheidungen 2026-06-05):** +> **Schema-Hinweis:** Dieses Tailnet nutzt das `grants`-Modell +> (`{"src","dst","ip"}`), nicht das aeltere `acls`/`action:accept`-Modell. +> Normaler SSH-Zugriff (`ssh kallilabcore` ueber OpenSSH Port 22) wird ueber +> `grants` geregelt, nicht ueber den `ssh`-Block; letzterer betrifft nur die +> Tailscale-SSH-Funktion. -- Ziel ist eine restriktivere, Tag-basierte ACL. -- Single-User-Realitaet: aktuell gehoeren alle Nodes demselben User - `michaelkaleschke@`. Eine Differenzierung Operator/Familie ist nur ueber - **Tags** moeglich. Tagging aendert Ownership/Key-Expiry und erfordert je Geraet - Re-Auth — deshalb bewusst ein eigener, spaeterer Schritt. -- **Heute bewusst nur Sichtung + Entwurf, kein Tagging, keine Anwendung.** -- Familiengeraete brauchen Tailnet-Zugriff auf **bestimmte** Dienste (welche - genau, ist noch zu konkretisieren) — `tag:family` bekommt gezielte `dst`-Regeln. -- `iphone-14` ist ein Operator-Geraet und faellt unter `tag:operator`. - -**Geraete -> Tag (fuer den spaeteren Tagging-Schritt):** - -| Tag | Geraete | -|---|---| -| `tag:server` | `kallilabcore` (Host, Subnet-Router) | -| `tag:operator` | `baerchen-1`, `iphone-14` | -| `tag:family` | kuenftige Familiengeraete | - -**Entwurf (Vorschlag, noch nicht in der Konsole gespeichert):** +**Angewendete Policy (live, kein Secret):** ```json { @@ -130,42 +142,64 @@ alles inklusive der LAN-Subnet-Route. "autoApprovers": { "routes": { "192.168.178.0/24": ["tag:server"] } }, - "acls": [ - { "action": "accept", "src": ["tag:operator"], "dst": ["*:*"] }, - { "action": "accept", "src": ["tag:server"], "dst": ["tag:operator:*"] }, - { "action": "accept", "src": ["tag:family"], "dst": ["100.80.98.33:443"] } + "grants": [ + {"src": ["tag:operator"], "dst": ["*"], "ip": ["*"]}, + {"src": ["tag:server"], "dst": ["tag:operator"], "ip": ["*"]}, + {"src": ["tag:family"], "dst": ["tag:server"], "ip": ["tcp:443"]} ], "ssh": [ - { "action": "accept", "src": ["tag:operator"], "dst": ["tag:server"], - "users": ["root", "autogroup:nonroot"] } + {"action": "check", "src": ["autogroup:member"], "dst": ["autogroup:self"], + "users": ["autogroup:nonroot", "root"]} ] } ``` -> Die `tag:family`-`dst` `100.80.98.33:443` ist ein **Platzhalter** und wird -> durch die real benoetigten Familien-Dienste ersetzt, sobald diese feststehen. +**Geraete-Tags (live):** `kallilabcore` = `tag:server`; `baerchen-1` + `iphone-14` += `tag:operator`; `kallilab-core` (Docker) + alter `baerchen` bewusst untagged -> +isoliert. -**Lockout-sichere Reihenfolge (wenn die Umsetzung freigegeben wird):** +**Rollout-Protokoll 2026-06-06 (lockout-sicher, je Schritt read-only verifiziert):** -1. `tagOwners` + `autoApprovers` + neue ACL-Regeln speichern, **Allow-all-Regel - zunaechst behalten**. -2. Geraete taggen (`baerchen-1`, `iphone-14` -> operator; `kallilabcore` -> - server) und je Geraet die Verbindung verifizieren. -3. Subnet-Route bleibt approved (jetzt via `autoApprovers`/`tag:server`). -4. **Erst zuletzt** die Allow-all-Regel entfernen -> restriktiv schalten. -5. Sofort Smoke-Tests fahren (siehe unten). +1. Policy additiv erweitert (Tags/grants definiert, Allow-all noch drin) -> alle Peers unveraendert verbunden, Route approved. +2. `baerchen-1` getaggt `tag:operator` -> online, verifiziert. +3. `iphone-14` getaggt `tag:operator` -> verifiziert. +4. `kallilab-core` faktisch geprueft (Docker-Sidecar, keine Abhaengigen) -> bewusst untagged gelassen. +5. Host `kallilabcore` getaggt `tag:server` -> Route blieb via `autoApprovers` automatisch approved, SSH ok. +6. Allow-all entfernt -> restriktiv. Smoke-Tests gruen: Operator-SSH ok, AdGuard-Admin ueber Tailnet `HTTP 302`, Ping 0% Verlust, Route weiter approved; Host sieht nur noch die zwei Operator-Peers (untagged Nodes isoliert). LAN-Rueckweg durchgehend verfuegbar. -**Smoke-Tests nach Anwendung:** +**Schema-/Erhaltungs-Hinweis fuer spaeter:** Die LAN-Subnet-Route +`192.168.178.0/24` wird jetzt ueber `autoApprovers`/`tag:server` approved +(vorher manuell). Es gibt keinen eigenen Bestand zu erhalten; die Policy oben +ist die vollstaendige Wahrheit. -- `baerchen-1` erreicht Host: `ping 100.80.98.33`, `ssh kallilabcore hostname` (read-only). -- `baerchen-1` erreicht LAN ueber Route: z. B. AdGuard-Admin `http://100.80.98.33:8082`, `curl -kI https://192.168.178.58`. -- Falls testbar: ein nicht-Operator-Geraet erreicht Route/Admin-Ports **nicht** mehr. -- Host-Gegencheck: `tailscale status` zeigt alle Soll-Peers weiter verbunden. +**Hintergrund / Designentscheidungen (2026-06-05/06):** -**Noch offene Eingaben vor Finalisierung:** +- Single-User-Realitaet: alle Nodes gehoeren demselben User `michaelkaleschke@`. + Eine Differenzierung Operator/Familie ist nur ueber **Tags** moeglich, deshalb + der Tag-Ansatz statt user-/gruppenbasiert. +- Erster Rollout bewusst klein: nur `tag:server` + `tag:operator`. +- **`tag:family` ist vorbereitet, aber schlafend:** Tag und eine konservative + Minimal-Regel (`dst: tag:server`, `ip: tcp:443`) sind definiert, aber **kein + Geraet traegt den Tag**, daher null Wirkung. Sobald ein echtes Familiengeraet + dazukommt, wird es einmal mit `tag:family` getaggt und die Regel greift sofort + — ohne Policy-Umbau. Vor dem ersten realen Familiengeraet die Regel auf die + dann benoetigten Dienste/Ports pruefen. +- Der `ssh`-Block bleibt der Default (Tailscale-SSH Check-Modus); normaler + OpenSSH-Zugriff laeuft ueber die `grants` (Port 22, fuer `tag:operator` ueber + `ip: ["*"]` abgedeckt). -1. Aktueller ACL-JSON aus der Admin-Konsole (read-only gesichtet, nur Struktur dokumentiert). -2. Konkrete Liste der Dienste/Ports, die Familiengeraete ueber Tailscale brauchen. +**Offene Folgepunkte (kein Risiko, Hygiene/spaeter):** + +- Familien-Dienste/Ports konkretisieren — erst wenn ein reales Familiengeraet dazukommt. +- **Zwei-Tailscale-Konsolidierung: ERLEDIGT 2026-06-06** — redundanter Docker-Stack + abgebaut, nur noch die native Plugin-Instanz `kallilabcore` (Subnet-Router) aktiv. +- Tailnet-Konsole aufraeumen: Node-Eintraege `kallilab-core` (jetzt down) und + alter Offline-`baerchen` entfernen (trivial, nur tote Geraeteeintraege). +- State-Pfad `/mnt/user/appdata/tailscale` (vom entfernten Docker-Stack) bei + Gelegenheit nach `_archive/tailscale-removed-2026-06-06/` (kein Sofort-Loeschen). +- Optionaler Off-LAN-Routentest: von einem Operator-Geraet im Mobilfunk + (nicht im Heim-LAN) ein LAN-Ziel ueber `192.168.178.0/24` erreichen, um die + Subnet-Route end-to-end zu bestaetigen (im Heim-LAN nicht sauber isolierbar). ## Portfreigaben und Exposure diff --git a/docs/RESTORE_MATRIX.md b/docs/RESTORE_MATRIX.md index 622dda7..e82b01f 100644 --- a/docs/RESTORE_MATRIX.md +++ b/docs/RESTORE_MATRIX.md @@ -29,7 +29,7 @@ Sie ist die fachliche Ergaenzung zu `docs/DISASTER_RECOVERY.md`. | Unraid OS Flash | Borg-Artefakt + optional Unraid Connect | `/boot/config` aus `unraid-flash-config.tar.gz` | `unraid-flash-config.tar.gz`, `.sha256`, Manifest | enthaelt sensible Host-Konfiguration, wie Secret-Material behandeln | Unraid USB Flash Creator / neuer Boot-Stick | Unraid bootet, Array-Zuordnung und Shares sind sichtbar | | Traefik | Share / Borg | `/mnt/user/appdata/traefik`, besonders `dynamic/`, `letsencrypt`, `secrets` | keine eigene DB | `cloudflare_dns_api_token` | `frontend_net`, `backend_net` | `https://traefik.kaleschke.info` erreichbar, Dashboard ueber Authelia | | AdGuard Home | Share / Borg | `/mnt/user/appdata/adguard/conf` | keine | keine zusaetzlichen Repo-Secrets dokumentiert | `dns_net`, `frontend_net` | DNS-Aufloesung funktioniert; Restore-Smoke am 2026-06-06 erfolgreich | -| Tailscale | Share / Borg | `/mnt/user/appdata/tailscale` | keine | Tailscale-State im Pfad | Host-Netz | Tailscale verbunden | +| Tailscale | Flash-Backup (funktional) / Share | **Funktional: `/boot/config/plugins/tailscale/state`** (native Unraid-Plugin-Instanz `kallilabcore`, Subnet-Router, im Flash-Backup gesichert). Der frueher hier genannte Pfad `/mnt/user/appdata/tailscale` gehoert zum **userspace-only Docker-Stack** `kallilab-core` (redundant, Abbau geplant — siehe `docs/NETWORK_INVENTORY.md`) | keine | Tailscale-State im jeweiligen State-Pfad | Host-Netz | Tailscale verbunden, Subnet-Route `192.168.178.0/24` aktiv | | PostgreSQL 18 | Share + Dumps | `/mnt/user/appdata/postgresql18` (archivierter Rollback-Altstand: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/postgresql17`) | `postgresql17-globals.sql`, `postgresql17-mailarchiver.dump`, `postgresql17-paperless.dump`, optional `postgresql17-authelia.dump` | `postgres_password.txt`, App-Rollen-Passwoerter aus den jeweiligen Stack-ENV/Secret-Dateien | `backend_net` | DB startet, Ziel-Datenbanken vorhanden; `SHOW data_checksums` ist `on` | | Redis 8 | Share / Host | `/mnt/user/appdata/redis`; Rollback-Backup unter `/mnt/user/backups/borg/dumps/latest/shared-redis-pre-redis8-` | RDB/AOF-Dateien im Datenpfad | `redis_password.txt` | `backend_net` | Redis startet, `redis_version` ist 8.x, Apps verbinden sich; Restore-Smoke am 2026-06-06 erfolgreich | | Authelia | Borg | `/mnt/user/appdata/authelia/config`, `/mnt/user/appdata/secrets/*authelia*` | Shared PostgreSQL 18, optional Dump `postgresql17-authelia.dump` | JWT/Session/Storage/Postgres-/SMTP-Secret-Dateien | PostgreSQL 18, Traefik, GMX SMTP | Login-Seite und ForwardAuth funktionieren; SMTP-Notifier startet; aktive Sessions werden nach Restart neu aufgebaut; Restore-Smoke am 2026-06-03 erfolgreich: Config aus Borg, minimale Test-Config, frisches Test-Postgres, HTTP `/api/health` 200, Report `/mnt/user/backups/restore-reports/authelia-2026-06-03.md` | diff --git a/docs/SERVICE_CATALOG.md b/docs/SERVICE_CATALOG.md index 3d4aaee..e89cb8d 100644 --- a/docs/SERVICE_CATALOG.md +++ b/docs/SERVICE_CATALOG.md @@ -13,7 +13,7 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und | `traefik` | zentraler Reverse Proxy, TLS, Docker-Label-Routing | `traefik/docker-compose.yml`, `traefik/dynamic/*` | `https://traefik.kaleschke.info` | Docker socket, Cloudflare DNS API, `frontend_net`, `backend_net` | `/mnt/user/appdata/traefik/dynamic`, `/mnt/user/appdata/traefik/letsencrypt` | Tier 1, Share/Borg | ja, eigene Dashboard-Route mit Authelia | Host-Ports 80/443 sind zentrale Ausnahme; dynamic configs werden nicht automatisch von Komodo deployed | | `adguard` | DNS-Server / LAN DNS | `host-services/Adguard/docker-compose.yml` | LAN-Port `53`, Admin `100.80.98.33:8082` | `dns_net`, `frontend_net`, Unbound | `/mnt/user/appdata/adguard/conf`, `/mnt/user/appdata/adguard/work` | Tier 1, config relevant | nein | Direkter DNS-Port 53 bleibt; Admin-Port ist bewusst ohne Traefik/2FA, aber auf Tailscale-IP begrenzt (Operator-Entscheidung 2026-05-26) | | `unbound` | Upstream DNS Resolver fuer AdGuard | `apps/unbound/docker-compose.yml` | intern | `dns_net` | `/mnt/user/appdata/unbound/config` | rebuildbar / config relevant | nein | intern isoliert | -| `tailscale` | VPN/Remote-Zugang | `host-services/tailscale/docker-compose.yml` | Tailscale | Host-Netz | `/mnt/user/appdata/tailscale` | Tier 1, State relevant | nein | `network_mode: host`, `NET_ADMIN`, `NET_RAW` und `/dev/net/tun` sind dokumentierte VPN-Ausnahmen | +| `tailscale` | VPN/Remote-Zugang, Subnet-Router | **Natives Unraid-Plugin** `tailscale.plg` (nicht repo-/Komodo-verwaltet) | Tailscale | Host-Netz (`tailscale1`) | `/boot/config/plugins/tailscale/state` (im Flash-Backup) | Tier 1, State relevant | nein | Subnet-Router `192.168.178.0/24`; redundanter Docker-Stack `host-services/tailscale/` am 2026-06-06 entfernt | | `gitea` | Git-Server / origin fuer GitOps | `core/gitea/docker-compose.yml` | `https://git.kaleschke.info`, SSH `222` | Traefik, `frontend_net`, externe DNS-Resolver fuer GitHub-Push-Mirror | `/mnt/user/services/gitea/data` | Tier 1, `gitea.sqlite.dump` + Share; privater GitHub-Push-Mirror fuer Repo-Bootstrap | ja | SSH-Port 222 direkte Host-Port-Ausnahme; Push-Mirror nach `michaelkaleschke-spec/homelab-infra` reduziert das DR-Bootstrap-Risiko | ## Security / Identity diff --git a/host-services/tailscale/docker-compose.yml b/host-services/tailscale/docker-compose.yml deleted file mode 100644 index 296073c..0000000 --- a/host-services/tailscale/docker-compose.yml +++ /dev/null @@ -1,25 +0,0 @@ -services: - tailscale: - image: tailscale/tailscale:stable@sha256:25cde9ad76020b0e29229136d0c38b5962e9a0e1774ffac9b0df68e4a37d6cf0 - container_name: Tailscale-Docker - restart: unless-stopped - network_mode: host - - cap_add: - - NET_ADMIN - - NET_RAW - - security_opt: - - no-new-privileges:true - - devices: - - /dev/net/tun:/dev/net/tun - - environment: - - TZ=Europe/Berlin - - TS_HOSTNAME=kallilab-core - - TS_STATE_DIR=/state - - TS_AUTH_ONCE=true - - volumes: - - /mnt/user/appdata/tailscale:/state diff --git a/ops/glance/config/glance.yml b/ops/glance/config/glance.yml index d3c2ae5..bd53b0c 100644 --- a/ops/glance/config/glance.yml +++ b/ops/glance/config/glance.yml @@ -497,12 +497,6 @@ pages: description: Upstream Resolver category: network hide: false - Tailscale-Docker: - name: Tailscale - icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/tailscale.svg - description: VPN - category: network - hide: false ddns-updater: name: DDNS Updater icon: mdi:cloud-sync