feat(schluessel): Private Key anzeigen, herunterladen, loeschen (#014)
Admins koennen einen gespeicherten Private Key nach frischer Bestaetigung einmalig anzeigen oder als Datei <slug> herunterladen und ihn endgueltig aus SSHKeyVault loeschen. Warum so: - Der Web-Prozess hat keinen Master-Key. Er bittet den Worker per Vorgang, den Key zu oeffnen; der legt ihn mit SSHKV_APP_SECRET verschluesselt in Vorgang.ergebnis ab. Das Web holt ihn genau einmal ab: ein einziges UPDATE unter Zeilensperre liest und ueberschreibt. - Nicht abgeholte Keys verfallen nach zwei Minuten: Worker-Takt alle 30 s, Aufraeumen vor jeder Abholung, und das Web gibt aeltere nicht mehr heraus. Die Status-Schnittstelle zeigt nur "bereit". - Download nur per POST (ein GET-Link oder Vorabruf wuerde die Abholung verbrauchen), no-store, Herkunft per Sec-Fetch-Site, weil no-referrer bei Formular-POSTs Origin: null sendet. - Loeschen laeuft als Worker-Vorgang, damit nur geheimnisse.ts die Chiffrat-Felder anfasst; eigenes Recht privateKeyLoeschen mit Bestaetigung. Deployment-Keys gibt sshkv weder heraus noch loescht es sie. - Protokoll: angefordert, angezeigt, heruntergeladen, geloescht - mit Fingerprint, nie mit Key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import { darf } from "@/server/auth/rechte";
|
||||
import { sitzungErforderlich } from "@/server/auth/sitzungspflicht";
|
||||
import { schluesselDetail, type SchluesselDetail } from "@/server/queries/schluessel";
|
||||
import { PrivateAusrollenAktion } from "./PrivateAusrollenAktion";
|
||||
import { PrivateKeyAnzeigen, PrivateKeyLoeschen } from "./PrivateKeyAktionen";
|
||||
import { PublicAusrollenAktion } from "./PublicAusrollenAktion";
|
||||
|
||||
export const metadata: Metadata = { title: "Schlüssel" };
|
||||
@@ -160,6 +161,10 @@ export default async function SchluesselSeite({ params }: { params: Promise<{ id
|
||||
const aktiv = s.status === "AKTIV";
|
||||
const personenKey = s.kategorie === "PERSON";
|
||||
const verwalten = darf(benutzer.rolle, "schluesselVerwalten");
|
||||
// Den Deployment-Key gibt sshkv nie heraus (#014) – Knoepfe dafuer erscheinen gar nicht erst.
|
||||
const privatHerausgebbar = s.privatGespeichert && s.kategorie !== "DEPLOYMENT";
|
||||
const darfAnzeigen = privatHerausgebbar && darf(benutzer.rolle, "privateKeyAnzeigen");
|
||||
const darfLoeschen = privatHerausgebbar && darf(benutzer.rolle, "privateKeyLoeschen");
|
||||
const jetzt = new Date();
|
||||
|
||||
return (
|
||||
@@ -216,7 +221,17 @@ export default async function SchluesselSeite({ params }: { params: Promise<{ id
|
||||
</span>
|
||||
</InfoFeld>
|
||||
<InfoFeld titel="Private Key">
|
||||
<PrivatStatus s={s} />
|
||||
<PrivatStatus
|
||||
s={s}
|
||||
anzeigen={
|
||||
darfAnzeigen && (
|
||||
<>
|
||||
<span aria-hidden>·</span>
|
||||
<PrivateKeyAnzeigen schluesselId={s.id} name={s.name} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</InfoFeld>
|
||||
</dl>
|
||||
</Karte>
|
||||
@@ -280,6 +295,18 @@ export default async function SchluesselSeite({ params }: { params: Promise<{ id
|
||||
>
|
||||
<MonoBlock wert={s.publicKey} beschriftung="Public Key" umbrechen />
|
||||
</Karte>
|
||||
|
||||
{darfLoeschen && (
|
||||
<Karte titel="Private Key löschen" untertitel="Nur noch auf den Hosts, nicht mehr in SSHKeyVault">
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<p className="text-muted max-w-xl text-[14px]">
|
||||
Sinnvoll, sobald der Private Key ausgerollt ist und sshkv ihn nicht mehr braucht. Danach kann
|
||||
ihn niemand mehr aus SSHKeyVault holen – auch kein Admin.
|
||||
</p>
|
||||
<PrivateKeyLoeschen schluesselId={s.id} name={s.name} />
|
||||
</div>
|
||||
</Karte>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user