Azure Key Vault ile Gizli Veri Yönetimi

Üretim ortamında bir şifrenin Git reposuna commit edildiğini fark etmek, her sysadmin’in kâbusu. O paniği yaşadıysanız ne demek istediğimi anlarsınız. Azure Key Vault, tam da bu tür felaket senaryolarını önlemek için tasarlanmış bir servis. Ama çoğu ekip Key Vault’u yanlış kullanıyor ya da potansiyelinin çok küçük bir kısmını keşfedebiliyor. Bu yazıda, gerçek dünya senaryoları üzerinden Azure Key Vault’u baştan sona ele alacağız.

Azure Key Vault Nedir ve Neden Önemlidir

Key Vault, Microsoft Azure’un gizli veri yönetim servisidir. Şifreler, API anahtarları, sertifikalar ve kriptografik anahtarları merkezi bir yerde güvenle saklarsınız. Basit tanım bu, ama asıl değeri uygulamaya geçince anlıyorsunuz.

Düşünün: 15 farklı microservice uygulamanız var. Her birinin veritabanı şifresi, üçüncü parti API anahtarı, SSL sertifikası var. Bu bilgileri nerede tutuyorsunuz? Environment variable olarak container’a mı inject ediyorsunuz? .env dosyasına mı yazıyorsunuz? Kubernetes secret olarak mı yönetiyorsunuz? Her yaklaşımın kendi güvenlik delikleri var.

Key Vault bu karmaşayı çözer. Tüm gizli veriler tek yerde, erişim logları tutulur, rotasyon otomatikleştirilebilir ve kimler neye erişmiş tam olarak görürsünüz.

Key Vault Temel Bileşenleri

Key Vault üç ana nesne türü ile çalışır:

  • Secrets (Gizli Veriler): Düz metin değerler. Şifreler, API anahtarları, connection string’ler bunun içine girer.
  • Keys (Anahtarlar): Kriptografik anahtarlar. RSA, EC veya HSM destekli anahtarlar. Şifreleme/imzalama işlemleri için kullanılır.
  • Certificates (Sertifikalar): SSL/TLS sertifikaları. Let’s Encrypt veya kurumsal CA entegrasyonu yapılabilir.

Bu yazıda ağırlıklı olarak Secrets yönetimine odaklanacağız, çünkü günlük operasyonda en sık ihtiyaç duyulan bu kısım.

Kurulum ve İlk Yapılandırma

Azure CLI ile hızlıca başlayalım. Önce gerekli provider’ı kaydedin ve Key Vault oluşturun:

# Azure CLI ile login
az login

# Subscription ayarla
az account set --subscription "Production-Subscription"

# Resource group oluştur (zaten yoksa)
az group create 
  --name rg-security-prod 
  --location westeurope

# Key Vault oluştur
az keyvault create 
  --name kv-mycompany-prod 
  --resource-group rg-security-prod 
  --location westeurope 
  --sku standard 
  --enable-soft-delete true 
  --soft-delete-retention-days 90 
  --enable-purge-protection true

Burada birkaç önemli parametre var. --enable-soft-delete ile silinen secret’lar hemen kaybolmuyor, 90 gün kurtarılabilir durumda kalıyor. --enable-purge-protection ise kalıcı silme işlemini engeller. Üretim ortamında bu iki seçeneği her zaman açın.

SKU seçimi konusunda: standard çoğu senaryo için yeterli. Eğer HSM (Hardware Security Module) gerektiren uyumluluk standartlarınız varsa (PCI-DSS, FIPS 140-2 Level 3 gibi), premium SKU’ya geçin.

Secret Ekleme ve Okuma

İlk secret’ı ekleyelim:

# Basit bir secret ekle
az keyvault secret set 
  --vault-name kv-mycompany-prod 
  --name "db-password-prod" 
  --value "S3cur3P@ssw0rd!" 
  --description "Production PostgreSQL password" 
  --expires "2025-12-31T23:59:59Z"

# Secret listele
az keyvault secret list 
  --vault-name kv-mycompany-prod 
  --output table

# Secret değerini oku
az keyvault secret show 
  --vault-name kv-mycompany-prod 
  --name "db-password-prod" 
  --query "value" 
  --output tsv

