WAF++ WAF++
Back to WAF++ Homepage

Best Practice: Backup, Recovery & Wiederherstellungstests

Kontext

Backup ohne getestete Recovery ist eine Sicherheitsillusion. Die häufigsten Backup-Fehler in der Praxis sind nicht fehlende Backups, sondern ungetestete Recovery-Verfahren, die im Ernstfall scheitern – weil manuelle Schritte fehlen, Schlüssel nicht verfügbar sind oder die IaC-Umgebung des Ziel-Accounts nicht existiert.

Häufige Probleme ohne strukturierte Backup-Recovery-Praxis:

  • Backups sind konfiguriert, aber Restore-Prozedur wurde nie ausgeführt

  • Backup-Verschlüsselungsschlüssel im selben Account wie die Daten (Ransomware)

  • RTO-Ziel = 1 Stunde, aber letzter Restore-Test ergab 4 Stunden

  • PITR aktiviert, aber Restore-Prozedur nicht dokumentiert

Zugehörige Controls

Zielbild

  • Automatisierte Backups mit RPO-alignierten Retentionsperioden

  • Cross-Account-Speicherung verhindert Single-Account-Kompromittierung

  • PITR für granulare Wiederherstellung auf Transaktionsebene

  • Quartalsweise getestete und dokumentierte Restore-Prozedur

Technische Umsetzung

AWS: Cross-Account RDS Backup

# Backup-Ziel: Separates AWS-Account
resource "aws_db_instance" "main" {
  identifier              = "payment-db-prod"
  engine                  = "postgres"
  engine_version          = "15.4"
  instance_class          = "db.t3.medium"
  allocated_storage       = 100
  backup_retention_period = 14          # 14 Tage PITR
  backup_window           = "02:00-03:00"
  deletion_protection     = true
  copy_tags_to_snapshot   = true

  tags = var.mandatory_tags
}

# AWS Backup Plan für Cross-Account Replikation
resource "aws_backup_plan" "main" {
  name = "payment-db-backup-plan"

  rule {
    rule_name         = "daily-backup"
    target_vault_name = aws_backup_vault.main.name
    schedule          = "cron(0 2 * * ? *)"

    lifecycle {
      delete_after = 90  # 90 Tage Retention
    }

    # Cross-Account Kopie in Backup-Account
    copy_action {
      destination_vault_arn = var.backup_account_vault_arn
      lifecycle {
        delete_after = 90
      }
    }
  }
}

# Backup Vault mit WORM-Schutz
resource "aws_backup_vault_lock_configuration" "main" {
  backup_vault_name   = aws_backup_vault.main.name
  min_retention_days  = 7
  max_retention_days  = 90
  changeable_for_days = 3  # Compliance Mode nach 3 Tagen
}

S3 Versioning + Object Lock

resource "aws_s3_bucket" "data" {
  bucket = "payment-production-data-${var.account_id}"
  tags   = var.mandatory_tags
}

resource "aws_s3_bucket_versioning" "data" {
  bucket = aws_s3_bucket.data.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_object_lock_configuration" "data" {
  bucket = aws_s3_bucket.data.id

  rule {
    default_retention {
      mode = "GOVERNANCE"
      days = 30  # 30 Tage Löschschutz
    }
  }
}

# Replikation in Backup-Account
resource "aws_s3_bucket_replication_configuration" "data" {
  bucket = aws_s3_bucket.data.id
  role   = aws_iam_role.replication.arn

  rule {
    id     = "backup-account-replication"
    status = "Enabled"

    destination {
      bucket        = var.backup_account_bucket_arn
      storage_class = "GLACIER_IR"
    }
  }
}

Azure: Geo-Redundant Database Backup

resource "azurerm_postgresql_flexible_server" "main" {
  name                         = "payment-db-prod"
  resource_group_name          = azurerm_resource_group.main.name
  location                     = "westeurope"
  version                      = "15"
  sku_name                     = "GP_Standard_D4s_v3"
  backup_retention_days        = 35    # Maximaler Azure-Wert
  geo_redundant_backup_enabled = true  # Cross-Region Backup

  high_availability {
    mode                      = "ZoneRedundant"
    standby_availability_zone = "2"
  }

  tags = var.mandatory_tags
}

Restore-Test Automatisierung (Bash/AWS CLI)

#!/bin/bash
# scripts/restore-test.sh
# Quartalsweiser Backup-Restore-Test

set -euo pipefail

TIMESTAMP=$(date +%Y%m%d-%H%M%S)
RESTORE_DB_ID="payment-db-restore-test-${TIMESTAMP}"
SNAPSHOT_ID=$(aws rds describe-db-snapshots \
  --db-instance-identifier payment-db-prod \
  --query 'sort_by(DBSnapshots, &SnapshotCreateTime)[-1].DBSnapshotIdentifier' \
  --output text)

echo "Using snapshot: ${SNAPSHOT_ID}"

# Restore in isoliertem Test-Subnet
aws rds restore-db-instance-from-db-snapshot \
  --db-instance-identifier "${RESTORE_DB_ID}" \
  --db-snapshot-identifier "${SNAPSHOT_ID}" \
  --db-instance-class db.t3.micro \
  --db-subnet-group-name restore-test-subnet-group \
  --no-publicly-accessible

# Warten bis verfügbar
aws rds wait db-instance-available \
  --db-instance-identifier "${RESTORE_DB_ID}"

# Verbindungstest
DB_ENDPOINT=$(aws rds describe-db-instances \
  --db-instance-identifier "${RESTORE_DB_ID}" \
  --query 'DBInstances[0].Endpoint.Address' \
  --output text)

echo "DB Endpoint: ${DB_ENDPOINT}"

# Datenintegritätstest
PSQL_CMD="psql -h ${DB_ENDPOINT} -U admin -d payment_db"
ROW_COUNT=$(${PSQL_CMD} -t -c "SELECT COUNT(*) FROM transactions WHERE created_at > NOW() - INTERVAL '24h'")
echo "Rows in last 24h: ${ROW_COUNT}"

# RTO messen
END_TIME=$(date +%s)
echo "Restore completed. Elapsed: $((END_TIME - START_TIME))s"

# Cleanup
aws rds delete-db-instance \
  --db-instance-identifier "${RESTORE_DB_ID}" \
  --skip-final-snapshot

Typische Fehlmuster

  • Backup im gleichen Account: Ransomware verschlüsselt Backups gemeinsam mit Produktionsdaten

  • Retentionsperiode = 1 Tag: Datenfehler, die erst nach 48h entdeckt werden, können nicht behoben werden

  • Restore-Test in derselben Umgebung wie Produktion: Test benutzt Produktionskonfiguration; im Ernstfall fehlen Ressourcen

  • Manuelle Restore-Anleitung veraltet: Service-URLs, Secrets und IAM-Rollen haben sich geändert

Metriken

  • Backup Success Rate: % der geplanten Backup-Jobs, die erfolgreich waren (Ziel: 100%)

  • Restore Test RTO: Tatsächliche Zeit bis zur Wiederherstellung beim letzten Restore-Test

  • Data Integrity Score: % der validierten Datenpunkte nach Restore (Ziel: 100%)

  • Backup Age: Alter des neuesten verfügbaren Backups (Ziel: < RPO)

Reifegrad

Level 1 – Keine Backups oder Ad-hoc Snapshots
Level 2 – Automatisierte Backups, nie getestet
Level 3 – PITR, Cross-Account, Restore quartalsweise getestet und dokumentiert
Level 4 – Automatisierter monatlicher Restore-Test in Pipeline
Level 5 – WORM-Backups, CDP, kontinuierliche Backup-Integritätsvalidierung