Schlüssel und Rollover
TL;DR – Regel 4 des Rollenmodells: Schlüssel bestimmen, was Sie öffnen können — nie, was Sie senden dürfen. Beide SDKs akzeptieren eine geordnete Liste privater Entschlüsselungs-Schlüssel; so rotieren Sie Zertifikate, ohne dass unterwegs befindliche Anträge unlesbar werden.
Drei Schlüssel, drei Besitzer
| Schlüssel | Wer hält ihn | Wofür | Öffentliche Hälfte liegt … |
|---|---|---|---|
| Entschlüsselungsschlüssel (RSA-4096, RSA-OAEP-256) | Zustellpunkt A/B | Anträge öffnen | im Self-Service-Portal; Absender holen sie aus dem Directory |
| Signaturschlüssel (PS512) | Zustellpunkt A/B | Events (accept, reject, Replies) signieren | im Self-Service-Portal; Empfänger von Events prüfen damit die Signatur |
| Rückkanalschlüssel | Onlinedienst C, pro Vorgang | Antworten öffnen | reist im Antrag mit (ReplyChannel) |
Ein reiner Sender braucht keinen einzigen davon: Zum Verschlüsseln holt sich das SDK den öffentlichen Schlüssel des Empfängers selbst.
Produktivschlüssel gehören in ein HSM oder einen Vault, nicht neben die Credentials in eine Datei.
Java zieht daraus die Konsequenz, dass Schlüssel gar kein Teil der SDK-Konfiguration sind:
Sie übergeben sie beim Erzeugen der Rolle — sdk.organisation(id, keys) — und können sie damit
jederzeit aus einer beliebigen Quelle laden. .NET ist DI-zentriert: Die Schlüssel stehen als
JWK-JSON in FitConnect.Client, und der Vault ist ein IConfiguration-Provider (Azure Key Vault,
User Secrets, Umgebungsvariablen) — die Konfigurationsdatei selbst enthält nur Platzhalter.
Schlüssel bereitstellen
- Java
- .NET (C#)
DestinationKeys nimmt die Entschlüsselungs-Schlüssel als Liste, neuester zuerst; jede
eingehende Nachricht wird der Reihe nach gegen jeden Schlüssel geprüft:
List<JWK> decryptionKeys = List.of(
vault.loadJwk("fit-connect/decrypt-current"),
vault.loadJwk("fit-connect/decrypt-previous")
);
DestinationKeys keys = new DestinationKeys(decryptionKeys, signatureKey);
Organisation organisation = sdk.organisation(myDestinationId, keys);
Einen einzelnen Schlüssel übergeben Sie mit new DestinationKeys(decryptionJwk, signatureJwk),
einen reinen Sender mit DestinationKeys.none(). Wollen Sie die Schlüssel dennoch in einer
eigenen YAML-Sektion pflegen, ist DestinationKeysDeserializer.fromNode(...) derselbe Baustein,
den auch das identity:-Element der Kommandozeile nutzt.
Testschlüssel erzeugen Sie mit dem SDK selbst (RSA-4096):
JWKPair pair = EncryptionKeyPairGenerator.generate("mein-key-id");
pair.publicKey(); // ins Portal hochladen
pair.privateKey(); // in den Vault
{
"FitConnect": {
"EnvironmentTag": "PROD",
"Client": {
"ClientId": "<client-id>",
"ClientSecret": "<client-secret>",
"DestinationId": "<eigene destination-uuid>",
"DecryptionKeys": [
"{ \"kty\": \"RSA\", \"kid\": \"current\", ... }",
"{ \"kty\": \"RSA\", \"kid\": \"previous\", ... }"
],
"SignatureKey": "{ \"kty\": \"RSA\", ... }"
}
}
}
Die DecryptionKeys-Liste ist geordnet: Der erste Eintrag ist der aktive Schlüssel,
Folgeeinträge werden beim Entschlüsseln durchprobiert. Für einen reinen Sender bleibt die Liste
leer und SignatureKey entfällt. In Produktion befüllen Sie die Werte aus einem Secret-Store —
mit dotnet user-secrets lokal und einem Vault-Provider im Betrieb:
dotnet user-secrets set "FitConnect:Client:DecryptionKeys:0" "$(cat decrypt-current.jwk)"
dotnet user-secrets set "FitConnect:Client:SignatureKey" "$(cat signature.jwk)"
Rollover ohne Ausfall
- Neues Schlüsselpaar B erzeugen; die öffentliche Hälfte im Self-Service-Portal hinterlegen. Ab jetzt verschlüsseln neue Anträge mit B.
- Liste im SDK auf
[B, A]stellen — B ist aktiv, A bleibt zum Entschlüsseln älterer Anträge. - Warten, bis keine mit A verschlüsselten Anträge mehr anliegen. Orientierung geben die Löschfristen der Plattform.
- A aus der Liste entfernen.
Das SDK wählt den Schlüssel anhand des kid im JWE-Header; passt keiner, landet das als Fehler im
Prüfbericht — die Submission wird nicht automatisch abgelehnt.
Rückkanalschlüssel: pro Vorgang, nicht pro Zustellpunkt
Der Rückkanalschlüssel gehört zu einem Vorgang. Deshalb nimmt das SDK beim Lesen von Antworten
keinen Schlüssel, sondern eine Nachschlagefunktion: Java ReplyKeys (ein funktionales
Interface — vault::find reicht), .NET IReplyKeys (ReplyKeys.FromLookup(vault.Find) oder
ReplyKeys.Of(dictionary)). Wie Sie den privaten Schlüssel beim Senden ablegen und beim Lesen
wiederfinden, zeigt Antworten senden und lesen.
Best Practices
- Halten Sie maximal zwei Schlüsselversionen aktiv — das vereinfacht das Auditing.
- Dokumentieren Sie Rotationszeitpunkte in Ihrer Betriebsdokumentation.
- Hinterlegen Sie den neuen öffentlichen Schlüssel im Portal, bevor Sie den privaten Schlüssel an die erste Stelle der Liste setzen.
- Rückkanalschlüssel sind Ephemeral Keys ohne V-PKI-Zertifikat — nur für Antworten innerhalb eines Vorgangs, nie zum Einrichten eines Zustellpunkts.
Weiter geht's
- Rezept: Einrichten — Schlüssel beim Erzeugen der Rolle übergeben
- Zertifikate und JWKs erzeugen
- Zustellpunkte verwalten — öffentliche Schlüssel per API hinterlegen