# Belirli bir versiyonu göster
az keyvault secret show 
  --vault-name kv-mycompany-prod 
  --name "db-password-prod" 
  --version "abc123def456"

Her secret değiştirildiğinde Key Vault yeni bir versiyon oluşturur. Önceki versiyonlara erişim devam eder. Bu özellik rotasyon sırasında kritik öneme sahip, biraz sonra bu konuya geleceğiz.

Erişim Kontrolü: RBAC vs Access Policies

Key Vault’un en can sıkıcı kısımlarından biri erişim yönetimi. İki farklı model var ve hangisini kullandığınızı bilmek önemli.

Eski Model: Access Policies

# Bir kullanıcıya secret okuma yetkisi ver (eski model)
az keyvault set-policy 
  --name kv-mycompany-prod 
  --upn [email protected] 
  --secret-permissions get list

# Service principal'a yetki ver
az keyvault set-policy 
  --name kv-mycompany-prod 
  --spn "http://myapp-service-principal" 
  --secret-permissions get list set delete

Yeni Model: Azure RBAC (Önerilen)

# RBAC modelini aktive et
az keyvault update 
  --name kv-mycompany-prod 
  --resource-group rg-security-prod 
  --enable-rbac-authorization true

# Kullanıcıya "Key Vault Secrets User" rolü ata
az role assignment create 
  --role "Key Vault Secrets User" 
  --assignee [email protected] 
  --scope "/subscriptions/SUB_ID/resourceGroups/rg-security-prod/providers/Microsoft.KeyVault/vaults/kv-mycompany-prod"

# Belirli bir secret için granular yetki
az role assignment create 
  --role "Key Vault Secrets User" 
  --assignee [email protected] 
  --scope "/subscriptions/SUB_ID/resourceGroups/rg-security-prod/providers/Microsoft.KeyVault/vaults/kv-mycompany-prod/secrets/db-password-prod"

RBAC modelinin avantajı açık: Azure’un standart IAM sistemiyle bütünleşiyor. Tek bir yerden tüm yetkileri yönetiyorsunuz, audit daha kolay, Conditional Access politikaları uygulanabiliyor. Yeni kurduğunuz her Key Vault için RBAC modelini kullanın.

Mevcut yerleşik roller şunlar:

  • Key Vault Administrator: Tam yönetim yetkisi, sadece ops lead’lere verin
  • Key Vault Secrets Officer: Secret CRUD işlemleri yapabilir, anahtarlara dokunamaz
  • Key Vault Secrets User: Yalnızca okuma, uygulamalara bu rolü verin
  • Key Vault Reader: Metadata görüntüleme, secret değerlerine erişemez

Managed Identity ile Entegrasyon

Şifreler için şifre kullanmak saçma. Key Vault’a erişmek için ayrı bir credential saklamak zorunda kalmak da aynı şekilde saçma. Managed Identity bu döngüyü kırar.

Bir Azure VM’in Key Vault’a erişimini ayarlayalım:

# VM'de system-assigned managed identity aktive et
az vm identity assign 
  --name myapp-vm-prod 
  --resource-group rg-app-prod

# Identity'nin principal ID'sini al
PRINCIPAL_ID=$(az vm identity show 
  --name myapp-vm-prod 
  --resource-group rg-app-prod 
  --query principalId 
  --output tsv)

echo "Principal ID: $PRINCIPAL_ID"

# Bu identity'ye Key Vault okuma yetkisi ver
az role assignment create 
  --role "Key Vault Secrets User" 
  --assignee $PRINCIPAL_ID 
  --scope "/subscriptions/SUB_ID/resourceGroups/rg-security-prod/providers/Microsoft.KeyVault/vaults/kv-mycompany-prod"

VM içinden erişim testi yapalım. VM’e SSH bağlandıktan sonra:

# VM içinden token al ve Key Vault'a eriş
# Azure Instance Metadata Service (IMDS) üzerinden token
TOKEN=$(curl -s -H "Metadata:true" 
  "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2019-08-01&resource=https://vault.azure.net" 
  | python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])")

