Scenarij 11.3: Rotacija ključeva

Kategorija: Upravljanje ključevima
Složenost: ⭐⭐⭐⭐ (Visoka)
Preduvjeti: Postojeći ključevi, strategija sigurnosnog kopiranja
Procijenjeno vrijeme: 30-45 minuta


Opis

Ovaj scenarij opisuje redovitu rotaciju kriptografskih ključeva. Rotacija ključeva je kritična sigurnosna mjera koja ograničava rizik kompromitacije.

Razlozi za rotaciju:

  • Vremenski - Dosegnuta maksimalna životna dob ključa
  • Količinski - Maksimalan broj operacija/volumen podataka
  • Sigurnosni incident - Sumnja na kompromitaciju
  • Usklađenost - Regulatorni zahtjevi
  • Nadogradnja algoritma - Migracija na jače algoritme

Tijek rada

flowchart TD TRIGGER[Okidač rotacije] --> CHECK{Rotacija potrebna?} CHECK -->|Ne| WAIT[Čekanje] CHECK -->|Da| BACKUP[Sigurnosna kopija starog ključa] BACKUP --> GEN[Generiranje novog ključa] GEN --> MIGRATE[Migracija sustava] MIGRATE --> TEST[Funkcionalni test] TEST --> OVERLAP{Preklapanje OK?} OVERLAP -->|Da| RETIRE[Deaktivacija starog ključa] OVERLAP -->|Ne| ROLLBACK[Rollback] RETIRE --> ARCHIVE[Arhiviranje/Brisanje] style GEN fill:#e8f5e9 style BACKUP fill:#fff3e0


Primjer koda: Automatska rotacija

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);
 
        // Provjera uvjeta za rotaciju
        var needsRotation = ShouldRotate(metadata);
 
        if (!needsRotation.Required)
        {
            return new RotationResult
            {
                KeyId = keyId,
                Rotated = false,
                Reason = "Rotacija nije potrebna"
            };
        }
 
        return await PerformRotationAsync(keyId, metadata, needsRotation.Reason);
    }
 
    private RotationCheck ShouldRotate(KeyMetadata metadata)
    {
        // 1. Vremenska rotacija
        if (DateTime.UtcNow - metadata.CreatedAt > _maxKeyAge)
        {
            return new RotationCheck(true, "Dosegnuta maksimalna starost");
        }
 
        // 2. Količinska rotacija
        if (metadata.OperationCount > _maxOperations)
        {
            return new RotationCheck(true, "Dosegnut maksimalni broj operacija");
        }
 
        // 3. Nadogradnja algoritma (RSA → ML-DSA)
        if (metadata.Algorithm.StartsWith("RSA") && !metadata.Algorithm.Contains("ML-DSA"))
        {
            return new RotationCheck(true, "Potrebna PQ-migracija");
        }
 
        return new RotationCheck(false, null);
    }
 
    private async Task<RotationResult> PerformRotationAsync(
        string keyId,
        KeyMetadata oldMetadata,
        string reason)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // 1. Sigurnosna kopija starog ključa
        await _keyStore.BackupAsync(keyId);
 
        // 2. Generiranje novog ključa
        var newKeyId = $"{keyId}-{DateTime.UtcNow:yyyyMMdd}";
        using var newKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
 
        // 3. Pohrana novog ključa
        await _keyStore.StoreAsync(newKeyId, newKey, new KeyMetadata
        {
            Algorithm = "ML-DSA-65",
            CreatedAt = DateTime.UtcNow,
            PreviousKeyId = keyId,
            RotationReason = reason
        });
 
        // 4. Označavanje starog ključa kao "u rotaciji"
        await _keyStore.SetStatusAsync(keyId, KeyStatus.Rotating);
 
        return new RotationResult
        {
            KeyId = keyId,
            NewKeyId = newKeyId,
            Rotated = true,
            Reason = reason
        };
    }
}

Primjer koda: Faza preklapanja

public class OverlappingKeyManager
{
    public async Task<byte[]> SignWithOverlap(
        byte[] data,
        string keyId,
        IKeyStore keyStore)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // Učitavanje trenutnog ključa
        var currentKey = await keyStore.GetCurrentKeyAsync(keyId);
 
        // Potpisivanje s trenutnim ključem
        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();
 
        // Dohvaćanje svih valjanih verzija ključa
        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)
            {
                // Pogrešan ključ, pokušaj sljedeći
                continue;
            }
        }
 
        return false;
    }
}

Primjer koda: HashiCorp Vault rotacija

public class VaultKeyRotation
{
    private readonly IVaultClient _vault;
 
    public async Task RotateKeyInVault(string keyPath)
    {
        // 1. Dohvaćanje trenutne verzije
        var current = await _vault.V1.Secrets.KeyValue.V2.ReadSecretAsync(
            path: keyPath,
            mountPoint: "secret"
        );
 
        var currentVersion = current.Data.Metadata.Version;
 
        // 2. Generiranje novog ključa
        using var ctx = PqCryptoContext.Initialize();
        using var newKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
 
        // 3. Spremanje kao nova verzija (stara ostaje sačuvana)
        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($"Ključ rotiran: {keyPath} v{currentVersion} → v{currentVersion + 1}");
    }
 
    public async Task DestroyOldVersions(string keyPath, int keepVersions = 3)
    {
        // Brisanje starih verzija (Vault zadržava metapodatke)
        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($"Stare verzije izbrisane: {string.Join(", ", versionsToDestroy)}");
        }
    }
}

Smjernice za rotaciju

Tip ključa Maks. starost Maks. operacije Preklapanje
Root-CA ključ 10-20 godina N/A 1 godina
Intermediate-CA ključ 3-5 godina N/A 90 dana
TLS serverski ključ 1 godina 10M rukovanja 7 dana
Code Signing ključ 2 godine 100K potpisa 30 dana
Ključ za šifriranje 1 godina 100TB podataka 30 dana

Zahtjevi za rotaciju specifični za industriju

Industrija Ciklus rotacije Zahtjev Posebnost
Financijski sektor 1 godina PCI-DSS 3.6.4 Obvezni Audit-Trail
Zdravstvo 2 godine HIPAA Key Escrow
Energetika/KRITIS 3 godine BSI KRITIS-VO Prozor održavanja
Vlada 2 godine BSI TR-03116 Obvezni HSM

Povezani scenariji

Povezanost Scenarij Opis
Preduvjet 11.2 Pohrana ključeva Sigurno čuvanje
Preduvjet 11.4 Sigurnosna kopija ključeva Sigurnosna kopija prije rotacije
Sljedeći korak 11.5 Uništavanje ključeva Brisanje starih ključeva
Povezano 4.2 Rekey Certifikat s novim ključem

« ← 11.2 Pohrana ključeva | ↑ Pregled ključeva | 11.4 Sigurnosna kopija ključeva → »


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

Zuletzt geändert: 30.01.2026. u 00:29