Merge branch 'phase/release-0.5.0'
@@ -15,6 +15,25 @@ und dieses Projekt folgt [Semantic Versioning](https://semver.org/lang/de/).
|
||||
|
||||
### Sicherheit
|
||||
|
||||
## [0.5.0] – 2026-10-12
|
||||
|
||||
Phase 5: Übersicht, Audit-Log, Benachrichtigungen, Handbuch und Betrieb.
|
||||
|
||||
### Hinzugefügt
|
||||
- Übersicht mit echten Zahlen: Kennzahlen, Hosts mit Abweichung, bald ablaufende und abgelaufene Schlüssel, letzte Aktionen (#026)
|
||||
- Audit-Log: Filter, aufklappbare Einträge mit Diff und Hashes, Prüfung der Hash-Kette, CSV-Export (gestreamt), optionale Syslog-Kopie nach RFC 5424 (#027)
|
||||
- Benachrichtigungen per E-Mail (Microsoft 365 SMTP vorbelegt) und Webhook mit Signatur: tägliche Zusammenfassung zu Drift, Ablauf und nicht erreichbaren Hosts, geänderte Host-Keys sofort; Testversand, Versandprotokoll ohne Doppelmeldungen; Einstellungsseite (#028)
|
||||
- Handbuch mit Bildern, Installation mit authentik und Reverse Proxy, Bedrohungsanalyse mit Notfallplan (#029)
|
||||
- `deploy/sichern.sh` und `deploy/wiederherstellen.sh` – Wiederherstellung auf einem Wegwerf-Stapel geprobt (#029)
|
||||
|
||||
### Geändert
|
||||
- Der Worker startet nicht, wenn der Master-Key nicht zur Datenbank passt (#029)
|
||||
|
||||
### Sicherheit
|
||||
- Sicherung ohne Master-Key, nur mit Prüfwert; Wiederherstellung bricht vor jeder Änderung ab, wenn der Master-Key nicht passt, und läuft in einer Transaktion
|
||||
- SMTP-Passwort und Webhook-Geheimnis verschlüsselt gespeichert und nie wieder angezeigt; Webhook nur über https, ohne Weiterleitungen
|
||||
- Syslog-Kopie enthält nie Details oder Diffs
|
||||
|
||||
## [0.4.0] – 2026-10-12
|
||||
|
||||
Phase 4: Abgleich, Import, Rotation, Widerruf und Zuweisungsmatrix.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## Zeitübersicht
|
||||
|
||||
**Gesamt (Wandzeit):** 3 h 40 min
|
||||
**Summe der Issue-Zeiten:** 11 h 03 min – Sub-Agenten arbeiteten parallel an #002, #006, #008, #011, #012–#014, #019 (Oberfläche), #023–#025.
|
||||
**Gesamt (Wandzeit):** 4 h 25 min
|
||||
**Summe der Issue-Zeiten:** 13 h 18 min – Sub-Agenten arbeiteten parallel an #002, #006, #008, #011, #012–#014, #019 (Oberfläche), #023–#025, #027 und #028.
|
||||
|
||||
| Issue | Zeit |
|
||||
|---|---|
|
||||
@@ -33,6 +33,10 @@
|
||||
| #023 Geführte Rotation | 0 h 20 min |
|
||||
| #024 Widerruf und Massenwiderruf | 0 h 25 min |
|
||||
| #025 Zuweisungsmatrix | 0 h 30 min |
|
||||
| #026 Übersicht | 0 h 25 min |
|
||||
| #027 Protokollansicht, CSV, Syslog | 0 h 20 min |
|
||||
| #028 Benachrichtigungen | 0 h 30 min |
|
||||
| #029 Handbuch und Betriebsdokumentation | 0 h 50 min |
|
||||
| #030 Gitea-Abgleich (vorbereitet) | 0 h 05 min |
|
||||
|
||||
| Meilenstein | Zeit |
|
||||
@@ -41,6 +45,7 @@
|
||||
| v0.2.0 | 1 h 00 min (Wandzeit) | **abgeschlossen**
|
||||
| v0.3.0 | 0 h 30 min (Wandzeit) | **abgeschlossen**
|
||||
| v0.4.0 | 0 h 45 min (Wandzeit) | **abgeschlossen**
|
||||
| v0.5.0 | 0 h 45 min (Wandzeit) | **abgeschlossen**
|
||||
|
||||
---
|
||||
|
||||
@@ -126,3 +131,21 @@
|
||||
- **Widerruf mit Zwischenzustand:** Ein Schlüssel wird erst WIDERRUFEN, wenn er überall entfernt ist; ein nicht erreichbarer Host lässt ihn erkennbar „unvollständig“.
|
||||
- **Rotation entfernt den alten Schlüssel erst nach erfolgreichen Verbindungstests**; doppelte Aliase in `~/.ssh/config`: die jüngste Zuweisung gewinnt.
|
||||
- **Migrationszeitstempel in Ortszeit-Reihenfolge** auch bei parallel entstandenen Migrationen (`…130000` Agent, `…131000` Hauptsitzung).
|
||||
|
||||
## 2026-10-12 · Sitzung 5 · 16:27–17:12
|
||||
**Issue:** #026–#029
|
||||
**Version:** 0.5.0
|
||||
|
||||
### Erledigt
|
||||
- #026 Übersicht aus der Datenbank; lesbare Aktionstexte aus #027
|
||||
- #027 Audit-Log-Ansicht, Kettenprüfung, CSV, Syslog (Sub-Agent)
|
||||
- #028 Benachrichtigungen und Einstellungsseite (Sub-Agent, eigener Mailpit und eigene Testziele)
|
||||
- #029 Handbuch (12 Kapitel mit Bildern), Installation, Bedrohungsanalyse, Sicherung; Sicherung/Wiederherstellung geprobt
|
||||
- Merge-Konflikte (Compose, Screenshot-Skript, Worker-Einstieg) zusammengeführt; der strukturelle Test für Aktionstexte fand vier neue Aktionen ohne Text
|
||||
- Stand: 858 Unit-/DB-Tests, 43 Integrationstests, 24 E2E-Abläufe grün
|
||||
|
||||
### Entscheidungen
|
||||
- **Wiederherstellung wirklich geprobt** statt nur beschrieben – sie fand zwei Fehler, die im Ernstfall die Wiederherstellung verhindert hätten.
|
||||
- **Master-Key nicht in die Sicherung,** nur ein Prüfwert; Worker verweigert den Start mit falschem Master-Key.
|
||||
- **Benachrichtigungen lesen ihre Anlässe aus der Datenbank** statt sich in den Abgleich einzuhängen; Doppelmeldungen verhindert ein Versandprotokoll mit Fingerabdruck je Anlass.
|
||||
- **Keine 1.0.0 ohne Abnahme:** 0.5.0 schließt die fünf Phasen; authentik, Gitea und ein Lauf auf echten Hosts stehen noch aus.
|
||||
|
||||
@@ -4,9 +4,9 @@ Selbst gehostete Weboberfläche zur zentralen Verwaltung von SSH-Schlüsseln: Sc
|
||||
erzeugen und verwalten, Public Keys in `authorized_keys` verteilen, Private Keys gezielt auf
|
||||
andere Hosts ausrollen, Ist- und Soll-Zustand abgleichen – alles revisionssicher protokolliert.
|
||||
|
||||
> **Stand 0.1.0 (Phase 1):** Grundgerüst, Anmeldung (OIDC + Notfall-Admin mit TOTP), Hosts und
|
||||
> Hostgruppen, Host-Key-Prüfung (TOFU) und Bootstrap neuer Hosts. Schlüsselverwaltung und
|
||||
> Ausrollen folgen in Phase 2 und 3 – siehe [`docs/PLAN.md`](docs/PLAN.md).
|
||||
> **Stand 0.5.0:** alle fünf Phasen aus [`docs/PLAN.md`](docs/PLAN.md) umgesetzt – Hosts mit Host-Key-Prüfung
|
||||
> und Bootstrap, Schlüssel, Ausrollen von Public und Private Keys mit Dry-Run, Host-zu-Host-Assistent,
|
||||
> Abgleich, Rotation, Widerruf, Zuweisungsmatrix, Audit-Log, Benachrichtigungen. 1.0.0 nach der Abnahme.
|
||||
|
||||
## Sicherheit vorab
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 181 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 180 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 114 KiB |
|
Before Width: | Height: | Size: 215 KiB After Width: | Height: | Size: 213 KiB |
|
Before Width: | Height: | Size: 221 KiB After Width: | Height: | Size: 219 KiB |
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 293 KiB After Width: | Height: | Size: 293 KiB |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sshkv",
|
||||
"version": "0.4.0",
|
||||
"version": "0.5.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "SSHKeyVault – zentrale Verwaltung von SSH-Schluesseln mit Weboberflaeche",
|
||||
|
||||
@@ -46,7 +46,10 @@ test("ohne Sitzung geht es zur Anmeldung, mit Ziel", async ({ page }) => {
|
||||
test("OIDC-Admin landet in der Übersicht und kann sich abmelden", async ({ page }) => {
|
||||
await oidcAnmelden(page, "admin");
|
||||
await expect(page.getByRole("heading", { name: "Übersicht" })).toBeVisible();
|
||||
await expect(page.getByText("Admin (Mock)")).toBeVisible();
|
||||
// Der Name steht seit #026 auch in den letzten Aktionen – gezielt im Benutzerkasten pruefen.
|
||||
await expect(
|
||||
page.getByText("Admin · über Mock-OIDC").locator("..").getByText("Admin (Mock)", { exact: true }),
|
||||
).toBeVisible();
|
||||
await expect(page.getByText("Admin · über Mock-OIDC")).toBeVisible();
|
||||
await page.getByRole("button", { name: "Abmelden" }).click();
|
||||
await expect(page.getByText("Sie wurden abgemeldet.")).toBeVisible();
|
||||
|
||||