Commit Graph
16 Commits
Author SHA1 Message Date
florian.wildeandClaude Opus 5.5 364c514b04 feat(protokoll): Eintraege vor dem Schreiben schwaerzen (#005)
Details und Diff laufen durch schwaerzen(), damit kein Private Key und
kein Passwort ins unveraenderliche Protokoll geraet - was dort einmal
steht, laesst sich per Trigger nicht mehr entfernen.

Der Wortstamm privat ist dafuer zu breit: er schwaerzte auch Pfade und
Verwendungszaehler, die das Protokoll gerade zeigen soll. Jetzt greifen
nur Felder, die den Schluessel selbst tragen, und jeder PEM-Block.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:30:51 +02:00
florian.wildeandClaude Opus 5.5 d1ba822a4a feat(auth): Anmeldeseiten, TOTP-Einrichtung und Bestaetigung (#004)
Anmeldung, Einrichtung des zweiten Faktors fuer den Notfall-Admin,
erneute Bestaetigung vor kritischen Aktionen und die Seite fuer
fehlende Rechte. Die Huelle zeigt jetzt den echten Benutzer, und jede
Seite prueft die Sitzung selbst; ein struktureller Test haelt das fest.

Die Ablaeufe sind im gebauten Stand gegen den Mock-OIDC geprueft
(pnpm test:e2e): Admin, Konto ohne Gruppe, Notfall-Admin mit TOTP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:28:51 +02:00
florian.wilde 4d0044b380 Merge branch 'phase/002-design-layout' 2026-10-12 09:21:46 +02:00
florian.wilde a2bdd9f205 Merge branch 'phase/007-worker-vorgaenge' 2026-10-12 09:21:41 +02:00
florian.wilde 63a378df8f Merge branch 'phase/006-geheimnisse-schluesselformat' (Kern) 2026-10-12 09:21:41 +02:00
florian.wildeandClaude Opus 5.5 4a23930b54 feat(worker): Worker mit pg-boss, Vorgaenge und Docker-Betrieb (#007)
Die Oberflaeche legt einen Vorgang an und schickt nur dessen ID in die
Warteschlange; der Worker fuehrt ihn aus und haelt Status, Ergebnis
oder Fehler fest. So bleiben lange SSH-Vorgaenge aus dem Webprozess
heraus, und der Fortschritt ist ohne Job-Interna sichtbar.

Kein automatisches Wiederholen: ein halb ausgefuehrter Schreibvorgang
auf einem Host gehoert vor einen Menschen. Fehlertexte aus fremden
Bibliotheken erreichen die Oberflaeche nie.

Dockerfile und Compose fuer den Betrieb: Master-Key als Secret nur im
Worker, Datenbank in einem internen Netz.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:21:41 +02:00
florian.wildeandClaude Opus 5.5 88b5697cc9 feat(ui): Design-Tokens, Schriften und Datumsformate (#002)
Die Farben des Tresor-Designs stehen als CSS-Variablen in :root und
werden per @theme inline an Tailwind gereicht, damit Inline-SVGs und
Utility-Klassen dieselbe Quelle nutzen. Schriften kommen selbst gehostet
aus @fontsource, nur in den benutzten Gewichten und im Latin-Ausschnitt.

src/lib/format.ts rechnet fest in Europe/Berlin: der Server laeuft im
Container auf UTC, die Anzeige soll aber ueberall dieselbe Ortszeit
zeigen. relativ() nimmt den Bezugspunkt als Parameter, damit statische
Seiten und Tests deterministisch bleiben.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:20:22 +02:00
florian.wilde bfa0d574aa Merge branch 'phase/004-anmeldung-rollen' (Logik) 2026-10-12 09:17:57 +02:00
florian.wilde 792bdd54ce Merge branch 'phase/011-test-ssh-container' 2026-10-12 09:17:48 +02:00
florian.wildeandClaude Opus 5.5 5ef90310e1 feat(auth): Anmeldung per OIDC und Notfall-Admin mit TOTP (#004)
Sitzung, OIDC-Fluss und Rueckruf aus Laufzettel uebernommen und auf
sshkv angepasst. Abweichungen mit Absicht:

- Ohne passende sshkv-Gruppe gibt es keinen Zugang, auch keinen
  Lesezugriff: schon die Hostliste verraet, wer wohin darf.
- Notfall-Admin nur mit TOTP (Freigabe Frage 5). Ein richtiges
  Passwort fuehrt beim ersten Mal nur zur Einrichtung. Jeder Code gilt
  einmal, fuenf Fehlversuche sperren 15 Minuten.
- Kritische Rechte verlangen eine Bestaetigung, die hoechstens fuenf
  Minuten alt ist. Bei OIDC mit prompt=login, max_age=0 und Pruefung
  von auth_time, sonst zaehlte eine laufende SSO-Sitzung als Beweis.
- Sitzungen laufen acht statt zwoelf Stunden.

Die Seiten folgen, sobald das Design-System (#002) steht.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:17:44 +02:00
florian.wildeandClaude Opus 5.5 d359b7d4c3 feat: Geheimnisse vor Log und Protokoll schwaerzen (#006)
Private Keys, Passwoerter und Tokens duerfen nie in Log oder Protokoll
landen (CLAUDE.md). Ein Netz ueber Feldnamen allein reicht nicht: Ein Key
kann in einer Fehlermeldung oder einem Stacktrace stecken, ohne dass das
Feld danach heisst. Deshalb schwaerzt `schwaerzen` sowohl Felder mit
verdaechtigen Namen (irgendwo im Namen, nicht nur am Anfang) als auch
jeden PEM-Private-Key in beliebigen Zeichenketten, auch abgeschnittene.

Der Helfer ist framework-frei und wird mit dem Logger und dem Protokoll
eingebaut.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:17:34 +02:00
florian.wildeandClaude Opus 5.5 893b840f06 feat: Envelope Encryption und Master-Key aus Datei (#006)
Private Keys liegen spaeter verschluesselt in PostgreSQL. Ein eigener DEK
je Geheimnis erlaubt eine Master-Key-Rotation, ohne die Chiffrate selbst
anzufassen; das AAD (Schluessel-ID und Fingerprint) bindet jedes Chiffrat
an seinen Datensatz, sodass vertauschte Zeilen beim Oeffnen auffallen
statt einen fremden Key zu liefern. Die Master-Key-Version steckt im AAD
des DEK.

masterKeyLaden akzeptiert roh, Base64 und Hex, weil `openssl rand` der
naheliegende Weg zum Anlegen ist, und bricht ab, wenn Gruppe oder Welt
die Datei lesen duerfen – ein lesbarer Master-Key oeffnet alle Private
Keys. SSHKV_MASTER_KEY_UNSICHER_ERLAUBT=1 erlaubt das bewusst.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:16:56 +02:00
florian.wildeandClaude Opus 5.5 6b20566676 feat: OpenSSH-Schluessel erzeugen, schreiben und lesen (#006)
Private Keys sollen nie als Datei auf dem sshkv-Server liegen, auch nicht
kurz. ssh-keygen braucht aber genau das. Deshalb erzeugt Node crypto die
Schluessel (ed25519, RSA-4096), und ein eigener Serializer schreibt das
Format openssh-key-v1 – unverschluesselt oder mit aes256-ctr und
bcrypt_pbkdf (16 Runden, 16 Byte Salt), Checkint und Padding wie OpenSSH.

Der Parser liest auch von ssh-keygen erzeugte Dateien, prueft, dass
Private und Public Key zusammengehoeren, und meldet fehlende oder falsche
Passphrasen ueber eigene Codes. Fehlermeldungen sind feste Saetze ohne
Eingabe darin, damit kein Schluesselmaterial in Logs geraet. RSA unter
2048 Bit wird beim Import abgelehnt; wer nur beobachtet, kann die Grenze
ausschalten.

Die Tests pruefen beide Richtungen gegen das echte ssh-keygen (-y, -lf).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:16:42 +02:00
florian.wildeandClaude Opus 5.5 e89112a761 test: SSH-Testziele und Mock-OIDC fuer Integrationstests (#011)
Bootstrap, Host-Key-Pruefung und spaeteres Ausrollen brauchen echte
sshd-Gegenstellen. Zwei Debian-13-Container (ziel-a, ziel-b) in einem
gemeinsamen Netz bilden frische Hosts vor dem Bootstrap nach: root- und
Passwort-Login sind absichtlich offen, Host-Keys entstehen erst beim
Start, und `hostkeys-tauschen` erlaubt den Test "geaenderter Host-Key
wird abgelehnt" ohne Neuerstellen des Containers.

Die Testhilfen lesen dieselben Adress-Variablen wie die Compose-Datei
und lassen Tests mit Hinweis auf den Startbefehl fehlschlagen, statt
sie still zu ueberspringen - ein uebersprungener Integrationstest sieht
sonst wie ein bestandener aus.

Der Mock-OIDC-Anbieter ersetzt authentik in der Entwicklung (PLAN.md,
Entscheidung 7). Bei interaktivem Login uebernimmt er nur Claims aus dem
Formular, daher belegt eine eigene Login-Seite email, name und groups
vor und laesst die Gruppen frei waehlen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:13:56 +02:00
florian.wildeandClaude Opus 5.5 03c7c45576 feat(datenbank): Datenmodell mit Datenbankregeln und Seed (#003)
Alle Modelle fuer die fuenf Phasen in einer Migration, damit spaetere
Phasen keine Umbauten an Kerntabellen brauchen. Was auch an der
Service-Schicht vorbei gelten muss, steht als CHECK, partieller Index
oder Trigger in der Datenbank: Personen-Keys ohne Private Key, genau
ein Instanz-Deployment-Key, ein vertrauter Host-Key je Algorithmus,
shell-sichere Zielbenutzer und Pfade.

Das Protokoll ist append-only und per Hash-Kette verbunden; den Hash
berechnet ein Trigger, damit keine Zeile ohne Verkettung entstehen
kann (#005 baut darauf auf).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:12:06 +02:00
florian.wildeandClaude Opus 5.5 cef9510f18 chore: Projektgeruest mit Next.js 16, Prisma 7 und pnpm (#001)
Konfiguration aus Laufzettel uebernommen, damit alle Projekte gleich
gebaut und geprueft werden. Entwicklungsdatenbank auf 5436, weil 5433
und 5434 von ProxLedger und Laufzettel belegt sind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 09:05:15 +02:00