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