chore(release): 0.2.0 - Phase 2 abgeschlossen
Schluessel, Personen, Private Key anzeigen, authorized_keys-Parser und Ausrollen von Public Keys; vorgezogen das Ausrollen von Private Keys mit ssh-config und known_hosts. CHANGELOG und DEVLOG nachgetragen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,26 @@ und dieses Projekt folgt [Semantic Versioning](https://semver.org/lang/de/).
|
|||||||
|
|
||||||
### Sicherheit
|
### Sicherheit
|
||||||
|
|
||||||
|
## [0.2.0] – 2026-10-12
|
||||||
|
|
||||||
|
Phase 2: Schlüssel, Personen und Ausrollen von Public Keys – dazu vorgezogen aus Phase 3 das Ausrollen von Private Keys.
|
||||||
|
|
||||||
|
### Hinzugefügt
|
||||||
|
- Schlüssel erzeugen (ed25519, RSA-4096, optional mit Passphrase), Paar oder Public Key importieren, Public Key exportieren; Liste mit Filter, Detailseite mit Verwendungen (#012)
|
||||||
|
- Personen verwalten; Self-Service „Meine Schlüssel“: jeder Benutzer hinterlegt eigene Public Keys, wirksam erst nach Zuweisung (#013)
|
||||||
|
- Private Key anzeigen und herunterladen – nur Admin, nur nach erneuter Bestätigung, genau einmal abholbar; Private Key aus SSHKeyVault löschen (#014)
|
||||||
|
- authorized_keys-Parser und verwalteter Block: fremde Zeilen bleiben bytegenau, beschädigte Blöcke werden nie überschrieben, Deployment-Key ist vor dem Entfernen geschützt (#015)
|
||||||
|
- Public Keys Hosts oder Hostgruppen zuweisen, Dry-Run mit Diff, Ausrollen mit Backup und optimistischer Sperre; Ansicht je Schlüssel und je Host (#016)
|
||||||
|
- Private Key auf einen Quell-Host ausrollen, mit verwaltetem Block in `~/.ssh/config` und `known_hosts` (#017)
|
||||||
|
- Verbindungstest von Host A nach Host B (#020, Teil)
|
||||||
|
- Zielbenutzer anlegen und sudoers pflegen – Grundlage, Oberfläche folgt (#018, Teil)
|
||||||
|
- Vorlagen: Platzhalter und Prüfung – Grundlage, Oberfläche folgt (#019, Teil)
|
||||||
|
|
||||||
|
### Sicherheit
|
||||||
|
- Importierte Private Keys reisen nur verschlüsselt im Job; Vorgang, Protokoll und Browser sehen sie nie (Tests)
|
||||||
|
- Private-Key-Ziele nimmt der Dry-Run nur für Admins auf
|
||||||
|
- Dateien in fremden Home-Verzeichnissen werden als deren Benutzer gelesen und geschrieben (Symlink-Schutz)
|
||||||
|
|
||||||
## [0.1.0] – 2026-10-12
|
## [0.1.0] – 2026-10-12
|
||||||
|
|
||||||
Phase 1: Grundgerüst, Anmeldung, Hosts und Bootstrap.
|
Phase 1: Grundgerüst, Anmeldung, Hosts und Bootstrap.
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
## Zeitübersicht
|
## Zeitübersicht
|
||||||
|
|
||||||
**Gesamt (Wandzeit):** 1 h 25 min
|
**Gesamt (Wandzeit):** 2 h 25 min
|
||||||
**Summe der Issue-Zeiten:** 4 h 23 min – Sub-Agenten arbeiteten parallel an #002, #006, #008 und #011.
|
**Summe der Issue-Zeiten:** 7 h 08 min – Sub-Agenten arbeiteten parallel an #002, #006, #008, #011 und #012–#014.
|
||||||
|
|
||||||
| Issue | Zeit |
|
| Issue | Zeit |
|
||||||
|---|---|
|
|---|---|
|
||||||
@@ -19,10 +19,20 @@
|
|||||||
| #009 Host-Key-Prüfung | 0 h 25 min |
|
| #009 Host-Key-Prüfung | 0 h 25 min |
|
||||||
| #010 Bootstrap | 0 h 35 min |
|
| #010 Bootstrap | 0 h 35 min |
|
||||||
| #011 Test-SSH-Container | 0 h 15 min |
|
| #011 Test-SSH-Container | 0 h 15 min |
|
||||||
|
| #012 Schlüssel erzeugen, importieren, exportieren | 0 h 25 min |
|
||||||
|
| #013 Personen und Self-Service | 0 h 10 min |
|
||||||
|
| #014 Private Key anzeigen | 0 h 10 min |
|
||||||
|
| #015 authorized_keys-Parser | 0 h 15 min |
|
||||||
|
| #016 Public Key ausrollen | 0 h 40 min |
|
||||||
|
| #017 Private Key ausrollen | 0 h 45 min |
|
||||||
|
| #018 Zielbenutzer und sudoers (Teil) | 0 h 10 min |
|
||||||
|
| #019 Vorlagen (Teil) | 0 h 10 min |
|
||||||
|
| #020 Verbindungstest (Teil) | 0 h 05 min |
|
||||||
|
|
||||||
| Meilenstein | Zeit |
|
| Meilenstein | Zeit |
|
||||||
|---|---|
|
|---|---|
|
||||||
| v0.1.0 | 1 h 25 min (Wandzeit) | **abgeschlossen**
|
| v0.1.0 | 1 h 25 min (Wandzeit) | **abgeschlossen**
|
||||||
|
| v0.2.0 | 1 h 00 min (Wandzeit) | **abgeschlossen**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -55,3 +65,22 @@
|
|||||||
- **Eigene Testdatenbank je parallelem Lauf:** Sub-Agent und Hauptsitzung leerten sich gegenseitig die Tabellen (in `CLAUDE.md` festgehalten).
|
- **Eigene Testdatenbank je parallelem Lauf:** Sub-Agent und Hauptsitzung leerten sich gegenseitig die Tabellen (in `CLAUDE.md` festgehalten).
|
||||||
- **Prisma-Client in den Worker gebündelt:** Im Standalone-Abbild fand die ESM-Auflösung `@prisma/client` sonst nicht (erst im echten Docker-Stapel aufgefallen).
|
- **Prisma-Client in den Worker gebündelt:** Im Standalone-Abbild fand die ESM-Auflösung `@prisma/client` sonst nicht (erst im echten Docker-Stapel aufgefallen).
|
||||||
- **Worker-Benutzer in Compose wählbar** (`SSHKV_WORKER_USER`), weil Docker-Secrets ohne Swarm die Rechte der Host-Datei tragen.
|
- **Worker-Benutzer in Compose wählbar** (`SSHKV_WORKER_USER`), weil Docker-Secrets ohne Swarm die Rechte der Host-Datei tragen.
|
||||||
|
|
||||||
|
## 2026-10-12 · Sitzung 2 · 10:07–11:07
|
||||||
|
**Issue:** #012–#020
|
||||||
|
**Version:** 0.2.0
|
||||||
|
|
||||||
|
### Erledigt
|
||||||
|
- #012–#014 (Schlüssel, Personen/Self-Service, Private Key anzeigen) von einem Sub-Agenten in eigenem Worktree, danach gemergt; Konflikte in `useVorgang` und der Handler-Tabelle zusammengeführt
|
||||||
|
- #015 authorized_keys-Parser und Merge mit 26 Randfall-Tests
|
||||||
|
- #016 Public Keys ausrollen: Soll, Trockenlauf, Ausrollen, Hostseite, Schlüsselseite – Integrationstests und E2E
|
||||||
|
- #017 Private Key mit `~/.ssh/config` und `known_hosts` – Integrationstest „A meldet sich bei B an“, E2E für den ganzen Kern-Anwendungsfall
|
||||||
|
- Vorgezogen: #018 Zielkonto-Skripte (Integrationstests), #019 Vorlagen-Logik, #020 Verbindungstest
|
||||||
|
- Stand: 410 Unit-/DB-Tests, 30 Integrationstests, 12 E2E-Abläufe grün
|
||||||
|
|
||||||
|
### Entscheidungen
|
||||||
|
- **Phase 3 teilweise vorgezogen,** weil Florian „weiter“ sagte, während der Agent noch an Phase 2 arbeitete – nur Teile ohne Schemaänderung, damit die Migrationen des Agenten nicht kollidieren.
|
||||||
|
- **Trockenlauf und Ausrollen als zwei Vorgänge mit Hash-Sperre:** Es wird nie etwas anderes geschrieben, als jemand gesehen hat.
|
||||||
|
- **Private-Key-Ziele im Dry-Run nur für Admins:** Sonst hätte ein Operator einen vorbereiteten Private Key ausrollen lassen können (Freigabe Frage 3).
|
||||||
|
- **Keine Sicherungskopie alter Private Keys** auf dem Host; config-Block am Dateianfang, weil ssh den ersten Treffer nimmt.
|
||||||
|
- **Ein Hook `useVorgang` für alle:** zwei parallel entstandene Fassungen zusammengeführt, beide Schnittstellen bleiben.
|
||||||
|
|||||||
@@ -1,21 +1,27 @@
|
|||||||
# #016 Public Key ausrollen mit Dry-Run und Backup
|
# #016 Public Key ausrollen mit Dry-Run und Backup
|
||||||
**Status:** offen
|
**Status:** erledigt
|
||||||
**Meilenstein:** v0.2.0
|
**Meilenstein:** v0.2.0
|
||||||
**Labels:** backend, ui
|
**Labels:** backend, ui
|
||||||
**Geschätzt:** 4 h **Tatsächlich:** –
|
**Geschätzt:** 4 h **Tatsächlich:** 0 h 40 min
|
||||||
|
|
||||||
## Ziel
|
## Ziel
|
||||||
Zuweisungen Schlüssel × Host/Gruppe × Benutzer; Dry-Run-Diff, Backup, atomares Schreiben, Rechte.
|
Zuweisungen Schlüssel × Host/Gruppe × Benutzer; Dry-Run-Diff, Backup, atomares Schreiben, Rechte.
|
||||||
|
|
||||||
## Aufgaben
|
## Aufgaben
|
||||||
- [ ] Remote-Skript
|
- [x] Remote-Skript
|
||||||
- [ ] Optimistische Sperre über Datei-Hash
|
- [x] Optimistische Sperre über Datei-Hash
|
||||||
- [ ] Diff-Box im Schlüsseldetail
|
- [x] Diff-Box im Schlüsseldetail
|
||||||
|
|
||||||
## Akzeptanzkriterien
|
## Akzeptanzkriterien
|
||||||
- [ ] Integrationstest Ausrollen/Entfernen
|
- [x] Integrationstest Ausrollen/Entfernen
|
||||||
|
|
||||||
## Abhängigkeiten
|
## Abhängigkeiten
|
||||||
#015, #010
|
#015, #010
|
||||||
|
|
||||||
## Notizen / Entscheidungen
|
## Notizen / Entscheidungen
|
||||||
|
- **Zwei Schritte:** TROCKENLAUF hält je Ziel Diff, Hinweise und die Hashes vorher/nachher fest; AUSROLLEN führt genau diesen Plan aus und bricht je Ziel ab, wenn sich Datei **oder** Soll geändert hat. Ein Trockenlauf gilt 15 Minuten und nur einmal.
|
||||||
|
- **Auf dem Host** alles als Zielbenutzer (`runuser`), Hash dort erneut geprüft, Sicherung (letzte 5 bleiben), Temp-Datei + `mv`, 0700/0600.
|
||||||
|
- **Nur gültiges UTF-8** wird bearbeitet, sonst ginge „bytegenau“ verloren.
|
||||||
|
- **Soll** = direkte und Gruppen-Zuweisungen; der Deployment-Key gehört immer zum Soll des Anmeldebenutzers (Aussperrschutz aus #015).
|
||||||
|
- Gruppen-Verwendungen: Zustand je Verwendung, Fehlschlag auf einem Host gewinnt. Zustand je Host folgt mit dem Abgleich (#021).
|
||||||
|
- Oberfläche: Zuweisen auf der Schlüsselseite, Dry-Run je Schlüssel und je Host.
|
||||||
|
|||||||
@@ -1,21 +1,27 @@
|
|||||||
# #017 Private Key ausrollen und ~/.ssh/config
|
# #017 Private Key ausrollen und ~/.ssh/config
|
||||||
**Status:** offen
|
**Status:** erledigt
|
||||||
**Meilenstein:** v0.3.0
|
**Meilenstein:** v0.3.0
|
||||||
**Labels:** backend, ui
|
**Labels:** backend, ui
|
||||||
**Geschätzt:** 4 h **Tatsächlich:** –
|
**Geschätzt:** 4 h **Tatsächlich:** 0 h 45 min
|
||||||
|
|
||||||
## Ziel
|
## Ziel
|
||||||
Private Key auf Zielhost/-benutzer/-pfad, verwalteter Block in `~/.ssh/config`, `known_hosts`.
|
Private Key auf Zielhost/-benutzer/-pfad, verwalteter Block in `~/.ssh/config`, `known_hosts`.
|
||||||
|
|
||||||
## Aufgaben
|
## Aufgaben
|
||||||
- [ ] Übertragung nur über stdin
|
- [x] Übertragung nur über stdin
|
||||||
- [ ] Warnung bei Passphrase
|
- [x] Warnung bei Passphrase
|
||||||
- [ ] nur Admin
|
- [x] nur Admin
|
||||||
|
|
||||||
## Akzeptanzkriterien
|
## Akzeptanzkriterien
|
||||||
- [ ] Integrationstest
|
- [x] Integrationstest
|
||||||
|
|
||||||
## Abhängigkeiten
|
## Abhängigkeiten
|
||||||
#016
|
#016
|
||||||
|
|
||||||
## Notizen / Entscheidungen
|
## Notizen / Entscheidungen
|
||||||
|
- **Dateien je Ziel:** Private Key (0600, keine Sicherungskopie), `.pub` (0644), verwalteter Block **am Anfang** von `~/.ssh/config` (ssh nimmt den ersten Treffer), verwalteter Block in `known_hosts` mit den vertrauten Host-Keys des Ziels unter dem HostName/Port aus der config.
|
||||||
|
- **Nie fremde Dateien überschreiben:** Liegt am Zielpfad schon etwas anderes, scheitert das Ziel im Trockenlauf.
|
||||||
|
- **Plan ohne Inhalt:** Der Trockenlauf zeigt beim Private Key nur die Aktion; weder Vorgang noch Protokoll noch Browser sehen den Schlüssel.
|
||||||
|
- **Nur Admins:** Zuweisen verlangt `privateKeyAusrollen`; der Trockenlauf nimmt Private-Key-Ziele nur für Admins auf.
|
||||||
|
- **Widerruf:** löschen oder umbenennen (`…sshkv-widerrufen.<Zeit>`), config- und known_hosts-Einträge verschwinden mit.
|
||||||
|
- Integrationstest: A meldet sich per Alias bei B an (StrictHostKeyChecking=yes). E2E im Browser für den ganzen Kern-Anwendungsfall.
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sshkv",
|
"name": "sshkv",
|
||||||
"version": "0.1.0",
|
"version": "0.2.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "SSHKeyVault – zentrale Verwaltung von SSH-Schluesseln mit Weboberflaeche",
|
"description": "SSHKeyVault – zentrale Verwaltung von SSH-Schluesseln mit Weboberflaeche",
|
||||||
|
|||||||
Reference in New Issue
Block a user