From de7b714b4d36fcf73ee0c4f74f6f90b6b708cfa8 Mon Sep 17 00:00:00 2001 From: Micha Date: Sun, 7 Jun 2026 11:02:07 +0200 Subject: [PATCH] docs(network): SSH-Host-Haertung dokumentieren (key-only root, upgrade-sichere Persistenz) Host gehaertet 2026-06-07: PermitRootLogin prohibit-password, PasswordAuthentication no, KbdInteractiveAuthentication no; PubkeyAuthentication yes. Persistenz upgrade-sicher via idempotentem /boot/config/ssh-harden.sh aus /boot/config/go (sshd -t vor HUP-Reload, Syslog-Selbst-Verifikation). Manueller Post-Upgrade-Check und Rollback dokumentiert. Co-Authored-By: Claude Opus 4.8 --- docs/NETWORK_INVENTORY.md | 77 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/docs/NETWORK_INVENTORY.md b/docs/NETWORK_INVENTORY.md index 3ba2a6c..4f32805 100644 --- a/docs/NETWORK_INVENTORY.md +++ b/docs/NETWORK_INVENTORY.md @@ -193,8 +193,8 @@ ist die vollstaendige Wahrheit. - 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). +- **Tailnet-Konsole aufraeumen: ERLEDIGT 2026-06-06** — Node-Eintraege `kallilab-core` + und alter Offline-`baerchen` aus der Admin-Konsole entfernt. - 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 @@ -288,6 +288,78 @@ docker network inspect frontend_net | jq '.[0].Containers | keys' docker network inspect backend_net | jq '.[0].Internal' ``` +## SSH-Konfiguration Host + +Geprueft 2026-06-06 (read-only), **gehaertet 2026-06-07** via `ssh root@192.168.178.58`. + +| Parameter | Ist-Wert (effektiv via `sshd -T`, Stand 2026-06-07) | Soll | Status | +|---|---|---|---| +| `Port` | `22` | 22 | ok | +| `PermitRootLogin` | `prohibit-password` | `prohibit-password` | **gehaertet 2026-06-07** | +| `PasswordAuthentication` | `no` | `no` | **gehaertet 2026-06-07** | +| `KbdInteractiveAuthentication` | `no` | `no` | **gehaertet 2026-06-07** (noetig wegen `UsePAM yes`) | +| `PubkeyAuthentication` | `yes` | `yes` | ok | +| `PermitEmptyPasswords` | `no` | `no` | ok | +| `AuthorizedKeysFile` | `.ssh/authorized_keys` | `.ssh/authorized_keys` | ok | + +**Hinterlegte SSH-Keys (root):** 3 Keys vorhanden (persistiert unter `/boot/config/ssh/root/authorized_keys`): +- `root@Kallilabcore` (Host-eigener Key) +- `michi@Baerchen` (Operator-Workstation) +- `hetzner-storagebox-maintenance-2026-06-01` (Hetzner-Maintenance-Key) + +**Durchgefuehrte Haertung (2026-06-07):** Root-Login ist jetzt key-only, +Passwort- und Keyboard-Interactive-Auth sind serverseitig abgeschaltet. +Verifiziert: frischer Key-Login `OK`; `ssh -o PreferredAuthentications=none` +meldet `Authentications that can continue: publickey`; reiner Passwort-Versuch +`Permission denied (publickey)`. + +**Wichtig — Unraid-Persistenz:** `/etc/ssh/sshd_config` wird beim Boot aus dem +OS-Image regeneriert (`rc.sshd`: `cp -f /boot/config/ssh/* /etc/ssh/`, danach +`sshd_build`, das nur `Port`/`ListenAddress`/`AddressFamily` setzt). Die +Unraid-GUI (**Settings → Management Access → SSH**) bietet nur `Use SSH`/`SSH port` +an — **`PermitRootLogin`/`PasswordAuthentication` sind dort nicht einstellbar.** +Persistiert wird daher **upgrade-sicher** ueber einen idempotenten Hook: + +- `/boot/config/ssh-harden.sh` — setzt die drei Direktiven idempotent (bestehende + aktive Zeile entfernen, genau einmal global vor dem ersten `Match`-Block einfuegen), + `sshd -t`-Validierung, Reload nur per `kill -HUP` des Host-`sshd` bei valider Config. + Idempotenz belegt: nach mehreren Laeufen je Direktive exakt 1 aktive Zeile, alte + `PermitRootLogin yes` entfernt. +- `/boot/config/go` — ruft `/bin/bash /boot/config/ssh-harden.sh` bei jedem Boot auf. + +**Selbst-Verifikation (Syslog, rein informativ, keine Reparatur):** Das Skript +schreibt nach jedem Lauf die effektiven Auth-Werte (`sshd -T`) nach syslog, z. B. +`ssh-harden: VERIFY permitrootlogin prohibit-password pubkeyauthentication yes +passwordauthentication no kbdinteractiveauthentication no`. Damit ist nach jedem +Boot/Upgrade nachweisbar, ob die Haertung gegriffen hat. + +**Post-Upgrade-/Reboot-Check** (manuell, einmal nach jedem Unraid-Upgrade): + +```bash +# A) Effektive Werte direkt abfragen (Soll: prohibit-password / no / no / yes) +ssh root@192.168.178.58 "sshd -T | grep -Ei 'permitroot|passwordauth|kbdinteractive|pubkey'" +# B) Oder die automatische VERIFY-Zeile im Syslog lesen (Unraid nutzt rsyslog -> /var/log/syslog, nicht logread) +ssh root@192.168.178.58 "grep 'ssh-harden' /var/log/syslog | tail -3" +``` + +Dieser Weg editiert die **jeweils aktuelle** von Unraid generierte Config nach und +ueberlebt damit Unraid-Upgrades; findet er die Stock-Zeile nicht (z. B. weil eine +neue Version schon `prohibit-password` ausliefert), macht der `sed` nichts und +bricht den Boot nicht (fail-safe Richtung offen, nicht ausgesperrt). Bewusst +**nicht** der oft empfohlene Weg einer kompletten `/boot/config/ssh/sshd_config` +auf Flash — der wuerde die Stock-Config einfrieren und beim Upgrade neue Defaults +verschlucken. + +**Rollback:** `go`-Block + `/boot/config/ssh-harden.sh` entfernen, dann +`cp /boot/config/ssh-harden.sshd_config.bak-20260607 /etc/ssh/sshd_config` und +`kill -HUP $(cat /var/run/sshd.pid)`. Notzugang ueber Unraid-Konsole/GUI bleibt. + +**Abgrenzung:** Ein zweiter `sshd` (`-D -e`) laeuft in einem Docker-Container +(s6-overlay, moby-Namespace) und bindet **nicht** den Host-`:22`; eigene Config +im Container, von dieser Haertung unberuehrt. + +--- + ## Offene Entscheidungen | Thema | Status | Naechster Schritt | @@ -300,3 +372,4 @@ docker network inspect backend_net | jq '.[0].Internal' | 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. | +| SSH-Haertung Host | **erledigt 2026-06-07** | Root-Login key-only: `PermitRootLogin prohibit-password`, `PasswordAuthentication no`, `KbdInteractiveAuthentication no`. Live gesetzt + verifiziert (Key-Login ok, Passwort-Auth abgelehnt). Persistenz upgrade-sicher ueber `/boot/config/ssh-harden.sh` (idempotent, `sshd -t` vor Reload) aufgerufen aus `/boot/config/go`. GUI bietet diese Optionen nicht. Details im Abschnitt „SSH-Konfiguration Host". |