Szenario 11.3: Schlüssel-Rotation

Kategorie: 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:


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<RotationResult> 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<RotationResult> 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<byte[]> 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<bool> 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<string, object>
        {
            ["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<int>();
 
        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 11.2 Schlüsselspeicherung Sichere Aufbewahrung
Voraussetzung 11.4 Schlüssel-Backup Vor Rotation sichern
Nächster Schritt 11.5 Schlüsselvernichtung Alte Keys löschen
Verwandt 4.2 Rekey Zertifikat mit neuem Key

« ← 11.2 Schlüsselspeicherung | ↑ Schlüssel-Übersicht | 11.4 Schlüssel-Backup → »


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional