TL;DR
- Usa AWS Backup restore testing para validar automáticamente que los backups cumplen objetivos RTO/RPO—backups no probados no son backups
- Automatiza testing DR con Terraform: levanta infraestructura de recuperación, valida funcionalidad, destruye—paga solo por la duración del test
- Prueba procedimientos de recuperación trimestralmente como mínimo; documenta cada paso y haz que personal que no escribió la documentación realice la restauración
Ideal para: Equipos con cargas de trabajo en producción que requieren capacidades de recuperación documentadas y requisitos de compliance No recomendado si: Ejecutas aplicaciones stateless sin datos persistentes (solo redespliega desde IaC) Tiempo de lectura: 15 minutos
Los backups que no se prueban minan la confianza en la recuperabilidad de datos. Estudios muestran que 34% de las empresas no prueban sus backups, y de las que lo hacen, 77% han encontrado fallos durante pruebas de restauración. Tu plan DR es tan bueno como tu última prueba exitosa.
Para testing de infraestructura relacionado, consulta Estrategias de Testing de Terraform y Testing de Infraestructura AWS.
Enfoques Asistidos por IA
Las herramientas de IA destacan generando planes de pruebas DR y analizando procedimientos de recuperación en busca de brechas.
Generando planes comprehensivos de pruebas DR:
Crea un plan de pruebas de disaster recovery para una aplicación web de tres capas:
- Capa web: Auto Scaling group con ALB
- Capa app: Servicios ECS Fargate
- Capa datos: RDS PostgreSQL Multi-AZ con Read Replicas
Incluye pruebas para:
1. Fallo de una sola AZ (verificar failover automático)
2. Fallo completo de región (verificar DR cross-region)
3. Corrupción de datos (verificar recuperación point-in-time)
4. Escenario de ransomware (verificar recuperación de backup aislado)
Para cada escenario, especifica: método de activación, RTO/RPO esperado,
pasos de validación, procedimiento de rollback y criterios de éxito.
Creando infraestructura DR con Terraform:
Escribe módulos Terraform para disaster recovery en AWS con:
1. Replicación RDS cross-region con failover automatizado
2. Replicación S3 cross-region con versionado
3. Health checks de Route 53 con failover DNS
4. Función Lambda activada por alarma CloudWatch para iniciar DR
Incluye variables para objetivos RTO/RPO y outputs para monitoreo.
Muestra cómo probar el failover sin afectar producción.
Analizando brechas de cobertura de backup:
Revisa esta configuración de backup AWS en busca de brechas:
Plan de Backup:
- RDS: Snapshots diarios, retención 7 días
- EBS: Snapshots semanales, retención 30 días
- S3: Sin backup (solo replicación cross-region)
- DynamoDB: Backups on-demand antes de deployments
Requisitos de aplicación:
- RPO: 1 hora para base de datos, 4 horas para almacenamiento de archivos
- RTO: 2 horas para recuperación completa
- Compliance: SOC 2, requiere retención de 90 días
Identifica brechas, problemas de compliance y recomendaciones.
Cuándo Usar Diferentes Enfoques de Testing
Framework de Decisión de Estrategia de Testing
| Tipo de Test | Frecuencia | Qué Valida | Impacto en Producción |
|---|---|---|---|
| Validación de backup | Diario (automatizado) | Backups son restaurables | Ninguno |
| Failover de componentes | Mensual | Recuperación de servicio individual | Mínimo (usa réplicas) |
| Ejercicio DR completo | Trimestral | Procedimiento completo de recuperación | Ventana de mantenimiento programada |
| Chaos engineering | Continuo | Resiliencia del sistema | Radio de impacto controlado |
| Ejercicio de mesa | Anual | Procedimientos humanos y comunicación | Ninguno |
Matriz de Estrategia RTO/RPO
| Estrategia | RTO | RPO | Costo | Caso de Uso |
|---|---|---|---|---|
| Backup & Restore | Horas | Horas | $ | Sistemas no críticos |
| Pilot Light | 10-30 min | Minutos | $$ | Sistemas de negocio core |
| Warm Standby | Minutos | Casi cero | $$$ | Aplicaciones críticas |
| Multi-Site Active | Casi cero | Casi cero | $$$$ | Misión crítica |
AWS Backup Restore Testing
Validación Automatizada de Backups
# Crear plan de testing de restauración
aws backup create-restore-testing-plan \
--restore-testing-plan-name "daily-validation" \
--schedule-expression "cron(0 6 * * ? *)" \
--start-window-hours 1 \
--recovery-point-selection '{
"Algorithm": "LATEST_WITHIN_WINDOW",
"RecoveryPointTypes": ["SNAPSHOT"],
"SelectionWindowDays": 1
}'
# Agregar RDS al plan de testing
aws backup create-restore-testing-selection \
--restore-testing-plan-name "daily-validation" \
--restore-testing-selection-name "rds-validation" \
--protected-resource-type "RDS" \
--iam-role-arn "arn:aws:iam::123456789012:role/BackupRestoreRole" \
--protected-resource-conditions '{
"StringEquals": [
{"Key": "aws:ResourceTag/Environment", "Value": "production"}
]
}'
Terraform para AWS Backup
# modules/backup-testing/main.tf
resource "aws_backup_plan" "production" {
name = "production-backup-plan"
rule {
rule_name = "daily-backups"
target_vault_name = aws_backup_vault.production.name
schedule = "cron(0 5 * * ? *)"
lifecycle {
delete_after = 90 # Compliance SOC 2
}
copy_action {
destination_vault_arn = aws_backup_vault.dr_region.arn
lifecycle {
delete_after = 90
}
}
}
rule {
rule_name = "hourly-backups"
target_vault_name = aws_backup_vault.production.name
schedule = "cron(0 * * * ? *)"
lifecycle {
delete_after = 7
}
}
}
resource "aws_backup_selection" "production_rds" {
iam_role_arn = aws_iam_role.backup.arn
name = "production-rds"
plan_id = aws_backup_plan.production.id
selection_tag {
type = "STRINGEQUALS"
key = "Backup"
value = "true"
}
resources = [
"arn:aws:rds:*:*:db:*",
"arn:aws:rds:*:*:cluster:*"
]
}
# Plan de testing de restauración
resource "aws_backup_restore_testing_plan" "validation" {
name = "automated-restore-validation"
recovery_point_selection {
algorithm = "LATEST_WITHIN_WINDOW"
recovery_point_types = ["SNAPSHOT"]
selection_window_days = 1
}
schedule_expression = "cron(0 8 * * ? *)"
}
Script Python para Validación de Backup
import boto3
import time
from datetime import datetime, timedelta
class BackupValidator:
def __init__(self, region='us-east-1'):
self.backup = boto3.client('backup', region_name=region)
self.rds = boto3.client('rds', region_name=region)
def validate_rds_backup(self, db_identifier, max_age_hours=24):
"""Validar que existe backup RDS y es restaurable."""
# Obtener snapshot más reciente
snapshots = self.rds.describe_db_snapshots(
DBInstanceIdentifier=db_identifier,
SnapshotType='automated'
)['DBSnapshots']
if not snapshots:
return {'status': 'FAILED', 'reason': 'No se encontraron snapshots'}
latest = max(snapshots, key=lambda x: x['SnapshotCreateTime'])
age = datetime.now(latest['SnapshotCreateTime'].tzinfo) - latest['SnapshotCreateTime']
if age > timedelta(hours=max_age_hours):
return {
'status': 'WARNING',
'reason': f'Snapshot más reciente tiene {age.total_seconds()/3600:.1f} horas'
}
# Verificar que snapshot está disponible
if latest['Status'] != 'available':
return {'status': 'FAILED', 'reason': f"Estado de snapshot: {latest['Status']}"}
return {
'status': 'PASSED',
'snapshot_id': latest['DBSnapshotIdentifier'],
'snapshot_age_hours': age.total_seconds() / 3600
}
def test_restore(self, snapshot_id, test_db_identifier):
"""Realizar prueba real de restauración."""
try:
# Iniciar restauración
self.rds.restore_db_instance_from_db_snapshot(
DBInstanceIdentifier=test_db_identifier,
DBSnapshotIdentifier=snapshot_id,
DBInstanceClass='db.t3.micro', # Mínimo para testing
PubliclyAccessible=False,
Tags=[{'Key': 'Purpose', 'Value': 'DR-Test'}]
)
# Esperar restauración
start_time = time.time()
waiter = self.rds.get_waiter('db_instance_available')
waiter.wait(DBInstanceIdentifier=test_db_identifier)
restore_time = time.time() - start_time
return {
'status': 'PASSED',
'restore_time_seconds': restore_time,
'meets_rto': restore_time < 7200 # RTO de 2 horas
}
finally:
# Limpiar instancia de prueba
try:
self.rds.delete_db_instance(
DBInstanceIdentifier=test_db_identifier,
SkipFinalSnapshot=True,
DeleteAutomatedBackups=True
)
except Exception:
pass
# Uso en pytest
def test_production_db_backup():
validator = BackupValidator()
result = validator.validate_rds_backup('production-db')
assert result['status'] in ['PASSED', 'WARNING'], f"Validación de backup falló: {result}"
Testing de Azure Site Recovery
Test Failover con Azure CLI
# Crear plan de recuperación
az site-recovery recovery-plan create \
--resource-group rg-dr \
--vault-name vault-dr \
--name "webapp-recovery-plan" \
--primary-zone "East US" \
--recovery-zone "West US" \
--failover-deployment-model "Resource"
# Ejecutar test failover (no disruptivo)
az site-recovery recovery-plan test-failover \
--resource-group rg-dr \
--vault-name vault-dr \
--name "webapp-recovery-plan" \
--failover-direction "PrimaryToRecovery" \
--network-id "/subscriptions/.../test-vnet"
# Validar entorno de prueba
az vm list --resource-group rg-dr-test --output table
# Limpiar test failover
az site-recovery recovery-plan test-failover-cleanup \
--resource-group rg-dr \
--vault-name vault-dr \
--name "webapp-recovery-plan"
Terraform para Azure DR
# modules/azure-dr/main.tf
resource "azurerm_recovery_services_vault" "dr" {
name = "vault-dr-${var.environment}"
location = var.dr_region
resource_group_name = azurerm_resource_group.dr.name
sku = "Standard"
soft_delete_enabled = true
}
resource "azurerm_site_recovery_fabric" "primary" {
name = "fabric-primary"
resource_group_name = azurerm_resource_group.dr.name
recovery_vault_name = azurerm_recovery_services_vault.dr.name
location = var.primary_region
}
resource "azurerm_site_recovery_fabric" "secondary" {
name = "fabric-secondary"
resource_group_name = azurerm_resource_group.dr.name
recovery_vault_name = azurerm_recovery_services_vault.dr.name
location = var.dr_region
}
resource "azurerm_site_recovery_replication_policy" "policy" {
name = "replication-policy"
resource_group_name = azurerm_resource_group.dr.name
recovery_vault_name = azurerm_recovery_services_vault.dr.name
recovery_point_retention_in_minutes = 1440 # 24 horas
application_consistent_snapshot_frequency_in_minutes = 60 # RPO 1 hora
}
# Política de backup para VMs
resource "azurerm_backup_policy_vm" "daily" {
name = "daily-backup-policy"
resource_group_name = azurerm_resource_group.dr.name
recovery_vault_name = azurerm_recovery_services_vault.dr.name
backup {
frequency = "Daily"
time = "23:00"
}
retention_daily {
count = 30
}
retention_weekly {
count = 12
weekdays = ["Sunday"]
}
retention_monthly {
count = 12
weekdays = ["Sunday"]
weeks = ["First"]
}
}
Testing DR Automatizado con Terraform
Entorno de Prueba DR Efímero
# dr-test/main.tf - Levantar, probar, destruir
variable "run_dr_test" {
description = "Establecer a true para ejecutar prueba DR"
type = bool
default = false
}
# Solo crear recursos durante prueba DR
resource "aws_db_instance" "dr_test" {
count = var.run_dr_test ? 1 : 0
identifier = "dr-test-${formatdate("YYYYMMDD", timestamp())}"
instance_class = "db.t3.medium"
# Restaurar desde snapshot más reciente
snapshot_identifier = data.aws_db_snapshot.latest.id
vpc_security_group_ids = [aws_security_group.dr_test[0].id]
db_subnet_group_name = aws_db_subnet_group.dr_test[0].name
skip_final_snapshot = true
deletion_protection = false
tags = {
Purpose = "DR-Test"
AutoClean = "true"
}
}
data "aws_db_snapshot" "latest" {
db_instance_identifier = var.production_db_identifier
most_recent = true
}
# Probar conectividad de aplicación
resource "null_resource" "validate_dr" {
count = var.run_dr_test ? 1 : 0
depends_on = [aws_db_instance.dr_test]
provisioner "local-exec" {
command = <<-EOT
# Esperar que DB esté lista
aws rds wait db-instance-available \
--db-instance-identifier ${aws_db_instance.dr_test[0].identifier}
# Ejecutar test de conectividad
python3 scripts/validate_dr.py \
--endpoint ${aws_db_instance.dr_test[0].endpoint} \
--expected-tables 50 \
--expected-rows 1000000
# Registrar RTO
echo "Prueba DR completada. RTO: $(cat /tmp/dr_rto.txt)"
EOT
}
}
output "dr_test_results" {
value = var.run_dr_test ? {
db_endpoint = aws_db_instance.dr_test[0].endpoint
restore_time = timestamp()
status = "Entorno de prueba listo"
} : null
}
Workflow GitHub Actions para Prueba DR
name: Prueba DR Trimestral
on:
schedule:
- cron: '0 6 1 */3 *' # Primer día del trimestre a las 6 AM
workflow_dispatch:
inputs:
test_type:
description: 'Tipo de prueba DR'
required: true
default: 'backup-restore'
type: choice
options:
- backup-restore
- failover
- full-dr
jobs:
dr-test:
runs-on: ubuntu-latest
environment: dr-test
steps:
- uses: actions/checkout@v4
- name: Configurar credenciales AWS
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.DR_TEST_ROLE_ARN }}
aws-region: us-west-2 # Región DR
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
- name: Iniciar Prueba DR
id: start_test
run: |
START_TIME=$(date +%s)
echo "start_time=$START_TIME" >> $GITHUB_OUTPUT
echo "Prueba DR iniciada a las $(date)"
- name: Desplegar Entorno DR
run: |
cd terraform/dr-test
terraform init
terraform apply -auto-approve -var="run_dr_test=true"
- name: Validar Recuperación
id: validate
run: |
cd terraform/dr-test
DB_ENDPOINT=$(terraform output -raw dr_test_db_endpoint)
# Probar conectividad de base de datos
python3 scripts/validate_dr.py \
--endpoint "$DB_ENDPOINT" \
--test-queries \
--output-file dr-results.json
# Calcular RTO
END_TIME=$(date +%s)
START_TIME=${{ steps.start_test.outputs.start_time }}
RTO=$((END_TIME - START_TIME))
echo "rto_seconds=$RTO" >> $GITHUB_OUTPUT
- name: Limpiar Prueba DR
if: always()
run: |
cd terraform/dr-test
terraform destroy -auto-approve -var="run_dr_test=true"
- name: Generar Reporte
run: |
cat << EOF > dr-report.md
# Reporte de Prueba DR - $(date +%Y-%m-%d)
## Resultados
- **Tipo de Prueba**: ${{ inputs.test_type || 'backup-restore' }}
- **RTO Real**: ${{ steps.validate.outputs.rto_seconds }} segundos
- **RTO Objetivo**: 7200 segundos (2 horas)
- **Estado**: $([[ ${{ steps.validate.outputs.rto_seconds }} -lt 7200 ]] && echo "APROBADO" || echo "FALLIDO")
## Detalles de Validación
$(cat dr-results.json | jq -r '.summary')
EOF
- name: Subir Reporte
uses: actions/upload-artifact@v4
with:
name: dr-test-report
path: dr-report.md
- name: Notificar en Fallo
if: failure()
run: |
# Enviar alerta si prueba DR falló
aws sns publish \
--topic-arn ${{ secrets.ALERTS_TOPIC_ARN }} \
--message "Prueba DR FALLIDA. Revisión requerida."
Midiendo el Éxito
| Métrica | Objetivo | Cómo Rastrear |
|---|---|---|
| Tasa de éxito de backup | 100% | Dashboards AWS Backup/Azure Backup |
| Tasa de éxito de pruebas de restauración | 100% | Resultados de tests automatizados |
| RTO real vs Objetivo | Real < Objetivo | Mediciones de pruebas DR |
| RPO real vs Objetivo | Real < Objetivo | Análisis de timestamps de backup |
| Frecuencia de pruebas DR | Trimestral mínimo | Seguimiento en calendario |
| Vigencia de documentación | Actualizada después de cada prueba | Fecha de última modificación |
Señales de que tu testing DR no funciona:
- Pruebas de restauración consistentemente omitidas por “restricciones de tiempo”
- Mediciones de RTO no incluyen tiempo de coordinación humana
- Backups existen pero nadie conoce el procedimiento de restauración
- Documentación DR referencia infraestructura obsoleta
- Lag de replicación cross-region no monitoreado
Conclusión
El testing efectivo de backup y DR requiere automatización y validación regular:
- Automatiza validación de backup con AWS Backup restore testing o herramientas similares
- Prueba restauraciones regularmente—ejercicios DR completos trimestralmente como mínimo
- Mide RTO/RPO durante pruebas reales, no estimaciones
- Documenta todo y haz que personal no familiarizado con procedimientos ejecute las pruebas
- Usa Terraform para crear entornos de prueba efímeros de forma rentable
La idea clave: backups no probados no son backups. La única forma de saber que tu plan DR funciona es ejecutarlo regularmente. Automatiza lo que puedas, pero asegura que los procedimientos humanos también se prueben.
Ver También
- Estrategias de Testing de Terraform - Fundamentos de testing de infraestructura
- Testing de Infraestructura AWS - Estrategias más amplias de testing AWS
- Testing de Compliance para IaC - Cumpliendo requisitos de compliance DR
- Testing de Configuración de Red - Validando conectividad de red DR
- Testing de Escalabilidad de Infraestructura - Pruebas de carga para entornos DR