# Token ile secret oku
SECRET_VALUE=$(curl -s 
  -H "Authorization: Bearer $TOKEN" 
  "https://kv-mycompany-prod.vault.azure.net/secrets/db-password-prod?api-version=7.4" 
  | python3 -c "import sys, json; print(json.load(sys.stdin)['value'])")

echo "Secret başarıyla alındı: ${#SECRET_VALUE} karakter"

Gerçek uygulamalarda tabii ki SDK kullanırsınız, ham HTTP değil. Ama mekanizmayı anlamak için bu yol faydalı.

Secret Rotasyonu ve Otomasyonu

Rotasyon, çoğu ekibin ihmal ettiği ama ihmal edildiğinde en büyük güvenlik açığına yol açan konudur. Key Vault’ta rotasyonu birkaç şekilde yönetebilirsiniz.

Manuel Rotasyon

#!/bin/bash
# rotate-db-password.sh
# PostgreSQL şifresini rotate eden basit script

VAULT_NAME="kv-mycompany-prod"
SECRET_NAME="db-password-prod"
DB_HOST="db-prod.postgres.database.azure.com"
DB_USER="appuser"

# Yeni şifre oluştur (openssl ile güçlü random şifre)
NEW_PASSWORD=$(openssl rand -base64 32 | tr -d '=' | head -c 24)

echo "Yeni şifre oluşturuldu, veritabanında güncelleniyor..."

# PostgreSQL'de şifreyi güncelle
PGPASSWORD=$(az keyvault secret show 
  --vault-name $VAULT_NAME 
  --name $SECRET_NAME 
  --query "value" 
  --output tsv) 
psql 
  -h $DB_HOST 
  -U $DB_USER 
  -c "ALTER USER $DB_USER WITH PASSWORD '$NEW_PASSWORD';"

if [ $? -eq 0 ]; then
  echo "Veritabanı şifresi güncellendi, Key Vault güncelleniyor..."
  
  # Key Vault'ta güncelle
  az keyvault secret set 
    --vault-name $VAULT_NAME 
    --name $SECRET_NAME 
    --value "$NEW_PASSWORD" 
    --expires $(date -d "+90 days" --utc +%Y-%m-%dT%H:%M:%SZ)
  
  echo "Rotasyon tamamlandı."
else
  echo "HATA: Veritabanı güncellemesi başarısız! Key Vault değiştirilmedi."
  exit 1
fi

Event Grid ile Otomatik Rotasyon Tetikleme

Key Vault, secret’ların sona erme tarihine yaklaşıldığında Event Grid üzerinden event yayabilir. Bir Function App ile bunu otomatize edebilirsiniz:

# Key Vault event subscription oluştur
az eventgrid event-subscription create 
  --name kv-secret-expiry-subscription 
  --source-resource-id "/subscriptions/SUB_ID/resourceGroups/rg-security-prod/providers/Microsoft.KeyVault/vaults/kv-mycompany-prod" 
  --endpoint "https://myfunctionapp.azurewebsites.net/api/RotateSecret" 
  --endpoint-type webhook 
  --included-event-types "Microsoft.KeyVault.SecretNearExpiry" 
  --subject-begins-with "db-password"

Bu yapıyla secret’ın sona erme tarihinden 30 gün önce Function App’iniz otomatik tetiklenir ve rotasyonu gerçekleştirir.

Azure DevOps Pipeline Entegrasyonu

CI/CD pipeline’larında Key Vault kullanmak, environment variable güvenliğini kökten iyileştirir.

# Azure DevOps'ta Key Vault task kullanımı
# azure-pipelines.yml örneği
# Bu aşağıdaki YAML yapısını pipeline dosyasına ekleyin:

# - task: AzureKeyVault@2
#   inputs:
#     azureSubscription: 'Production-ServiceConnection'
#     KeyVaultName: 'kv-mycompany-prod'
#     SecretsFilter: 'db-password-prod,api-key-stripe,jwt-secret'
#     RunAsPreJob: true

# Pipeline içinde CLI ile secret'lara erişim
az keyvault secret download 
  --vault-name kv-mycompany-prod 
  --name "ssl-certificate-prod" 
  --encoding base64 
  --file /tmp/ssl-cert.pfx

