feat(hosts): Host-Key und Bootstrap in der Oberflaeche (#009, #010)

Auf der Hostseite: Host-Key abrufen, Fingerprint vergleichen und
vertrauen oder ablehnen. Weicht ein Key vom vertrauten ab, erscheint
eine deutliche Warnung, und Annehmen geht nur mit Haekchen und frischer
Bestaetigung. Danach Bootstrap per Einmal-Passwort oder per Befehl und
Verbindungspruefung, jeweils mit Fortschrittsanzeige.

Der sshd-Befund empfiehlt prohibit-password, wenn root sich per
Passwort anmelden darf - nur als Hinweis, geaendert wird nichts.

E2E im gebauten Stand mit Worker gegen ein echtes sshd.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 10:00:43 +02:00
co-authored by Claude Opus 5.5
parent c87c7b4e43
commit 4584669962
12 changed files with 450 additions and 45 deletions
+12 -8
View File
@@ -1,23 +1,27 @@
# #009 Host-Key-Prüfung (TOFU) und Erreichbarkeit
**Status:** offen
**Status:** erledigt
**Meilenstein:** v0.1.0
**Labels:** sicherheit
**Geschätzt:** 3 h **Tatsächlich:** –
**Geschätzt:** 3 h **Tatsächlich:** 0 h 25 min
## Ziel
Beim ersten Kontakt wird der Host-Key angezeigt und bestätigt; danach strikte Prüfung, Änderung = Warnung.
## Aufgaben
- [ ] Vorgang „Host-Key abrufen“ (ohne Anmeldung)
- [ ] Bestätigen/Ablehnen mit Protokolleintrag
- [ ] `hostVerifier` in ssh2 gegen gespeicherten Key
- [ ] Geänderter Host-Key: Status GEAENDERT, keine Verbindung, deutliche Warnung
- [ ] Erreichbarkeitsprüfung
- [x] Vorgang „Host-Key abrufen“ (ohne Anmeldung)
- [x] Bestätigen/Ablehnen mit Protokolleintrag
- [x] `hostVerifier` in ssh2 gegen gespeicherten Key
- [x] Geänderter Host-Key: Status GEAENDERT, keine Verbindung, deutliche Warnung
- [x] Erreichbarkeitsprüfung
## Akzeptanzkriterien
- [ ] Integrationstest: geänderter Host-Key wird abgelehnt
- [x] Integrationstest: geänderter Host-Key wird abgelehnt
## Abhängigkeiten
#006, #007
## Notizen / Entscheidungen
- **Nur vertraute Algorithmen anbieten:** `serverHostKey` enthält nur die Verfahren der vertrauten Keys (für `ssh-rsa` die `rsa-sha2-*`). Sonst könnte ein Server einen Key eines anderen Typs zeigen, den nie jemand gesehen hat.
- **Abrufen bricht im `hostVerifier` ab** – vor jedem Austausch von Zugangsdaten.
- **Geänderter Key:** wird als AUSSTEHEND festgehalten, öffnet eine Abweichung `HOSTKEY_GEAENDERT` und setzt den Host auf Drift. Ersetzen nur mit ausdrücklichem Häkchen in der Oberfläche **und** frischer Bestätigung (Re-Auth).
- Integrationstest gegen echtes sshd inkl. Host-Key-Tausch; E2E im Browser (abrufen → vertrauen).
+15 -9
View File
@@ -1,24 +1,30 @@
# #010 Bootstrap neuer Hosts
**Status:** offen
**Status:** erledigt
**Meilenstein:** v0.1.0
**Labels:** backend, ui
**Geschätzt:** 4 h **Tatsächlich:** –
**Geschätzt:** 4 h **Tatsächlich:** 0 h 35 min
## Ziel
Deployment-Key auf neuen Host bringen: einmalige Passwortanmeldung (nie gespeichert) oder Copy-Paste-Befehl. Dienstbenutzer `sshkv` + sudoers.
## Aufgaben
- [ ] Einmal-Passwort nur im Arbeitsspeicher des Workers, verschlüsselt im Job, danach gelöscht
- [ ] Bootstrap-Skript: Benutzer `sshkv`, `/etc/sudoers.d/sshkv` (geprüft mit `visudo -c`), Deployment-Key in verwaltetem Block
- [ ] Alternative: Befehl zum Kopieren
- [ ] Prüfung nach Bootstrap: Anmeldung per Schlüssel, sudo ohne Passwort
- [ ] sshd-Check: `PermitRootLogin`, `PasswordAuthentication` (nur Anzeige)
- [x] Einmal-Passwort nur im Arbeitsspeicher des Workers, verschlüsselt im Job, danach gelöscht
- [x] Bootstrap-Skript: Benutzer `sshkv`, `/etc/sudoers.d/sshkv` (geprüft mit `visudo -c`), Deployment-Key in verwaltetem Block
- [x] Alternative: Befehl zum Kopieren
- [x] Prüfung nach Bootstrap: Anmeldung per Schlüssel, sudo ohne Passwort
- [x] sshd-Check: `PermitRootLogin`, `PasswordAuthentication` (nur Anzeige)
## Akzeptanzkriterien
- [ ] Integrationstest gegen Test-Container: Bootstrap per Passwort und per Befehl
- [ ] Passwort taucht nirgends in DB, Logs oder Protokoll auf
- [x] Integrationstest gegen Test-Container: Bootstrap per Passwort und per Befehl
- [x] Passwort taucht nirgends in DB, Logs oder Protokoll auf
## Abhängigkeiten
#009
## Notizen / Entscheidungen
- **Ein Skript für beide Wege** (Passwort im Worker, Befehl zum Kopieren) – keine zwei Wahrheiten über Änderungen am Host.
- **Passwort:** reist verschlüsselt (`SSHKV_APP_SECRET`) nur im Job, Job wird nach dem Lauf gelöscht; Test: Passwort steht in keiner Tabelle. JS-Strings lassen sich nicht überschreiben – das Passwort lebt bis zur Speicherbereinigung im Worker-Speicher.
- **Nicht-root mit sudo-Passwort** wird unterstützt (`sudo -S`).
- **Symlink-Schutz:** Dateien im Home des Zielbenutzers liest und schreibt das Skript als dieser Benutzer (`runuser`). Test mit Symlink auf `/etc/shadow`: Abbruch, `/etc/shadow` unverändert.
- **CRLF:** Das Bootstrap-Skript entfernt `\r` aus authorized_keys. Die bytegenaue Erhaltung fremder Zeilen leistet erst der TS-Merge aus #015.
- **sshd-Hinweise** (nur Anzeige): `PermitRootLogin yes` → Empfehlung `prohibit-password`; abweichendes `AuthorizedKeysFile` → Warnung.