~~NOTOC~~
====== Szenario 11.3: Schlüssel-Rotation ======
**Kategorie:** [[.:start|Schlüsselmanagement]] \\
**Komplexität:** ⭐⭐⭐⭐ (Hoch) \\
**Voraussetzungen:** Bestehende Schlüssel, Backup-Strategie \\
**Geschätzte Zeit:** 30-45 Minuten
----
===== Beschreibung =====
Dieses Szenario beschreibt die **regelmäßige Rotation kryptographischer Schlüssel**. Schlüssel-Rotation ist eine kritische Sicherheitsmaßnahme, die das Risiko einer Kompromittierung begrenzt.
**Rotations-Gründe:**
* **Zeitbasiert** - Maximale Schlüssel-Lebensdauer erreicht
* **Nutzungsbasiert** - Maximale Operationen/Datenvolumen
* **Sicherheitsvorfall** - Verdacht auf Kompromittierung
* **Compliance** - Regulatorische Anforderungen
* **Algorithmus-Upgrade** - Migration zu stärkeren Algorithmen
----
===== Workflow =====
flowchart TD
TRIGGER[Rotations-Trigger] --> CHECK{Rotation nötig?}
CHECK -->|Nein| WAIT[Warten]
CHECK -->|Ja| BACKUP[Alten Key sichern]
BACKUP --> GEN[Neuen Key generieren]
GEN --> MIGRATE[Systeme migrieren]
MIGRATE --> TEST[Funktionstest]
TEST --> OVERLAP{Überlappung OK?}
OVERLAP -->|Ja| RETIRE[Alten Key deaktivieren]
OVERLAP -->|Nein| ROLLBACK[Rollback]
RETIRE --> ARCHIVE[Archivieren/Löschen]
style GEN fill:#e8f5e9
style BACKUP fill:#fff3e0
----
===== Code-Beispiel: Automatische Rotation =====
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
public class KeyRotationService
{
private readonly IKeyStore _keyStore;
private readonly TimeSpan _maxKeyAge = TimeSpan.FromDays(365);
private readonly long _maxOperations = 1_000_000;
public KeyRotationService(IKeyStore keyStore)
{
_keyStore = keyStore;
}
public async Task CheckAndRotateAsync(string keyId)
{
var metadata = await _keyStore.GetMetadataAsync(keyId);
// Rotations-Bedingungen prüfen
var needsRotation = ShouldRotate(metadata);
if (!needsRotation.Required)
{
return new RotationResult
{
KeyId = keyId,
Rotated = false,
Reason = "Keine Rotation erforderlich"
};
}
return await PerformRotationAsync(keyId, metadata, needsRotation.Reason);
}
private RotationCheck ShouldRotate(KeyMetadata metadata)
{
// 1. Zeitbasierte Rotation
if (DateTime.UtcNow - metadata.CreatedAt > _maxKeyAge)
{
return new RotationCheck(true, "Maximales Alter erreicht");
}
// 2. Nutzungsbasierte Rotation
if (metadata.OperationCount > _maxOperations)
{
return new RotationCheck(true, "Maximale Operationen erreicht");
}
// 3. Algorithmus-Upgrade (RSA → ML-DSA)
if (metadata.Algorithm.StartsWith("RSA") && !metadata.Algorithm.Contains("ML-DSA"))
{
return new RotationCheck(true, "PQ-Migration erforderlich");
}
return new RotationCheck(false, null);
}
private async Task PerformRotationAsync(
string keyId,
KeyMetadata oldMetadata,
string reason)
{
using var ctx = PqCryptoContext.Initialize();
// 1. Alten Schlüssel sichern
await _keyStore.BackupAsync(keyId);
// 2. Neuen Schlüssel generieren
var newKeyId = $"{keyId}-{DateTime.UtcNow:yyyyMMdd}";
using var newKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
// 3. Neuen Schlüssel speichern
await _keyStore.StoreAsync(newKeyId, newKey, new KeyMetadata
{
Algorithm = "ML-DSA-65",
CreatedAt = DateTime.UtcNow,
PreviousKeyId = keyId,
RotationReason = reason
});
// 4. Alten Schlüssel als "rotating" markieren
await _keyStore.SetStatusAsync(keyId, KeyStatus.Rotating);
return new RotationResult
{
KeyId = keyId,
NewKeyId = newKeyId,
Rotated = true,
Reason = reason
};
}
}
----
===== Code-Beispiel: Überlappungsphase =====
public class OverlappingKeyManager
{
public async Task SignWithOverlap(
byte[] data,
string keyId,
IKeyStore keyStore)
{
using var ctx = PqCryptoContext.Initialize();
// Aktuellen Schlüssel laden
var currentKey = await keyStore.GetCurrentKeyAsync(keyId);
// Mit aktuellem Schlüssel signieren
var signature = ctx.SignData(
data,
currentKey,
HashAlgorithmName.SHA256
);
return signature;
}
public async Task VerifyWithOverlap(
byte[] data,
byte[] signature,
string keyId,
IKeyStore keyStore)
{
using var ctx = PqCryptoContext.Initialize();
// Alle gültigen Schlüssel-Versionen holen
var validKeys = await keyStore.GetValidKeysAsync(keyId);
foreach (var key in validKeys)
{
try
{
if (ctx.VerifyData(data, signature, key.PublicKey, HashAlgorithmName.SHA256))
{
return true;
}
}
catch (CryptographicException)
{
// Falscher Schlüssel, nächsten versuchen
continue;
}
}
return false;
}
}
----
===== Code-Beispiel: HashiCorp Vault Rotation =====
public class VaultKeyRotation
{
private readonly IVaultClient _vault;
public async Task RotateKeyInVault(string keyPath)
{
// 1. Aktuelle Version abrufen
var current = await _vault.V1.Secrets.KeyValue.V2.ReadSecretAsync(
path: keyPath,
mountPoint: "secret"
);
var currentVersion = current.Data.Metadata.Version;
// 2. Neuen Schlüssel generieren
using var ctx = PqCryptoContext.Initialize();
using var newKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
// 3. Als neue Version speichern (alte bleibt erhalten)
var secretData = new Dictionary
{
["privateKey"] = Convert.ToBase64String(newKey.ExportPkcs8()),
["publicKey"] = Convert.ToBase64String(newKey.PublicKey.Export()),
["algorithm"] = "ML-DSA-65",
["rotatedAt"] = DateTime.UtcNow.ToString("O"),
["previousVersion"] = currentVersion
};
await _vault.V1.Secrets.KeyValue.V2.WriteSecretAsync(
path: keyPath,
data: secretData,
mountPoint: "secret"
);
Console.WriteLine($"Schlüssel rotiert: {keyPath} v{currentVersion} → v{currentVersion + 1}");
}
public async Task DestroyOldVersions(string keyPath, int keepVersions = 3)
{
// Alte Versionen löschen (Vault behält Metadaten)
var metadata = await _vault.V1.Secrets.KeyValue.V2.ReadSecretMetadataAsync(
path: keyPath,
mountPoint: "secret"
);
var currentVersion = metadata.Data.CurrentVersion;
var versionsToDestroy = new List();
for (int v = 1; v < currentVersion - keepVersions; v++)
{
versionsToDestroy.Add(v);
}
if (versionsToDestroy.Any())
{
await _vault.V1.Secrets.KeyValue.V2.DestroySecretVersionsAsync(
path: keyPath,
versions: versionsToDestroy,
mountPoint: "secret"
);
Console.WriteLine($"Alte Versionen gelöscht: {string.Join(", ", versionsToDestroy)}");
}
}
}
----
===== Rotations-Richtlinien =====
^ Schlüsseltyp ^ Max. Alter ^ Max. Operationen ^ Überlappung ^
| **Root-CA Key** | 10-20 Jahre | N/A | 1 Jahr |
| **Intermediate-CA Key** | 3-5 Jahre | N/A | 90 Tage |
| **TLS Server Key** | 1 Jahr | 10M Handshakes | 7 Tage |
| **Code Signing Key** | 2 Jahre | 100K Signaturen | 30 Tage |
| **Encryption Key** | 1 Jahr | 100TB Daten | 30 Tage |
----
===== Branchenspezifische Rotations-Anforderungen =====
^ Branche ^ Rotationszyklus ^ Anforderung ^ Besonderheit ^
| **Finanzsektor** | 1 Jahr | PCI-DSS 3.6.4 | Audit-Trail Pflicht |
| **Healthcare** | 2 Jahre | HIPAA | Key Escrow |
| **Energie/KRITIS** | 3 Jahre | BSI KRITIS-VO | Wartungsfenster |
| **Behörden** | 2 Jahre | BSI TR-03116 | HSM-Pflicht |
----
===== Verwandte Szenarien =====
^ Beziehung ^ Szenario ^ Beschreibung ^
| **Voraussetzung** | [[.:speicherung|11.2 Schlüsselspeicherung]] | Sichere Aufbewahrung |
| **Voraussetzung** | [[.:backup|11.4 Schlüssel-Backup]] | Vor Rotation sichern |
| **Nächster Schritt** | [[.:vernichtung|11.5 Schlüsselvernichtung]] | Alte Keys löschen |
| **Verwandt** | [[de:int:pqcrypt:szenarien:verwaltung:rekey|4.2 Rekey]] | Zertifikat mit neuem Key |
----
<< [[.:speicherung|← 11.2 Schlüsselspeicherung]] | [[.:start|↑ Schlüssel-Übersicht]] | [[.:backup|11.4 Schlüssel-Backup →]] >>
{{tag>szenario schluessel rotation lifecycle compliance}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//