# Secret değerini environment variable olarak set et (sadece pipeline session için)
export DB_CONNECTION=$(az keyvault secret show 
  --vault-name kv-mycompany-prod 
  --name "db-connection-string-prod" 
  --query "value" 
  --output tsv)

# Uygulamayı bu variable ile çalıştır
./deploy.sh

Pipeline’da önemli bir nokta: Secret değerlerini hiçbir zaman log’a yazmayın. Azure DevOps secret variable’ları otomatik maskeliyor ama Key Vault’tan okuduğunuz değerleri echo ile yazdırmayın.

Kubernetes ile Key Vault Entegrasyonu

AKS kullanıyorsanız, CSI Secret Store Driver ile Key Vault’u doğrudan pod’lara mount edebilirsiniz:

# Secret Store CSI Driver kurulumu
helm repo add secrets-store-csi-driver 
  https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts

helm install csi-secrets-store 
  secrets-store-csi-driver/secrets-store-csi-driver 
  --namespace kube-system 
  --set syncSecret.enabled=true

# Azure Key Vault Provider kurulumu
helm repo add csi-secrets-store-provider-azure 
  https://azure.github.io/secrets-store-csi-driver-provider-azure/charts

helm install azure-csi-provider 
  csi-secrets-store-provider-azure/csi-secrets-store-provider-azure 
  --namespace kube-system

# SecretProviderClass tanımlama
cat <<EOF | kubectl apply -f -
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: azure-keyvault-secrets
  namespace: production
spec:
  provider: azure
  parameters:
    usePodIdentity: "false"
    useVMManagedIdentity: "true"
    userAssignedIdentityID: ""
    keyvaultName: "kv-mycompany-prod"
    cloudName: "AzurePublicCloud"
    objects: |
      array:
        - |
          objectName: db-password-prod
          objectType: secret
          objectVersion: ""
        - |
          objectName: api-key-stripe
          objectType: secret
          objectVersion: ""
    tenantId: "YOUR-TENANT-ID"
EOF

Bu yapıyla secret’lar pod’un filesystem’ına mount edilir. Uygulama kodu Key Vault API’sini bilmek zorunda kalmaz, sadece dosya okur.

Monitoring ve Audit Logging

Key Vault’ta kimin neye ne zaman eriştiğini bilmek güvenlik açısından olmazsa olmaz.

# Diagnostic settings ile Log Analytics'e log gönder
LOG_ANALYTICS_WORKSPACE_ID=$(az monitor log-analytics workspace show 
  --workspace-name law-security-prod 
  --resource-group rg-security-prod 
  --query id 
  --output tsv)

az monitor diagnostic-settings create 
  --name kv-diagnostics 
  --resource "/subscriptions/SUB_ID/resourceGroups/rg-security-prod/providers/Microsoft.KeyVault/vaults/kv-mycompany-prod" 
  --workspace $LOG_ANALYTICS_WORKSPACE_ID 
  --logs '[{"category": "AuditEvent", "enabled": true, "retentionPolicy": {"days": 365, "enabled": true}}]' 
  --metrics '[{"category": "AllMetrics", "enabled": true}]'

# Log Analytics'te audit sorgulama
# Aşağıdaki KQL sorgusunu Log Analytics Workspace'de çalıştırın:
# AzureDiagnostics
# | where ResourceProvider == "MICROSOFT.KEYVAULT"
# | where OperationName == "SecretGet"
# | project TimeGenerated, CallerIPAddress, identity_claim_upn_s, requestUri_s
# | order by TimeGenerated desc

# CLI ile recent operasyonları göster
az monitor activity-log list 
  --resource-id "/subscriptions/SUB_ID/resourceGroups/rg-security-prod/providers/Microsoft.KeyVault/vaults/kv-mycompany-prod" 
  --start-time "2024-01-01T00:00:00Z" 
  --query "[].{Time:eventTimestamp, Operation:operationName.value, Caller:caller, Status:status.value}" 
  --output table

Audit loglarını düzenli gözden geçirin. Özellikle şu alert’leri kurun:

  • Beklenmedik IP adresinden erişim
  • Servis saatleri dışında okuma (gece yarısı otomatik işlemler hariç)
  • Başarısız erişim denemeleri
  • Key Vault ayarlarında yapılan değişiklikler

