Müşteri ödeme verileri işleyen bir SaaS müşterimizin denetimi PCI DSS uyumu istiyordu. Mevcut sistem: API key’ler appsettings.json’da plaintext, database password environment variable’da, TLS sertifikaları manuel rotate. 4 ay süren projede Azure Key Vault Premium ile baştan kurguladık. Bu yazı o projeden notlar.
Standard vs Premium SKU
| Özellik | Standard | Premium |
|---|---|---|
| Aylık baz ücret | $0 (transaction bazlı) | $1/HSM-protected key + transaction |
| Transaction fiyat | $0.03/10K | $0.03/10K |
| Software-protected keys | Var | Var |
| HSM-protected keys (FIPS 140-2 Level 3) | Yok | Var |
| Compliance | SOC, ISO | + FIPS 140-2 Level 3, PCI |
PCI DSS, FIPS 140-2 Level 3 HSM gerektiriyor. Premium şart.
Üç Tip Asset
- Secrets: Database password, API key, connection string. Plain string olarak saklanır, base64 encoded.
- Keys: Cryptographic keys (RSA, EC). Sign, verify, encrypt, decrypt, wrap, unwrap operasyonları için. Private key Key Vault’tan dışarı çıkmaz; tüm operasyonlar Key Vault içinde.
- Certificates: TLS sertifikaları. Otomatik renewal (Let’s Encrypt, public CA, internal CA).
Authentication: Managed Identity Şart
Eski yöntem: Service principal credentials → secret olarak başka bir yere yazılıyor → Key Vault’a auth → secret çekiliyor. Sonsuz döngü.
Modern yaklaşım: Managed Identity. App Service / Function App / VM / AKS’in identity’si Key Vault’a “Key Vault Secrets User” RBAC role’üyle yetkilenir, kod hiç secret saklamadan çekiyor.
// .NET 8 örneği
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
var client = new SecretClient(
vaultUri: new Uri("https://kv-saas-prod.vault.azure.net"),
credential: new DefaultAzureCredential() // Managed Identity otomatik kullanılır
);
KeyVaultSecret dbPassword = await client.GetSecretAsync("DbPassword");
string connectionString = $"Server=sql-prod;Database=app;User=app;Password={dbPassword.Value};";
DefaultAzureCredential local’de Visual Studio / Azure CLI credential, production’da managed identity kullanır. Aynı kod farklı ortamlarda çalışır.
RBAC vs Access Policy
Key Vault’un eskiden kendi access policy modeli vardı. Artık Azure RBAC önerilen yaklaşım. Granüler roller:
- Key Vault Administrator: Tam yetki (sadece yöneticiler).
- Key Vault Secrets Officer: Secret CRUD.
- Key Vault Secrets User: Sadece read (uygulama identity’leri).
- Key Vault Crypto Officer: Key CRUD.
- Key Vault Crypto User: Sign/verify/encrypt/decrypt.
- Key Vault Certificate Officer: Certificate CRUD.
SaaS müşterimizde uygulama identity’lerine sadece “Secrets User” rolü, yöneticilere “Administrator”. Geliştiriciler dev key vault’a “Secrets Officer”, production key vault’a sadece read.
Automated Secret Rotation
Key Vault, Event Grid + Function App pattern’iyle otomatik rotation destekliyor. Database password rotation örneği:
# Rotation policy tanımla
az keyvault secret set-attributes
--vault-name kv-saas-prod
--name "DbPassword"
--expires "2026-12-31T00:00:00Z"
# Event Grid subscription: 30 gün önce uyarı
az eventgrid event-subscription create
--name secret-near-expiry
--source-resource-id /subscriptions/.../vaults/kv-saas-prod
--endpoint-type azurefunction
--endpoint /subscriptions/.../functions/RotatePassword
--included-event-types Microsoft.KeyVault.SecretNearExpiry
Function App secret expire’a 30 gün kala tetiklenir, yeni password generate eder, database’de update eder, Key Vault’a yeni secret kaydeder. Application managed identity ile yeni secret’ı bir sonraki call’da çekiyor.
Certificate Management: Auto-Renewal
TLS sertifikaları Key Vault’ta saklanıyor. Public CA (DigiCert, GlobalSign) integration ile auto-renewal:
az keyvault certificate create
--vault-name kv-saas-prod
--name app-tls-cert
--policy '{
"issuerParameters": {"name": "DigiCert"},
"x509CertificateProperties": {
"subject": "CN=app.example.com",
"validityInMonths": 12
},
"lifetimeActions": [{
"trigger": {"daysBeforeExpiry": 30},
"action": {"actionType": "AutoRenew"}
}]
}'
App Service / Application Gateway Key Vault’tan sertifikayı otomatik çekiyor. Renewal sonrası otomatik güncelleniyor, manuel deployment yok.
HSM-Backed Keys: PCI Compliance
Premium SKU’da key oluştururken –protection hsm flag’i ile HSM içinde tutulan key:
az keyvault key create
--vault-name kv-saas-prod
--name PaymentEncryptionKey
--protection hsm
--kty RSA-HSM
--size 2048
--ops encrypt decrypt wrap unwrap sign verify
Key private kısmı asla HSM’den dışarı çıkmıyor (hatta export edilse bile encrypted). PCI auditor “key bizden bağımsız bir HSM’de” dediğinde tatmin oluyor.
Audit Log Analizi
Key Vault diagnostic settings ile Log Analytics’e log gidiyor. Tipik sorgular:
// Hangi identity'ler hangi secret'ı çekiyor
AzureDiagnostics
| where ResourceType == "VAULTS"
| where OperationName == "SecretGet"
| summarize Count=count() by identity_claim_oid_g, requestUri_s
| order by Count desc
// Şüpheli erişim: yeni IP'den çok hızlı arka arkaya secret çekme
AzureDiagnostics
| where ResourceType == "VAULTS"
| where OperationName == "SecretGet"
| summarize Count=count() by CallerIPAddress, bin(TimeGenerated, 1m)
| where Count > 50
| order by Count desc
Sahada Düşülen Üç Tuzak
- Soft delete + purge protection unutmak: Yanlışlıkla silinen vault 90 gün geri getirilebilir (soft delete) ama purge protection açık değilse manuel purge edilebilir. Production’da ikisi de açık.
- Network restriction yok: Default’ta public endpoint açık. Private endpoint + selected VNet ile sıkılaştır.
- Secret versioning’i kullanmamak: Yeni version secret’ı yazıldığında eski version hâlâ geçerli. Application’ın hangi version’ı çektiğini takip et, rollback gerekirse spesifik version’a dön.
CloudSpark olarak Azure Key Vault implementasyon, secret rotation otomasyonu, HSM migration ve PCI/HIPAA uyum projeleri için danışmanlık veriyoruz.



