# Network Inventory - KalliLab CORE Status: Host-Audit erfasst; Router-Baseline und Portfreigaben-UI bereinigt; FRITZ!Box-Remote-Dienste aus; IPv6-Exposure technisch und per UI entschaerft; Tailscale-Inventar am 2026-06-05 real gemessen. Letzte Pruefung: 2026-06-05 (Tailscale-Inventar), 2026-06-01 (Router/Ports) ## Zweck Dieses Dokument beschreibt Router, DNS, Tailscale, Portfreigaben und Netztrennung. Es ergaenzt das Architektur-Zielbild in `HOMELAB_ARCHITECTURE_MASTER_V2.md` um konkrete Hardware- und Betriebswerte. ## Internet und Router | Feld | Wert | |---|---| | Anschluss / Provider | DSL, Telekom | | Bandbreite (FRITZ!Box-UI) | ca. 87,3 Mbit/s Download, ca. 36 Mbit/s Upload | | Router-Modell | FRITZ!Box 7590 | | Firmware | FRITZ!OS 8.25 (`154.08.25` per TR-064 am 2026-06-01) | | Router-IP | 192.168.178.1 | | DHCP-Server | FRITZ!Box (Standardannahme, Override durch Operator nicht dokumentiert) | | Lokales Subnetz | 192.168.178.0/24 | | IPv6 aktiv | Windows-Client hat Provider-IPv6; Host hat keine globale Provider-IPv6, nur Tailscale-ULA | | DynDNS / DDNS | Cloudflare via `ddns-updater` (kein FRITZ!Box-DynDNS in Nutzung) | | Heimnetz-Geraete (FRITZ!Box-UI) | 35 aktive Geraete | | LAN-Ports belegt | LAN 1-4 verbunden | | Telefonie / DECT | aktiv | | USB an FRITZ!Box | nicht verbunden | | Ausfallschutz (FRITZ!Box) | nicht eingerichtet (Mobilfunk-Stick-Failover nicht aktiv) | ### Beobachtungen - Telekom-DSL ist Single-WAN; ohne Ausfallschutz ist Internet-Ausfall = kein DDNS-Update, keine ACME-Erneuerung, keine externen Push-Quellen. - Upload 36 Mbit/s ist die effektive Obergrenze fuer Off-site-Backup-Geschwindigkeit nach Hetzner und fuer Plex-Remote-Streaming. - FRITZ!OS ist am 2026-06-01 per TR-064 auf `154.08.25` beobachtet; FRITZ!Box-Konfig-Backup `Einstellungen_FRITZ.Box_7590_154.08.25_01.06.26_1318.export` wurde extern/off-system in Vaultwarden abgelegt. - `Internet -> Freigaben -> FRITZ!Box-Dienste` ist am 2026-06-01 geprueft: Internetzugriff auf die FRITZ!Box per HTTPS ist aus, FTP/FTPS-Zugriff auf Speichermedien ist aus. ## DNS | Komponente | Rolle | Adresse | Bemerkung | |---|---|---|---| | AdGuard Home | LAN DNS / Filter | Host `192.168.178.58`, Docker `172.23.0.3` | DNS auf Port 53; Admin soll nur via Tailscale-IP `100.80.98.33:8082` erreichbar sein | | Unbound | Rekursiver Resolver | Docker `dns_net` | Upstream fuer AdGuard | | Cloudflare | Authoritative DNS | extern | DNS-Challenge fuer TLS | | Router | DHCP DNS-Verteilung | TBD | Muss auf AdGuard zeigen, falls so betrieben | ## Tailscale Gemessen am 2026-06-05 per read-only SSH auf den Host (`tailscale status`, `tailscale status --json`, `tailscale ip -4/-6`). | Feld | Wert / Status | |---|---| | Node-Name | Kallilabcore | | Tailnet / MagicDNS | `taild9fcf2.ts.net`; DNSName `kallilabcore.taild9fcf2.ts.net` | | Tailscale IPv4 | `100.80.98.33` | | 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 | **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) | Tailscale-IP | Node | OS | Status | |---|---|---|---| | `100.80.98.33` | kallilabcore | linux | aktiv (Host, Subnet-Router) | | `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 | **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. | > **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 Weil `Kallilabcore` das LAN `192.168.178.0/24` als Subnet-Route anbietet, kann **jedes** Tailnet-Geraet mit Zugriff auf diese Route potenziell LAN-Dienste auf `192.168.178.0/24` erreichen — auch die Admin-Ports, die im LAN bewusst nur auf die Tailscale-IP gebunden sind, sind ueber die Subnet-Route adressierbar. Genau deshalb ist die ACL-Policy (unten) der eigentliche Schutzmechanismus und nicht nur der LAN-Bind. Pruefkommando (auf dem Unraid-Host, read-only): ```bash tailscale status tailscale status --json | jq '{exitNode: .Self.ExitNodeOption, primaryRoutes: .Self.PrimaryRoutes, allowedIPs: .Self.AllowedIPs}' tailscale ip -4 tailscale ip -6 ``` ### ACL-Policy — ANGEWENDET 2026-06-06 (restriktive Tag-basierte grants) **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. > **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. **Angewendete Policy (live, kein Secret):** ```json { "tagOwners": { "tag:server": ["autogroup:admin"], "tag:operator": ["autogroup:admin"], "tag:family": ["autogroup:admin"] }, "autoApprovers": { "routes": { "192.168.178.0/24": ["tag:server"] } }, "grants": [ {"src": ["tag:operator"], "dst": ["*"], "ip": ["*"]}, {"src": ["tag:server"], "dst": ["tag:operator"], "ip": ["*"]}, {"src": ["tag:family"], "dst": ["tag:server"], "ip": ["tcp:443"]} ], "ssh": [ {"action": "check", "src": ["autogroup:member"], "dst": ["autogroup:self"], "users": ["autogroup:nonroot", "root"]} ] } ``` **Geraete-Tags (live):** `kallilabcore` = `tag:server`; `baerchen-1` + `iphone-14` = `tag:operator`; `kallilab-core` (Docker) + alter `baerchen` bewusst untagged -> isoliert. **Rollout-Protokoll 2026-06-06 (lockout-sicher, je Schritt read-only verifiziert):** 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. **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. **Hintergrund / Designentscheidungen (2026-06-05/06):** - 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). **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 ### FRITZ!Box (WAN -> Host) Aktiver Soll-Stand nach Operator-Bereinigung und UI-Gegencheck 2026-06-01: | Aktive Freigabe | Ziel | Zweck | Bemerkung | |---|---|---|---| | `443/tcp` -> `192.168.178.58:443` | Traefik HTTPS | einziger Public-HTTPS-Einstieg, Wildcard-Cert via Cloudflare-DNS-Challenge | bleibt | Bewusst **nicht** freigegeben: | Port | Begruendung | |---|---| | `80/tcp` | Cloudflare-DNS-Challenge ersetzt HTTP-01; Traefik macht HTTP->HTTPS-Redirect nur LAN-seitig; WAN-`80` waere zusaetzliche Angriffsflaeche ohne Funktionsnutzen. **2026-05-28 in FRITZ!Box-UI entfernt**, Validierung: Mobilfunk-Test ergibt Timeout auf `http://vault.kaleschke.info`, `https://...` weiter erreichbar. | | `222/tcp` (Gitea SSH) | bewusst Tailscale-only: Operator-Pfad ist Tailscale, GitHub-Mirror deckt DR-Bootstrap ab, Gitea-Bundles sind off-host. Externe SSH-Brute-Force-Vektoren vermeiden. | ### UPnP / Selbstständige Portfreigaben | Geraet | UPnP-Selbstfreigabe-Recht | Begruendung | |---|---|---| | `Kallilabcore` (192.168.178.58) | nicht erlaubt | Repo-managed; alle benoetigten Public-Ports sind explizite Freigaben | | `PC-192-168-178-71` / VONETS-Adapter (192.168.178.71, MAC 00:17:13:2F:61:96) | **2026-06-01 erneut geprueft und deaktiviert** | wahrscheinlich VONETS-WiFi-Bridge fuer SolarEdge-Wechselrichter; SolarEdge-Cloud-Sync ist ausschliesslich outbound, eingehende Ports sind nicht erforderlich | Sollten neue Geraete UPnP-Selbstfreigaben anfordern, wird das hier als bewusste Ausnahme dokumentiert oder pro Geraet wieder deaktiviert. Historischer UI-Befund vor Bereinigung vom 2026-05-27 (`Internet -> Freigaben -> Kallilabcore`): | Beobachtung | Bewertung | |---|---| | `HTTP-Server`, TCP, extern `80/tcp` auf `192.168.178.58` | war Abweichung; **2026-05-28 entfernt** | | `HTTPS-Server`, TCP, extern `443/tcp` auf `192.168.178.58` | entspricht Repo-Soll | | Keine `222/tcp`-Freigabe sichtbar | entspricht seit 2026-05-28 dem Soll: Gitea-SSH bleibt Tailscale-only | | Kallilabcore: keine selbststaendige Portfreigabe, kein IPv4-/IPv6-Exposed-Host sichtbar | entspricht Sicherheitsziel | | `PC-192-168-178-71`: selbststaendige Portfreigabe erlaubt, `0 aktiv` | **2026-06-01 deaktiviert**; danach nur noch `Kallilabcore` in der Portfreigabenliste sichtbar | ### Host (lokal beobachtbar) | Port | Ziel | Zweck | Bewertung | |---:|---|---|---| | 80/tcp | Traefik | HTTP->HTTPS / ACME | nur LAN, keine WAN-Freigabe noetig | | 443/tcp | Traefik | HTTPS | WAN-Freigabe in FRITZ!Box erwartet | | 222/tcp | Gitea SSH | Git SSH | nur LAN/Tailscale; keine WAN-Freigabe | | 53/tcp+udp | AdGuard | DNS | LAN-only, dokumentierte Ausnahme | | 8082/tcp | AdGuard Admin | Admin UI | Bind nur `100.80.98.33:8082` (Tailscale), nicht im LAN exponiert | | 8181/tcp | InfluxDB 3 Core | Home Assistant / Ecowitt Writer | 2026-05-31 effektiv nur `127.0.0.1:8181`, nicht LAN-exponiert | Pruefkommando: ```bash ss -ltnp | sort -k4 docker ps --format "{{.Names}}: {{.Ports}}" | sort ``` ## Netztrennung | Netz | Status | Bemerkung | |---|---|---| | LAN | 192.168.178.0/24 | Hauptnetz, Host `192.168.178.58`, FRITZ!Box meldet 35 aktive Geraete | | WLAN 2,4 / 5 GHz | aktiv, SSID `Fritzi` | Standard-WLAN, im LAN-Adressbereich, kein eigener Adressraum | | Gast-WLAN | **inaktiv** (FRITZ!Box-UI) | Solange inaktiv: kein Gast-Pfad zu LAN-Diensten; AdGuard-Admin-Trennung primaer ueber Tailscale-Bind statt Netzsegmentierung | | IoT-Netz | nicht existent | Keine VLAN-Trennung dokumentiert | | Tailscale | aktiv | Operator-Zugang, Host-IP `100.80.98.33` | | VLANs | nicht in Nutzung | FRITZ!Box 7590 kann VLAN-Tagging an einzelnen LAN-Ports; aktuell nicht konfiguriert | ## Docker-Netze Authoritativ ist `HOMELAB_ARCHITECTURE_MASTER_V2.md`. Dieses Inventar haelt nur den Laufzeit-Snapshot fest. | Docker-Netz | Zweck | Erwartung | |---|---|---| | frontend_net | Traefik/Web | external bridge | | backend_net | DB/Cache intern | internal bridge | | dns_net | AdGuard/Unbound | bridge | | monitoring_net | Observability | compose-intern | | app-interne Netze | Stack-isoliert | nur wenn technisch noetig | Pruefkommando: ```bash docker network ls docker network inspect frontend_net | jq '.[0].Containers | keys' docker network inspect backend_net | jq '.[0].Internal' ``` ## Offene Entscheidungen | Thema | Status | Naechster Schritt | |---|---|---| | AdGuard Admin nur via Tailscale | live validiert 2026-05-26 | Compose bindet Admin-Port auf `100.80.98.33:8082`; DNS auf Port 53 funktioniert, LAN-Zugriff auf `192.168.178.58:8082` schlaegt fehl | | FRITZ!Box-Portfreigaben mit Repo-Soll abgleichen | **erledigt 2026-06-01** | Bereinigt: `80/tcp` entfernt (Cloudflare-DNS-Challenge ersetzt HTTP-01; Mobilfunk-Test bestaetigt Timeout auf `http://`, `https://` weiter ok). `222/tcp` bleibt bewusst nicht eingerichtet (Tailscale-only-Linie). UPnP-Selbstfreigaben sind aus. Aktiver Soll-Stand: ausschliesslich `443/tcp -> 192.168.178.58`. | | FRITZ!Box-Dienste aus dem Internet | **erledigt 2026-06-01** | `Internet -> Freigaben -> FRITZ!Box-Dienste`: HTTPS-Zugriff auf die FRITZ!Box aus dem Internet aus; FTP/FTPS auf Speichermedien aus. | | FRITZ!OS Update und Konfig-Backup | **erledigt 2026-06-01** | TR-064 meldet `154.08.25`; Konfig-Export liegt extern/off-system in Vaultwarden, Kennwort und Datei bleiben ausserhalb des Repos. | | Gast-/IoT-Zugriff auf Admin-Ports | **validiert 2026-06-06** | Runbook `docs/GUEST_IOT_NETWORK.md` und Checks `ops/maintenance/check-guest-iot-isolation.ps1` sowie `ops/maintenance/check-guest-iot-preflight.sh` vorhanden. LAN-Preflight von `baerchen` gruen: `192.168.178.58:8082` und `:8181` blockiert. Host-Preflight auf Unraid gruen, Report `/mnt/user/backups/restore-reports/guest-iot-preflight-2026-06-06-131316.md`. Gast-WLAN-Smoke per iPhone: `192.168.178.58:8082`, `:8181`, `:222`, `https://192.168.178.58` und `192.168.178.1` nicht erreichbar. | | IPv6 Exposure | technisch und per UI entschaerft | Public DNS liefert keine AAAA-Records fuer `*.kaleschke.info`; Host hat keine globale Provider-IPv6. TR-064 meldet IPv6-Firewall aktiv und Pinholes grundsaetzlich erlaubt; FRITZ!Box-UI zeigt keine aktiven IPv6-Freigaben, keine Admin-/SSH-Freigaben. | | WAN-Ausfallschutz | **geparkt: spaeter evaluieren** (Operator-Entscheidung 2026-06-05) | Mobilfunk-Stick-Failover an FRITZ!Box bleibt vorerst inaktiv. Folgen sind bewusst akzeptiert: Internet-Ausfall = ACME/DDNS pausieren, lokale Apps laufen weiter. Review-Trigger: haeufigere oder laengere DSL-Ausfaelle, oder wenn externer Remote-Zugang (statt nur lokalem Betrieb) geschaeftskritisch wird. Erst dann Mobilfunk-Failover technisch bewerten. | | Home Assistant InfluxDB Bind | validiert 2026-05-31 | `docker-proxy` bindet `127.0.0.1:8181`; keine LAN-Exposure. Wenn Home Assistant nicht lokal auf dem Host schreibt, braucht das eine bewusste Bind-Aenderung. |