Gerçek Dünya Senaryosu: Multi-Environment Secret Yönetimi

Tipik bir setup: dev, staging, prod için ayrı Key Vault’lar, ama ortak bir naming convention.

#!/bin/bash
# setup-environments.sh
# Tüm ortamlar için Key Vault yapısı kur

ENVIRONMENTS=("dev" "staging" "prod")
RESOURCE_GROUP_PREFIX="rg-security"
VAULT_PREFIX="kv-mycompany"
LOCATION="westeurope"

for ENV in "${ENVIRONMENTS[@]}"; do
  echo "=== $ENV ortamı kuruluyor ==="
  
  RG_NAME="${RESOURCE_GROUP_PREFIX}-${ENV}"
  VAULT_NAME="${VAULT_PREFIX}-${ENV}"
  
  # Resource group oluştur
  az group create 
    --name $RG_NAME 
    --location $LOCATION 
    --tags Environment=$ENV ManagedBy=ops-team
  
  # Key Vault oluştur
  az keyvault create 
    --name $VAULT_NAME 
    --resource-group $RG_NAME 
    --location $LOCATION 
    --sku standard 
    --enable-soft-delete true 
    --soft-delete-retention-days 30 
    --enable-purge-protection $([ "$ENV" == "prod" ] && echo "true" || echo "false") 
    --tags Environment=$ENV
  
  echo "$VAULT_NAME oluşturuldu."
  
  # Prod için ek güvenlik
  if [ "$ENV" == "prod" ]; then
    # Network ACL kısıtlaması ekle
    az keyvault network-rule add 
      --name $VAULT_NAME 
      --resource-group $RG_NAME 
      --ip-address "203.0.113.0/24"  # Ofis IP bloğu
    
    az keyvault update 
      --name $VAULT_NAME 
      --resource-group $RG_NAME 
      --default-action Deny
    
    echo "Prod için network kısıtlaması eklendi."
  fi
done

echo "Tüm ortamlar hazır."

Bu yaklaşımda her ortam izole. Bir geliştirici dev vault’una erişebilir ama prod vault’una erişemez. Staging’den prod’a terfi iş akışı net ve denetlenebilir.

Sık Yapılan Hatalar

Bunları pratikte defalarca gördüm:

  • Secret adlarını açık tutmak: password yerine app-frontend-db-password-prod gibi isimlendirin. İleride ne olduğunu anlamak kolaylaşır.
  • Expiry date koymamak: Her secret için bir sona erme tarihi belirleyin. Key Vault sizi zorlamaz ama operasyonel disiplin açısından şart.
  • Tek vault’a her şeyi koymak: Uygulama bazlı vault’lara ayırın. Bir uygulamanın service account’u sızarsa, sadece o uygulamanın secret’larına erişilsin.
  • Soft delete’i yanlış anlamak: Soft delete açık olsa bile vault’u silmek mümkün. Purge protection ayrıca aktif edilmeli.
  • Access log’ları izlememek: Key Vault’u kurmak yeterli değil, kim neye baktığını takip etmezseniz bir güvenlik değeri üretmiyorsunuz.

Sonuç

Azure Key Vault, doğru kurulduğunda ve doğru entegre edildiğinde güvenlik operasyonlarını köklü biçimde iyileştiriyor. En önemli adımlar şunlar: RBAC modelini kullanın, Managed Identity ile kimlik bilgisi yönetimini döngüden çıkarın, her secret için expiry tarihi belirleyin ve audit loglarını aktif olarak izleyin.

Başlamak için büyük bir proje planı yapmaya gerek yok. Önce en kritik şifrelerinizi Key Vault’a taşıyın. Bir uygulama için Managed Identity entegrasyonu yapın. Çalıştığını görünce momentum kendiğinden gelir. Git reponuza gömülü şifreler, .env dosyaları ve Confluence sayfalarına yazılmış API anahtarları bir sistemin güvenlik olgunluğunun ne kadar düşük olduğunun göstergesidir. Key Vault o olgunluk seviyesini ciddi ölçüde yukarı taşır.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir