Test Senaryoları ile Felaket Kurtarma Simülasyonu
Felaket kurtarma planı yapmak bir şeydir, onu gerçekten test etmek bambaşka bir şeydir. Çoğu sistem yöneticisi “yedeklerimiz var, sorun olmaz” der ama gerçek bir kriz anında bu yedeklerin çalışıp çalışmadığını, ekibin nasıl tepki vereceğini ve sistemlerin ne kadar sürede ayağa kalkacağını bilmez. İşte bu yüzden felaket kurtarma simülasyonları, teorik planlardan çok daha değerlidir. Bu yazıda gerçek dünya senaryolarına dayanan, uygulanabilir DR test metodolojilerini ve kod örneklerini ele alacağız.
Felaket Kurtarma Testinin Temel Kavramları
Bir DR testine başlamadan önce iki temel metriği netleştirmeniz gerekiyor:
RTO (Recovery Time Objective): Sistemin felaketten sonra ne kadar sürede ayağa kalkması gerektiği. Örneğin e-ticaret siteniz için bu 4 saat olabilir.
RPO (Recovery Point Objective): Ne kadar veri kaybını tolere edebileceğiniz. Günde bir yedek alıyorsanız maksimum 24 saatlik veri kaybı kabul edilebilir demektir.
Bu iki değer, test senaryolarınızın başarı kriterlerini belirler. Testi geçmek için hem RTO’yu hem de RPO’yu karşılamanız gerekir.
DR testleri genel olarak üç kategoriye ayrılır:
- Masa başı tatbikatı (Tabletop Exercise): Ekip toplanır, senaryo kağıt üzerinde tartışılır. En düşük riskli yöntemdir.
- Kısmi test (Partial Test): Sistemlerin belirli bir bölümü gerçekten failover edilir.
- Tam ölçekli test (Full-Scale Test): Tüm üretim sistemleri kapatılır, her şey DR ortamından çalıştırılır. En gerçekçi ama en riskli yöntemdir.
Test Ortamı Hazırlığı
Testlere başlamadan önce izole bir ortam oluşturmanız şarttır. Bunu yapmadan gerçek üretim sistemlerine zarar verebilirsiniz.
#!/bin/bash
# DR test ortamı ön hazırlık scripti
# Bu script test öncesi kontrol listesini çalıştırır
DR_LOG="/var/log/dr_test_$(date +%Y%m%d_%H%M%S).log"
TEST_ENV="staging"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$DR_LOG"
}
check_prerequisites() {
log "Ön koşul kontrolü başlıyor..."
# Disk alanı kontrolü
AVAILABLE=$(df /backup | awk 'NR==2{print $4}')
if [ "$AVAILABLE" -lt 51200000 ]; then
log "HATA: Yetersiz disk alanı. En az 50GB gerekli."
exit 1
fi
# Network bağlantısı kontrolü
if ! ping -c 3 "$DR_SERVER_IP" &>/dev/null; then
log "HATA: DR sunucusuna erişilemiyor: $DR_SERVER_IP"
exit 1
fi
# Son yedeğin yaşını kontrol et
LAST_BACKUP=$(find /backup -name "*.tar.gz" -newer /backup/.last_success 2>/dev/null | head -1)
if [ -z "$LAST_BACKUP" ]; then
log "UYARI: Son 24 saat içinde alınmış yedek bulunamadı!"
fi
log "Ön koşul kontrolü tamamlandı."
}
check_prerequisites
Senaryo 1: Veritabanı Sunucusu Çöküşü
Bu senaryo, en sık karşılaşılan felaket türlerinden biridir. PostgreSQL veya MySQL sunucunuzun tamamen çöktüğünü ve yedeğe geri dönmeniz gerektiğini simüle ediyoruz.
Test ortamında önce mevcut veritabanını “çökmüş gibi” davranacak şekilde durduruyoruz, ardından kurtarma prosedürünü uyguluyoruz.
#!/bin/bash
# PostgreSQL DR test scripti
# Senaryo: Ana DB sunucusu erişilemez, standby'a geçiş
PRIMARY_DB="db-primary.internal"
STANDBY_DB="db-standby.internal"
DB_USER="postgres"
TEST_DB="testdb"
START_TIME=$(date +%s)
log "=== PostgreSQL Failover Testi Başladı ==="
log "Başlangıç zamanı: $(date)"
# Adım 1: Standby'ın replikasyon durumunu kontrol et
log "Standby replikasyon lag kontrolü..."
REPL_LAG=$(psql -h "$STANDBY_DB" -U "$DB_USER" -t -c "
SELECT EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))::INT
AS replication_lag_seconds;
")
if [ "$REPL_LAG" -gt 60 ]; then
log "UYARI: Replikasyon gecikmesi $REPL_LAG saniye. Veri kaybı riski var!"
fi
# Adım 2: Standby'ı promote et
log "Standby sunucu promote ediliyor..."
pg_ctl promote -D /var/lib/postgresql/data -w
# Adım 3: Uygulama bağlantılarını yönlendir
log "Uygulama konfigürasyonu güncelleniyor..."
sed -i "s/$PRIMARY_DB/$STANDBY_DB/g" /etc/app/database.conf
# Adım 4: Bağlantıyı doğrula
if psql -h "$STANDBY_DB" -U "$DB_USER" -c "SELECT 1;" &>/dev/null; then
END_TIME=$(date +%s)
ELAPSED=$((END_TIME - START_TIME))
log "BAŞARILI: Failover $ELAPSED saniyede tamamlandı."
log "RTO hedefi: 900 saniye | Gerçekleşen: $ELAPSED saniye"
else
log "HATA: Yeni primary'e bağlanılamıyor!"
exit 1
fi
Bu testi çalıştırdıktan sonra sonuçları belgelemeniz kritik önem taşır. Kaç saniyede tamamlandı? RTO hedefinizi karşıladınız mı? Veri kaybı yaşandı mı?
Senaryo 2: Dosya Sistemi Yedekten Geri Yükleme
Bir sunucuda kritik uygulama dosyaları silinmiş ya da bozulmuş olabilir. Bu senaryoda rsnapshot veya Bacula ile alınan yedeklerden geri yükleme simüle ediyoruz.
#!/bin/bash
# Dosya sistemi geri yükleme testi
# rsnapshot yedeklerinden seçici geri yükleme
BACKUP_ROOT="/backup/rsnapshot"
RESTORE_TARGET="/tmp/dr_restore_test"
TEST_DIR="/var/www/html"
SNAPSHOT_LEVEL="daily.0"
log "Dosya sistemi geri yükleme testi başlıyor..."
# Test için restore dizini oluştur
mkdir -p "$RESTORE_TARGET"
# Yedekten geri yükle
rsync -avz --progress
"$BACKUP_ROOT/$SNAPSHOT_LEVEL/localhost$TEST_DIR/"
"$RESTORE_TARGET/"
2>&1 | tee -a "$DR_LOG"
# Dosya bütünlüğünü kontrol et
ORIGINAL_COUNT=$(find "$TEST_DIR" -type f | wc -l)
RESTORED_COUNT=$(find "$RESTORE_TARGET" -type f | wc -l)
log "Orijinal dosya sayısı: $ORIGINAL_COUNT"
log "Geri yüklenen dosya sayısı: $RESTORED_COUNT"
if [ "$ORIGINAL_COUNT" -eq "$RESTORED_COUNT" ]; then
log "BAŞARILI: Tüm dosyalar geri yüklendi."
else
MISSING=$((ORIGINAL_COUNT - RESTORED_COUNT))
log "UYARI: $MISSING dosya eksik!"
fi
# MD5 checksum doğrulaması
log "Checksum doğrulaması yapılıyor..."
find "$TEST_DIR" -type f -exec md5sum {} ; > /tmp/original_checksums.txt
find "$RESTORE_TARGET" -type f -exec md5sum {} ; > /tmp/restored_checksums.txt
diff /tmp/original_checksums.txt /tmp/restored_checksums.txt > /tmp/checksum_diff.txt
if [ -s /tmp/checksum_diff.txt ]; then
log "UYARI: Checksum farklılıkları tespit edildi. Detaylar: /tmp/checksum_diff.txt"
else
log "BAŞARILI: Tüm checksum'lar eşleşiyor."
fi
Senaryo 3: Tam Sunucu Kurtarma (Bare Metal Recovery)
Bu en kapsamlı senaryodur. Fiziksel veya sanal sunucu tamamen yok olmuş gibi davranıp, sistemi sıfırdan ayağa kaldırıyoruz. Modern ortamlarda bu genellikle snapshot’tan yeni bir VM oluşturmak anlamına gelir.
#!/bin/bash
# VMware / KVM snapshot'tan VM kurtarma testi
# Proxmox VE ortamı için örnek
VM_ID="105"
SNAPSHOT_NAME="pre_update_snapshot"
NEW_VM_ID="999" # Test için geçici VM ID
DR_NODE="pve-dr-node"
log "Bare metal kurtarma testi başlıyor..."
log "Kaynak VM: $VM_ID, Snapshot: $SNAPSHOT_NAME"
# Snapshot'ı listele ve doğrula
SNAP_EXISTS=$(pvesh get /nodes/localhost/qemu/$VM_ID/snapshot | grep "$SNAPSHOT_NAME")
if [ -z "$SNAP_EXISTS" ]; then
log "HATA: Snapshot bulunamadı: $SNAPSHOT_NAME"
exit 1
fi
# DR node'unda yeni VM oluştur (snapshot'tan klonlama)
log "DR node'unda klonlama işlemi başlıyor..."
qm clone "$VM_ID" "$NEW_VM_ID"
--name "dr-test-$(date +%Y%m%d)"
--target "$DR_NODE"
--snapname "$SNAPSHOT_NAME"
--full 1
CLONE_STATUS=$?
if [ $CLONE_STATUS -ne 0 ]; then
log "HATA: Klonlama başarısız! Exit code: $CLONE_STATUS"
exit 1
fi
# Test VM'i farklı bir network segmentinde başlat
log "Test VM ağ ayarları yapılandırılıyor (izole VLAN)..."
qm set "$NEW_VM_ID" --net0 virtio,bridge=vmbr1,tag=999
# VM'i başlat
qm start "$NEW_VM_ID"
sleep 60 # Bootlanması için bekle
# VM'e SSH ile bağlan ve temel kontrolleri yap
VM_IP=$(qm agent "$NEW_VM_ID" network-get-interfaces | grep -A2 "eth0" | grep "ip-address" | head -1 | awk '{print $2}')
log "Test VM IP adresi: $VM_IP"
# Servis kontrolleri
SERVICES=("nginx" "postgresql" "redis")
for service in "${SERVICES[@]}"; do
if ssh -o StrictHostKeyChecking=no "admin@$VM_IP" "systemctl is-active $service" 2>/dev/null | grep -q "active"; then
log "OK: $service servisi çalışıyor"
else
log "HATA: $service servisi çalışmıyor!"
fi
done
log "Test tamamlandı. Test VM temizleniyor..."
qm stop "$NEW_VM_ID" && qm destroy "$NEW_VM_ID"
Senaryo 4: Ağ Altyapısı Arızası Simülasyonu
Sadece sunucu değil, ağ altyapısı da çökebilir. Bu senaryoda kritik ağ bağlantılarının kesilmesini simüle edip uygulamanın nasıl davrandığını test ediyoruz.
#!/bin/bash
# Network partition testi - iptables ile bağlantı kesme simülasyonu
# DİKKAT: Bu scripti sadece test ortamında çalıştırın!
TARGET_SUBNET="10.10.20.0/24" # Simüle edilecek ağ
TEST_DURATION=300 # 5 dakika bağlantı kesme
MONITOR_INTERVAL=10
log "Ağ kesinti simülasyonu başlıyor..."
log "Hedef subnet: $TARGET_SUBNET"
log "Süre: $TEST_DURATION saniye"
# Bağlantıyı kes
iptables -A INPUT -s "$TARGET_SUBNET" -j DROP
iptables -A OUTPUT -d "$TARGET_SUBNET" -j DROP
log "Bağlantı kesildi. Uygulama izleniyor..."
# Test süresi boyunca uygulama davranışını izle
END_TIME=$(($(date +%s) + TEST_DURATION))
ALERT_COUNT=0
while [ $(date +%s) -lt $END_TIME ]; do
# Uygulama health check
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 http://app.internal/health)
if [ "$HTTP_STATUS" != "200" ]; then
ALERT_COUNT=$((ALERT_COUNT + 1))
log "ALERT #$ALERT_COUNT: Uygulama yanıt vermiyor (HTTP: $HTTP_STATUS)"
else
log "OK: Uygulama yanıt veriyor (HTTP: $HTTP_STATUS) - Graceful degradation çalışıyor"
fi
sleep "$MONITOR_INTERVAL"
done
# Bağlantıyı geri yükle
log "Test süresi doldu. Bağlantı restore ediliyor..."
iptables -D INPUT -s "$TARGET_SUBNET" -j DROP
iptables -D OUTPUT -d "$TARGET_SUBNET" -j DROP
log "Toplam alert sayısı: $ALERT_COUNT"
log "Ağ geri yükleme sonrası recovery süresi ölçülüyor..."
# Recovery süresini ölç
RECOVERY_START=$(date +%s)
until curl -s --max-time 5 http://app.internal/health | grep -q "ok"; do
sleep 2
done
RECOVERY_TIME=$(($(date +%s) - RECOVERY_START))
log "Recovery süresi: $RECOVERY_TIME saniye"
Otomatik DR Test Raporlama
Manuel test sonuçlarını takip etmek zorlaşabilir. Özellikle düzenli testler yapıyorsanız otomatik raporlama şart.
#!/bin/bash
# DR test sonuç raporu oluşturucu
REPORT_FILE="/var/reports/dr_test_$(date +%Y%m%d).html"
LOG_FILE="$DR_LOG"
generate_html_report() {
cat > "$REPORT_FILE" << EOF
<!DOCTYPE html>
<html>
<head><title>DR Test Raporu - $(date +%Y-%m-%d)</title></head>
<body>
<h2>Felaket Kurtarma Test Raporu</h2>
<p>Test Tarihi: $(date '+%d/%m/%Y %H:%M')</p>
<p>Test Ortamı: $TEST_ENV</p>
<hr>
<h3>Test Sonuçlari</h3>
<pre>
$(cat "$LOG_FILE" | grep -E "BAŞARILI|HATA|UYARI|OK" | head -50)
</pre>
<h3>Metrikler</h3>
EOF
# RTO hesapla
RTO_ACTUAL=$(grep "tamamlandı" "$LOG_FILE" | grep -oP 'd+ saniye' | tail -1)
echo "<p>Gerçekleşen RTO: $RTO_ACTUAL</p>" >> "$REPORT_FILE"
# Başarı oranı
SUCCESS=$(grep -c "BAŞARILI" "$LOG_FILE")
FAILURE=$(grep -c "HATA" "$LOG_FILE")
TOTAL=$((SUCCESS + FAILURE))
if [ "$TOTAL" -gt 0 ]; then
RATE=$((SUCCESS * 100 / TOTAL))
echo "<p>Başarı Oranı: %$RATE ($SUCCESS/$TOTAL)</p>" >> "$REPORT_FILE"
fi
echo "</body></html>" >> "$REPORT_FILE"
log "Rapor oluşturuldu: $REPORT_FILE"
# Raporu e-posta ile gönder
mail -s "DR Test Raporu - $(date +%Y-%m-%d)"
-a "Content-Type: text/html"
[email protected] < "$REPORT_FILE"
}
generate_html_report
Senaryo 5: Ransomware Saldırısı Simülasyonu
Günümüzde en yaygın felakette türlerinden biri artık fidye yazılımı saldırılarıdır. Bu senaryoda kritik dizinler “şifrelenmiş” gibi davranıp, temiz yedekten kurtarma yapıyoruz.
#!/bin/bash
# Ransomware kurtarma simülasyonu
# Temiz bir snapshot noktasına geri dönüş testi
INFECTED_DIRS=("/var/www/html" "/opt/app/data")
CLEAN_BACKUP_DATE="2024-01-15" # Bilinen temiz yedek tarihi
BACKUP_SOURCE="/backup/daily/$CLEAN_BACKUP_DATE"
log "=== Ransomware Kurtarma Simülasyonu ==="
log "Temiz yedek tarihi: $CLEAN_BACKUP_DATE"
# Adım 1: Sistemi ağdan izole et (simülasyon için sadece loglama)
log "ADIM 1: Etkilenen sistemler ağdan izole ediliyor..."
log "Firewall kuralları uygulandı. Lateral movement engellendi."
# Adım 2: Etkilenme kapsamını belirle
log "ADIM 2: Etkilenme kapsamı analizi..."
for dir in "${INFECTED_DIRS[@]}"; do
FILE_COUNT=$(find "$dir" -type f 2>/dev/null | wc -l)
ENCRYPTED=$(find "$dir" -name "*.encrypted" -o -name "*.locked" 2>/dev/null | wc -l)
log "Dizin: $dir | Toplam: $FILE_COUNT | Etkilenen: $ENCRYPTED"
done
# Adım 3: Yedek bütünlüğünü doğrula
log "ADIM 3: Yedek bütünlüğü kontrol ediliyor..."
if [ -f "$BACKUP_SOURCE/manifest.sha256" ]; then
cd "$BACKUP_SOURCE"
if sha256sum -c manifest.sha256 --quiet 2>/dev/null; then
log "BAŞARILI: Yedek bütünlüğü doğrulandı."
else
log "HATA: Yedek bütünlüğü bozuk! Alternatif yedek aranıyor..."
# Bir önceki yedeği dene
BACKUP_SOURCE="/backup/daily/$(date -d "$CLEAN_BACKUP_DATE - 1 day" +%Y-%m-%d)"
fi
fi
# Adım 4: Kurtarma işlemi
log "ADIM 4: Kurtarma işlemi başlıyor..."
RESTORE_START=$(date +%s)
for dir in "${INFECTED_DIRS[@]}"; do
log "Geri yükleniyor: $dir"
rsync -avz --delete
"$BACKUP_SOURCE/$(basename $dir)/"
"$dir/" >> "$DR_LOG" 2>&1
done
RESTORE_END=$(date +%s)
RESTORE_DURATION=$((RESTORE_END - RESTORE_START))
log "Geri yükleme süresi: $RESTORE_DURATION saniye"
# Adım 5: Uygulama doğrulama
log "ADIM 5: Uygulama fonksiyonellik testi..."
sleep 10
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost/health)
if [ "$HTTP_CODE" = "200" ]; then
log "BAŞARILI: Uygulama normal çalışıyor."
else
log "HATA: Uygulama health check başarısız! HTTP: $HTTP_CODE"
fi
DR Test Takvimi ve Sıklığı
Testlerin ne zaman yapılacağı da en az nasıl yapılacağı kadar önemlidir. Önerilen frekanslar şunlardır:
- Haftalık: Otomatik yedek doğrulama ve checksum kontrolü
- Aylık: Kısmi geri yükleme testi (tek bir veritabanı veya uygulama bileşeni)
- Üç ayda bir: Tam failover testi, standby ortamının aktivasyonu
- Altı ayda bir: Tam ölçekli DR tatbikatı, ekibin tüm iletişim prosedürlerini dahil et
- Yılda bir: Üst yönetimin katıldığı masa başı tatbikatı ve plan güncellemesi
Bu takvimleri crontab ile otomatize edebilirsiniz:
# Otomatik DR test takvimi
# /etc/cron.d/dr-tests dosyasına eklenecek
# Her gece 02:00'de yedek doğrulama
0 2 * * * root /opt/dr-scripts/verify_backups.sh >> /var/log/dr_backup_verify.log 2>&1
# Her Pazar sabahı 04:00'te aylık geri yükleme testi
0 4 * * 0 root /opt/dr-scripts/monthly_restore_test.sh >> /var/log/dr_monthly_test.log 2>&1
# Her çeyreğin ilk günü saat 06:00'da failover testi
0 6 1 1,4,7,10 * root /opt/dr-scripts/quarterly_failover_test.sh >> /var/log/dr_quarterly.log 2>&1
# Test raporunu her Pazartesi sabahı e-posta ile gönder
0 8 * * 1 root /opt/dr-scripts/generate_weekly_report.sh
Sık Yapılan Hatalar ve Kaçınma Yolları
DR testlerinde en çok karşılaştığım hatalar şunlardır:
- Yedekleri hiç test etmemek: En klasik hata. Yedek almak yeterli değil, yedeği geri yükleyebiliyor musunuz, bunu bilmeniz gerekiyor.
- Üretim ortamında test yapmak: Her zaman izole bir test ortamı kullanın. Aksi halde “simülasyon” gerçek felakete dönüşebilir.
- Ekibi teste dahil etmemek: DR planı sadece siz biliyorsanız tatil veya hasta olduğunuzda plan işe yaramaz. Tüm ekip tatbikata katılmalı.
- Belgeleme yapmamak: Her testi detaylı belgeleyin. Bir sonraki testte neyin değiştiğini görmek için önceki sonuçlara ihtiyacınız olacak.
- Başarısız testleri önemsememek: Bir test başarısız olduğunda kutlayın, sorun var anlamına gelir, gerçek krizden önce buldunuz.
- Planı güncellemeden testi tekrar etmek: Test sonuçlarına göre planı mutlaka güncelleyin, sonra tekrar test edin.
Sonuç
Felaket kurtarma simülasyonu, organizasyonunuzun en değerli sigorta poliçesidir. Yazıda ele aldığımız senaryolar, veritabanı çöküşünden fidye yazılımı saldırısına kadar gerçek hayatta karşılaşabileceğiniz durumları kapsıyor. Ancak en önemli nokta şu: mükemmel bir plan bile test edilmemişse kağıt üzerinde kalır.
İlk adım olarak basit başlayın. Bu hafta yedeklerinizden bir dosyayı geri yükleyin ve ne kadar sürdüğünü not edin. Gelecek ay bir veritabanı failover’ı simüle edin. Her testten öğrenin, planı güncelleyin ve tekrar test edin. Bir felaket anında “umarım çalışır” değil “test ettim, çalışıyor” diyebilmek için harcadığınız her dakika kesinlikle değer.
Gerçek bir kriz geldiğinde en iyi arkadaşınız, üç ay önce yaptığınız tatbikatta aldığınız notlar olacak.
