Prepare external operator checks

This commit is contained in:
2026-06-01 12:48:00 +02:00
parent 479eb291c4
commit ae5d4aedfc
7 changed files with 234 additions and 14 deletions
+3 -2
View File
@@ -48,8 +48,8 @@ Authoritativ: `docs/AUDIT_2026-05-25_TODO.md`.
Kurzfassung:
- Alt-Volumes fruehestens ab 2026-06-02 freigeben
- Hetzner-Account-Hygiene und Borg `append-only` pruefen
- FRITZ!Box-Servicefenster fuer Update, Config-Backup und IPv6-Exposure planen
- Hetzner-Account-Hygiene und Borg `append-only` mit `docs/EXTERNAL_OPERATOR_RUNBOOK.md` im Account/Storage-Box-SSH-Setup bestaetigen
- FRITZ!Box-Konfig-Backup und UI-Gegencheck fuer IPv6-Portfreigaben/Selbstfreigaben erledigen
- Auth-/OIDC-/CrowdSec-/Hermes-Themen bewusst geparkt
Letzte Bestaetigung:
@@ -58,3 +58,4 @@ Letzte Bestaetigung:
- H:/ Nearline-Pull 2026-06-01 repariert: Borg-Dumps werden kuratiert kopiert, Gitea-Bundles aktuell.
- Family-Status-Dashboard liegt als `monitoring/grafana/dashboards/family-status.json` im Repo.
- Alt-Volume-Freigabe ist per `ops/maintenance/release-alt-volumes.sh` vorbereitet; `--execute` nicht vor 2026-06-02.
- Externer Betreibercheck: `ops/maintenance/check-external-operator.sh`; FRITZ!Box 7590 meldet FRITZ!OS `154.08.25`, DNS fuer Public Apps hat keine AAAA-Records, Host hat keine globale Provider-IPv6.
+4 -3
View File
@@ -8,9 +8,9 @@ Audit-Snapshots wurden aus der Arbeitskopie entfernt; Detailhistorie liegt in Gi
| Prioritaet | Punkt | Naechster Schritt |
|---|---|---|
| P0 | Alt-Volumes nach Burn-in freigeben | Ab 2026-06-02 `ops/maintenance/release-alt-volumes.sh --dry-run` pruefen, danach nur bei sauberem Ergebnis mit `--execute` freigeben |
| P1 | Hetzner-Account-Hygiene | Starkes einzigartiges Passwort, Backup-Zahlungsweg und Login-Benachrichtigungen extern bestaetigen |
| P1 | Borg `--append-only` fuer Hetzner pruefen | Rollback-faehigen Test fuer `borg serve --append-only` in Hetzner `authorized_keys` planen |
| P1 | FRITZ!Box-Servicefenster | FRITZ!OS-Update, FRITZ!Box-Konfig-Backup und IPv6-Exposure-Pruefung gemeinsam erledigen |
| P1 | Hetzner-Account-Hygiene | Mit `docs/EXTERNAL_OPERATOR_RUNBOOK.md` im Hetzner-Konto bestaetigen; keine Secret-Werte ins Repo |
| P1 | Borg `--append-only` fuer Hetzner pruefen | Produktiven Borg-UI-SSH-Key in der Storage-Box-`authorized_keys` per forced command auf `borg serve --append-only` einschraenken; separaten Maintenance-Key offline halten |
| P1 | FRITZ!Box-Servicefenster | FRITZ!Box-Konfig-Backup und UI-Gegencheck fuer IPv6-Portfreigaben/Selbstfreigaben; FRITZ!OS `154.08.25` ist technisch bereits beobachtet |
| P2 | Family-Onboarding praktisch starten | Familienkonten, Vaultwarden-Organisation und Immich-Mobile-Backup gemeinsam einrichten |
## Bewusst geparkt
@@ -27,6 +27,7 @@ Audit-Snapshots wurden aus der Arbeitskopie entfernt; Detailhistorie liegt in Gi
## Zuletzt geschlossen
- Externer Betreibercheck vorbereitet: `docs/EXTERNAL_OPERATOR_RUNBOOK.md` und `ops/maintenance/check-external-operator.sh`; Live-Baseline am 2026-06-01: FRITZ!OS `154.08.25`, keine Public-AAAA-Records fuer `*.kaleschke.info`, Host ohne globale Provider-IPv6, WAN `443/tcp` offen und `80/tcp`/`222/tcp` geschlossen.
- Family-View Dashboard ist repo-seitig gebaut: `monitoring/grafana/dashboards/family-status.json` zeigt Family-App-Uptime, Backup-Alter, TLS-Restlaufzeit, Critical-Container und Image-Drift.
- Alt-Volume-Freigabe ist vorbereitet: `ops/maintenance/release-alt-volumes.sh --dry-run` validiert aktive Pfade, Container-Health, Restore-Freshness und gemountete Altpfade; Test am 2026-06-01 fand vier Kandidaten und keine Blocker, Ausfuehrung bleibt wegen Cutoff bis 2026-06-02 gesperrt.
- Borg-Nachlauf nach dem 2026-05-31-Sprint ist belegt: Archiv `Taegliche-Sicherung-2026-06-01T04:30:26.913`, 101669 Dateien, `rc=0`; Freshness-Check am 2026-06-01: Critical 0, Warnings 0.
+2 -1
View File
@@ -1,6 +1,6 @@
# External Dependencies - KalliLab CORE
Status: Initiale Betreiber-Baseline 2026-05-26; konkrete Account-Recovery-Codes und Besitznachweise muessen ausserhalb des Repos bestaetigt werden.
Status: Betreiber-Baseline 2026-06-01; konkrete Account-Recovery-Codes und Besitznachweise muessen ausserhalb des Repos bestaetigt werden.
## Zweck
@@ -78,3 +78,4 @@ Authoritativ ist `docs/SECRETS_MAP.md`. Diese Liste markiert nur externe Abhaeng
| 2026-05-26 | Bekannte externe Abhaengigkeiten aus Repo-/Betriebsdoku dokumentiert; keine Secret-Werte aufgenommen. Borg-Passphrase ist laut Operator offline gesichert. | Account-Besitz, 2FA-Recovery-Codes und Zahlungswege extern bestaetigen |
| 2026-05-26 | Telekom-DSL und FRITZ!Box 7590 (FRITZ!OS 8.21) als WAN-/Router-Abhaengigkeit aufgenommen; Ausfallschutz nicht eingerichtet | FRITZ!OS-Update im Service-Fenster pruefen |
| 2026-05-28 | FRITZ!Box-Portfreigaben bereinigt: aktiv bleibt nur `443/tcp`; `80/tcp` entfernt, `222/tcp` bewusst nicht angelegt; UPnP-Recht fuer VONETS-Bridge deaktiviert | IPv6-Exposure bei naechstem WAN-/Router-Review pruefen |
| 2026-06-01 | Externer Betreibercheck vorbereitet: `docs/EXTERNAL_OPERATOR_RUNBOOK.md` und `ops/maintenance/check-external-operator.sh`; FRITZ!Box meldet per TR-064 FRITZ!OS `154.08.25`, Public DNS hat keine AAAA-Records, Host hat keine globale Provider-IPv6 | Hetzner Account-Hygiene und Borg append-only im Konto/Storage-Box-SSH-Key-Setup bestaetigen |
+125
View File
@@ -0,0 +1,125 @@
# External Operator Runbook
Stand: 2026-06-01
Dieses Runbook schliesst die Betreiber-Aufgaben, die nicht vollstaendig aus dem
Repo automatisierbar sind: Hetzner-Account-Hygiene, Borg-Append-Only und
FRITZ!Box-Servicefenster. Keine Secret-Werte ins Repo schreiben.
## 1. Vorher pruefen
Auf dem Unraid-Host:
```bash
bash /mnt/user/services/homelab-infra/ops/maintenance/check-external-operator.sh
```
Erwarteter Stand vom 2026-06-01:
- FRITZ!Box 7590 meldet FRITZ!OS `154.08.25`.
- Public DNS fuer `*.kaleschke.info` liefert A-Records auf `217.249.115.154`, keine AAAA-Records.
- Host hat keine globale Provider-IPv6-Adresse; sichtbar ist nur Tailscale-IPv6 `fd7a:115c:a1e0::2c01:62b2`.
- WAN-Smoke gegen die Public-IP: `443/tcp` offen, `80/tcp` und `222/tcp` geschlossen.
- Borg UI nutzt `borg 1.4.x`; Repository `appdata-critical` liegt auf Hetzner Storage Box `ssh://...your-storagebox.de:23/./hetzner_borg_appdata_critical`.
- Restore-Freshness: `Critical 0`, `Warnings 0`.
## 2. Hetzner Account-Hygiene
Im Hetzner-/Storage-Box-Konto pruefen und extern/off-system dokumentieren:
| Punkt | Soll |
|---|---|
| Passwort | stark, eindeutig, im Passwortmanager |
| 2FA | aktiv, Recovery-Codes offline auffindbar |
| Kontakt-E-Mail | aktuell und ohne Homelab-Abhaengigkeit erreichbar |
| Zahlungsweg | gueltig, Fallback bekannt |
| Storage Box | Produkt, Benutzer und Rechnungsstatus sichtbar |
| SSH/SFTP/WebDAV/SMB | nur benoetigte Protokolle aktiv |
| Recovery | Kundennummer, Login-Pfad und Support-Pfad extern notiert |
Im Repo nur das Datum der Bestaetigung dokumentieren, nie Zugangsdaten.
## 3. Borg Append-Only
Ziel: Der produktive Backup-Client darf neue Archive schreiben, aber nicht
normal prune/delete/compact als unbeschraenkter Client ausfuehren.
Hetzner dokumentiert Borg-Zugriff auf Storage Boxen inklusive `--remote-path`
fuer Borg-Versionen; fuer Borg 1.4 wird `--remote-path=borg-1.4` empfohlen.
Hetzner bestaetigt auch, dass append-only moeglich ist. Borg selbst setzt
append-only pro SSH-Key typischerweise ueber einen forced command in
`authorized_keys` um.
Empfohlenes Zielmodell:
```text
command="borg serve --append-only --restrict-to-repository /home/hetzner_borg_appdata_critical",restrict ssh-ed25519 <backup-public-key> borg-ui-append-only
command="borg serve --restrict-to-repository /home/hetzner_borg_appdata_critical",restrict ssh-ed25519 <maintenance-public-key> borg-maintenance
```
Hinweise:
- Pfad auf der Storage Box vor dem Eintragen pruefen. Bei Hetzner werden Pfade
im Borg-Repo haeufig relativ als `./repo-name` verwendet; in
`authorized_keys` muss der serverseitige Pfad zur Storage-Box-Home-Struktur
passen.
- Der produktive Borg-UI-Key sollte append-only sein.
- Ein separater Maintenance-Key bleibt fuer bewusste Retention/Prune/Compact
noetig und darf nicht auf dem produktiven Homelab-Host liegen.
- Append-only verhindert nicht, dass ein kompromittierter Client Archive als
geloescht markiert; es verhindert die unmittelbare physische Entfernung.
Nach einem Vorfall keine unbeschraenkte Schreiboperation ausfuehren, bevor
die Borg-Transaktionen bewertet wurden.
Nach Aenderung:
1. Einen regulaeren Borg-Lauf abwarten oder manuell starten.
2. `check-external-operator.sh` ausfuehren.
3. In `docs/AUDIT_2026-05-25_TODO.md` nur das Ergebnis dokumentieren.
## 4. FRITZ!Box-Servicefenster
Vor dem Fenster:
1. Familie informieren: Internet/Telefonie koennen kurz weg sein.
2. Aktuellen Repo-Stand und Borg-Freshness pruefen.
3. FRITZ!Box-Konfig exportieren: `System -> Sicherung -> Sichern`.
4. Sicherungsdatei nicht ins Repo legen; im Passwortmanager/off-system ablegen.
In der FRITZ!Box:
| Bereich | Soll |
|---|---|
| `System -> Update` | FRITZ!OS aktuell; am 2026-06-01 per TR-064 `154.08.25` beobachtet |
| `Internet -> Freigaben -> Portfreigaben` | nur `443/tcp -> 192.168.178.58:443` |
| IPv6-Portfreigaben | keine unerwarteten Freigaben; insbesondere kein `222/tcp`, kein Admin-Port |
| Selbststaendige Portfreigaben/UPnP | fuer `Kallilabcore` aus; neue Geraete nur bewusst erlauben |
| Gastnetz | bleibt aus, solange keine Gastnetz-Policy gepflegt wird |
| Ausfallschutz | bewusst aus; nur neu bewerten, wenn ein Mobilfunk-Fallback gewuenscht ist |
Nach dem Fenster:
```bash
bash /mnt/user/services/homelab-infra/ops/maintenance/check-external-operator.sh
```
Dann in `docs/NETWORK_INVENTORY.md` aktualisieren:
- FRITZ!OS-Version
- IPv6-Status
- aktive Portfreigaben
- Datum der Konfig-Sicherung
## Quellen
- Hetzner Docs: Storage Box Zugriff mit SSH/rsync/BorgBackup, inklusive
Borg-Versionen, `--remote-path` und Append-Only-Hinweis:
<https://docs.hetzner.com/storage/storage-box/access/access-ssh-rsync-borg/>
- BorgBackup Docs: `borg serve --append-only` und forced commands in
`authorized_keys`:
<https://borgbackup.readthedocs.io/en/stable/deployment/pull-backup.html>
- AVM FRITZ!Box Hilfe: IPv6-Portfreigaben werden separat verwaltet; eingehende
Zugriffe sind standardmaessig nicht offen:
<https://help.avm.de/fritzbox.php?hardware=145&language=en&oem=avme&set=009&topic=hilfe_internet_freigabe_ipv6>
- AVM FRITZ!Box Hilfe: Sicherung der FRITZ!Box-Einstellungen:
<https://help.avm.de/fritzbox.php?hardware=145&language=en&oem=avme&set=009&topic=hilfe_system_export>
+7 -7
View File
@@ -1,7 +1,7 @@
# Network Inventory - KalliLab CORE
Status: Host-Audit erfasst; Router-Baseline und Portfreigaben-UI bereinigt; VLAN/IPv6-Details offen.
Letzte Pruefung: 2026-05-28
Status: Host-Audit erfasst; Router-Baseline und Portfreigaben-UI bereinigt; IPv6-Exposure technisch entschaerft.
Letzte Pruefung: 2026-06-01
## Zweck
@@ -14,11 +14,11 @@ Dieses Dokument beschreibt Router, DNS, Tailscale, Portfreigaben und Netztrennun
| 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.21 (Update gemeldet, nicht eingespielt) |
| 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 | TBD (FRITZ!Box-UI separat pruefen) |
| 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) | 36 aktive Geraete |
| LAN-Ports belegt | LAN 1-4 verbunden |
@@ -30,7 +30,7 @@ Dieses Dokument beschreibt Router, DNS, Tailscale, Portfreigaben und Netztrennun
- 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 8.21 hat ein angezeigtes Update; Einspielung ist Betreiber-Aufgabe und nicht Teil des Repos.
- FRITZ!OS ist am 2026-06-01 per TR-064 auf `154.08.25` beobachtet; FRITZ!Box-Konfig-Backup bleibt Betreiber-Aufgabe.
## DNS
@@ -151,8 +151,8 @@ docker network inspect backend_net | jq '.[0].Internal'
|---|---|---|
| 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-05-28** | 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-Selbstfreigabe-Recht fuer VONETS-Bridge (SolarEdge) deaktiviert. Aktiver Soll-Stand: ausschliesslich `443/tcp -> 192.168.178.58`. |
| FRITZ!OS 8.21 Update | gemeldet | Operator-Aufgabe; vor Update kurzes Service-Fenster planen, weil Reboot WAN/Tailscale-Aufbau unterbricht |
| FRITZ!OS Update | **erledigt / beobachtet 2026-06-01** | TR-064 meldet `154.08.25`; nach Betreiber-Login nur noch FRITZ!Box-Konfig-Backup ablegen |
| Gast-/IoT-Zugriff auf Admin-Ports | aktuell entschaerft | Gast-WLAN ist inaktiv; bei Aktivierung muessen `192.168.178.58:8082`, `192.168.178.58:8181` und ggf. weitere LAN-Ports per FRITZ!Box-Kindersicherung/Netzwerk-Filter abgesichert werden |
| IPv6 Exposure | offen | Router und Traefik/Cloudflare pruefen; Telekom-DSL liefert in der Regel IPv6, FRITZ!Box-Standard-Verhalten klaeren |
| IPv6 Exposure | technisch entschaerft | Public DNS liefert keine AAAA-Records fuer `*.kaleschke.info`; Host hat keine globale Provider-IPv6. In der FRITZ!Box trotzdem IPv6-Portfreigaben gegenpruefen: keine Admin-/SSH-Freigaben |
| WAN-Ausfallschutz | bewusst nicht eingerichtet | Mobilfunk-Stick-Failover an FRITZ!Box ist nicht aktiv; Internet-Ausfall = ACME/DDNS pausieren, lokale Apps laufen weiter |
| 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. |
+2 -1
View File
@@ -1,6 +1,6 @@
# Documentation Index
Stand: 2026-05-31
Stand: 2026-06-01
Diese Datei trennt aktive Betriebsdokumentation von historischer Arbeitsdoku. Neue operative Dokumente duerfen nur in `docs/` liegen, wenn sie heute als Einstieg, Runbook, Inventar oder offene Arbeitsliste gebraucht werden. Erledigte Audits, Chat-Handoffs, Prompt-Dateien und abgeschlossene Plaene bleiben in der Git-Historie, aber nicht als dauerhafte Arbeitskopie.
@@ -34,6 +34,7 @@ Diese Datei trennt aktive Betriebsdokumentation von historischer Arbeitsdoku. Ne
| `HARDWARE_INVENTORY.md` | Host-, Disk-, SMART-, USV- und Power-Baseline |
| `NETWORK_INVENTORY.md` | Router, DNS, Tailscale, Portfreigaben und Netzthemen |
| `EXTERNAL_DEPENDENCIES.md` | Provider, Konten und externe Abhaengigkeiten |
| `EXTERNAL_OPERATOR_RUNBOOK.md` | Hetzner-/Borg-/FRITZ!Box-Betreibercheck |
| `CAPACITY_AND_LIFECYCLE.md` | Kapazitaet, Wachstum und Upgrade-Trigger |
## Monitoring und Automatisierung
+91
View File
@@ -0,0 +1,91 @@
#!/usr/bin/env bash
set -euo pipefail
HOST_IP="${HOST_IP:-192.168.178.58}"
FRITZBOX_URL="${FRITZBOX_URL:-http://192.168.178.1:49000/tr64desc.xml}"
BORG_DB="${BORG_DB:-/mnt/user/appdata/borg-ui/data/borg.db}"
REPO_ROOT="${REPO_ROOT:-/mnt/user/services/homelab-infra}"
section() {
printf '\n## %s\n\n' "$1"
}
section "FRITZBox"
if fritz_xml="$(curl -fsS --max-time 5 "$FRITZBOX_URL")"; then
printf '%s\n' "$fritz_xml" | grep -E '<friendlyName>|<modelName>|<Display>' | sed -E 's/^[[:space:]]+//'
else
echo "FRITZBox TR-064 descriptor not reachable at $FRITZBOX_URL"
fi
section "Host IPv6"
global_ipv6="$(
ip -6 addr show scope global \
| awk '/inet6 / {print $2}' \
| grep -Ev '^(fd|fe80:)' || true
)"
if [[ -n "$global_ipv6" ]]; then
echo "Provider/global IPv6 addresses present:"
printf '%s\n' "$global_ipv6"
else
echo "No provider/global IPv6 address on host; only ULA/link-local/Tailscale may be present."
fi
tailscale ip -4 2>/dev/null | sed 's/^/Tailscale IPv4: /' || true
tailscale ip -6 2>/dev/null | sed 's/^/Tailscale IPv6: /' || true
section "DNS"
for name in \
kaleschke.info \
vault.kaleschke.info \
git.kaleschke.info \
cloud.kaleschke.info \
traefik.kaleschke.info; do
echo "$name"
dig +short @1.1.1.1 "$name" A | sed 's/^/ public A /' || true
dig +short @1.1.1.1 "$name" AAAA | sed 's/^/ public AAAA /' || true
done
section "Host Listeners"
ss -ltnp | awk '
/:(80|443|222|53|8082|8181)[[:space:]]/ ||
/100\.80\.98\.33:8082/ ||
/127\.0\.0\.1:8181/ {print}
' | sort -k4
section "External Port Smoke"
public_ipv4="$(curl -4 -fsS --max-time 5 https://ifconfig.co 2>/dev/null || true)"
if [[ -z "$public_ipv4" ]]; then
public_ipv4="$(dig +short @1.1.1.1 kaleschke.info A | tail -n 1)"
fi
for check in \
"$public_ipv4 443 expected-open" \
"$public_ipv4 80 expected-closed" \
"$public_ipv4 222 expected-closed"; do
set -- $check
target="$1"
port="$2"
expected="$3"
if timeout 5 bash -c "cat < /dev/null > /dev/tcp/$target/$port" 2>/dev/null; then
result="open"
else
result="closed"
fi
printf '%s:%s %s (%s)\n' "$target" "$port" "$result" "$expected"
done
section "Borg UI Repository"
if [[ -f "$BORG_DB" ]]; then
sqlite3 -header -csv "$BORG_DB" \
"select name,repository_type,path,remote_path,last_backup,last_check,borg_version,custom_flags from repositories order by id;"
sqlite3 -header -csv "$BORG_DB" \
"select id,repository,status,archive_name,started_at,completed_at,nfiles from backup_jobs order by id desc limit 3;"
else
echo "Borg UI database not found: $BORG_DB"
fi
section "Restore Freshness"
if [[ -x "$REPO_ROOT/ops/restore-tests/run-restore-checks.sh" ]]; then
"$REPO_ROOT/ops/restore-tests/run-restore-checks.sh" freshness
else
echo "Restore freshness script not executable: $REPO_ROOT/ops/restore-tests/run-restore-checks.sh"
fi