~~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//