erp-construccion/docs/02-definicion-modulos/MAI-013-administracion-seguridad/requerimientos/RF-ADM-005-backups.md

764 lines
20 KiB
Markdown

# RF-ADM-005: Backups Automáticos y Disaster Recovery
**ID:** RF-ADM-005
**Módulo:** MAI-013 - Administración & Seguridad
**Tipo:** Requerimiento Funcional
**Prioridad:** P0 (Crítica)
**Fecha de creación:** 2025-11-20
**Versión:** 1.0
---
## 📋 Descripción
El sistema debe proporcionar **backups automáticos** y un plan de **Disaster Recovery (DR)** que garantice:
- **Backups automáticos** programados sin intervención manual
- **Estrategia 3-2-1:** 3 copias, 2 medios diferentes, 1 copia offsite
- **Restauración rápida:** RTO < 4 horas, RPO < 1 hora
- **Verificación de integridad:** Checksums MD5/SHA-256
- **Pruebas mensuales** de restauración
- **Alertas** de backups fallidos
La estrategia de backups es fundamental para garantizar **continuidad del negocio** ante desastres (fallas de hardware, ataques ransomware, errores humanos).
---
## 🎯 Objetivos
### Objetivos de Negocio
1. **Protección de datos:** Cero pérdida de datos críticos
2. **Continuidad del negocio:** Recuperación rápida ante desastres
3. **Cumplimiento normativo:** ISO 27001, SOC 2, GDPR
4. **Confianza del cliente:** Datos siempre disponibles y seguros
5. **Reducción de riesgos:** Mitigación de ransomware, fallas, errores
### Objetivos Técnicos
1. **RTO (Recovery Time Objective):** < 4 horas
2. **RPO (Recovery Point Objective):** < 1 hora
3. **Automatización:** 100% de backups sin intervención manual
4. **Retención:** Según criticidad (7 días, 30 días, 1 año)
5. **Performance:** Backups no afectan operación del sistema
---
## 📊 Estrategia 3-2-1 de Backups
### Regla 3-2-1
**3 copias** de los datos:
- 1 copia en producción (activa)
- 2 copias de respaldo (backups)
**2 medios diferentes:**
- Local: NAS/SAN en oficina
- Cloud: AWS S3 / Azure Blob Storage
**1 copia offsite:**
- Geográficamente separada (otra ciudad/país)
- Protección contra desastres físicos (incendio, inundación)
### Implementación
```
┌─────────────────────────────────────────────────────────────┐
│ ESTRATEGIA 3-2-1 │
├─────────────────────────────────────────────────────────────┤
│ │
│ COPIA 1: Producción (Activa) │
│ └─> Servidor DB Principal (PostgreSQL) │
│ Ubicación: Culiacán, Sinaloa │
│ │
│ COPIA 2: Backup Local (Medio 1) │
│ └─> NAS/SAN en oficina │
│ Ubicación: Culiacán, Sinaloa │
│ Retención: 7 días │
│ │
│ COPIA 3: Backup Cloud (Medio 2 + Offsite) │
│ └─> AWS S3 / Azure Blob │
│ Ubicación: us-west-2 (Oregon, USA) │
│ Retención: 30 días (rolling) │
│ │
└─────────────────────────────────────────────────────────────┘
```
---
## 🗂️ Tipos de Backup
### 1. Full Backup (Completo)
**Frecuencia:** Diario (3:00 AM)
**Duración:** 2-4 horas (según tamaño)
**Retención:** 7 días
**Contenido:**
- Base de datos completa (PostgreSQL dump)
- Archivos subidos (documentos, evidencias, planos)
- Configuraciones del sistema
- Variables de entorno (secrets)
- Logs de aplicación (últimos 7 días)
**Comando (PostgreSQL):**
```bash
pg_dump -h localhost -U postgres -F c \
-f /backups/full/backup-$(date +%Y-%m-%d).dump \
erp_construccion
```
**Tamaño estimado:**
- DB pequeña (< 1 año): 5-10 GB
- DB mediana (1-3 años): 20-50 GB
- DB grande (> 3 años): 100-200 GB
**Ventajas:**
- ✅ Restauración más rápida (un solo archivo)
- ✅ Autónomo (no depende de backups anteriores)
**Desventajas:**
- ❌ Consume más espacio
- ❌ Más lento que incremental
---
### 2. Incremental Backup
**Frecuencia:** Cada 6 horas (00:00, 06:00, 12:00, 18:00)
**Duración:** 15-30 minutos
**Retención:** 48 horas
**Contenido:**
- Solo cambios desde el último backup (full o incremental)
- Archivos modificados/creados en últimas 6 horas
- Logs de aplicación nuevos
**Herramienta:** `rsync` o `pg_basebackup` con WAL archiving
**Comando (rsync):**
```bash
rsync -av --delete --link-dest=/backups/previous \
/var/lib/postgresql/data \
/backups/incremental/backup-$(date +%Y-%m-%d_%H-%M)
```
**Ventajas:**
- ✅ Rápido (solo cambios)
- ✅ Consume menos espacio
**Desventajas:**
- ❌ Restauración más lenta (requiere full + todos los incrementales)
---
### 3. Backup de Archivos Críticos
**Frecuencia:** Cada hora (top of the hour)
**Duración:** 5-10 minutos
**Retención:** 24 horas
**Contenido:**
- Documentos subidos (contratos, minutas)
- Evidencias fotográficas de obra
- Planos y documentación técnica
- Archivos CFDI (facturas electrónicas)
**Ubicaciones:**
```
/storage/documents/
/storage/photos/
/storage/plans/
/storage/invoices/
```
**Método:**
- Sincronización en tiempo real a AWS S3
- Versionado activado (conservar versiones anteriores)
**Ventajas:**
- ✅ RPO < 1 hora (baja pérdida de datos)
- Archivos versionados (recuperar versiones antiguas)
---
### 4. Snapshots de Base de Datos (PITR)
**Frecuencia:** Cada 30 minutos
**Duración:** Instantáneo
**Retención:** 6 horas
**Contenido:**
- Snapshot del filesystem de PostgreSQL
- WAL (Write-Ahead Logging) archiving
- Permite Point-In-Time Recovery
**Configuración PostgreSQL:**
```ini
# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'rsync %p /backups/wal/%f'
```
**Ventajas:**
- RPO mínimo (< 1 hora)
- Recuperación a cualquier punto en el tiempo
**Desventajas:**
- Requiere configuración avanzada
---
## 📅 Calendario de Backups
### Calendario Semanal
```
┌──────────┬────────┬────────────┬──────────┬──────────┐
│ Hora │ Lun-Dom│ Tipo │ Ubicación│ Retención│
├──────────┼────────┼────────────┼──────────┼──────────┤
│ 03:00 AM │ Diario │ Full │ Local+S3 │ 7 días │
│ 00:00 │ Diario │ Incremental│ Local │ 48 hrs │
│ 06:00 │ Diario │ Incremental│ Local │ 48 hrs │
│ 12:00 │ Diario │ Incremental│ Local │ 48 hrs │
│ 18:00 │ Diario │ Incremental│ Local │ 48 hrs │
│ Hourly │ Diario │ Archivos │ S3 │ 24 hrs │
│ :00/:30 │ Diario │ Snapshot │ Local │ 6 hrs │
└──────────┴────────┴────────────┴──────────┴──────────┘
```
### Calendario Mensual
**Primer domingo de cada mes:**
- Backup full completo con retención de **1 año**
- Prueba de restauración completa
- Reporte de integridad de backups
**Ejemplo:**
- Backup del 2025-12-01 se conserva hasta 2026-12-01
- Total: 12 backups mensuales por año
---
## 🔄 Proceso de Restauración
### Escenarios de Recuperación
#### Escenario 1: Recuperación de Archivo Individual
**Caso:** Usuario borró por error un contrato PDF
**RTO:** 15 minutos
**RPO:** < 1 hora
**Procedimiento:**
1. Usuario reporta: "Borré contrato-123.pdf por error"
2. Admin accede a AWS S3 console
3. Busca archivo en versiones anteriores
4. Descarga versión más reciente
5. Sube archivo nuevamente al sistema
6. Valida con usuario
**Herramienta:** AWS S3 Versioning
---
#### Escenario 2: Recuperación de Base de Datos a Punto Específico
**Caso:** Error en script SQL borró 500 registros a las 14:30
**RTO:** 1-2 horas
**RPO:** < 30 minutos
**Procedimiento:**
1. Identificar timestamp exacto del error: 2025-11-20 14:30
2. Detener aplicación (modo mantenimiento)
3. Crear backup de estado actual (por si acaso)
4. Restaurar base de datos a 2025-11-20 14:25 (5 min antes):
```bash
pg_restore -h localhost -U postgres \
--clean --if-exists \
/backups/full/backup-2025-11-20.dump
```
5. Aplicar WAL logs hasta 14:25:
```bash
pg_wal_replay --target-time='2025-11-20 14:25:00'
```
6. Verificar integridad de datos
7. Reiniciar aplicación
8. Validar con usuarios clave
**Resultado:** Recuperados 500 registros, pérdida de datos: 5 minutos.
---
#### Escenario 3: Disaster Recovery (Servidor Completo)
**Caso:** Servidor físico destruido por incendio
**RTO:** 4-8 horas
**RPO:** < 1 hora
**Procedimiento:**
**Fase 1: Provisionamiento (2 horas)**
1. Provisionar nueva infraestructura:
- Servidor cloud (AWS EC2 / Azure VM)
- Disco de 500 GB SSD
- Configuración de red (VPC, Security Groups)
2. Instalar sistema operativo (Ubuntu 22.04 LTS)
3. Instalar PostgreSQL 15
4. Instalar Node.js 20, npm, pm2
**Fase 2: Restauración de Datos (2 horas)**
5. Descargar último full backup desde AWS S3:
```bash
aws s3 cp s3://backups-empresa/backup-2025-11-20.dump .
```
6. Restaurar base de datos:
```bash
pg_restore -h localhost -U postgres \
--clean --create \
backup-2025-11-20.dump
```
7. Sincronizar archivos desde S3:
```bash
aws s3 sync s3://storage-empresa/documents /storage/documents
aws s3 sync s3://storage-empresa/photos /storage/photos
```
8. Restaurar configuraciones:
```bash
aws s3 cp s3://backups-empresa/configs/env .env
```
**Fase 3: Validación y Reinicio (1 hora)**
9. Validar integridad de datos:
```sql
SELECT COUNT(*) FROM projects; -- Debe coincidir con último reporte
SELECT COUNT(*) FROM users;
```
10. Ejecutar smoke tests:
- Login funciona
- Proyectos se listan correctamente
- Crear registro de prueba
11. Reconfigurar DNS:
```
app.ejemplo.com Nueva IP: 54.123.45.67
```
12. Reiniciar aplicación:
```bash
pm2 start ecosystem.config.js
pm2 logs --lines 100
```
13. Notificar a usuarios: "Sistema restaurado, funcionando normalmente"
**Fase 4: Post-Mortem (1 hora)**
14. Reunión de equipo para analizar incidente
15. Documentar lecciones aprendidas
16. Actualizar plan de DR si es necesario
**Resultado:** Sistema en línea en 4-8 horas, pérdida de datos < 1 hora.
---
## 🔒 Seguridad de Backups
### Encriptación
**En tránsito (upload a S3):**
```bash
aws s3 cp backup.dump s3://backups/ \
--sse AES256 \
--storage-class STANDARD_IA
```
**En reposo (S3):**
- Server-Side Encryption (SSE-S3 o SSE-KMS)
- Archivos cifrados con AES-256
**Backups locales:**
```bash
# Cifrar backup antes de almacenar
gpg --symmetric --cipher-algo AES256 backup.dump
```
### Control de Acceso
**AWS S3 Bucket Policy:**
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:DeleteObject",
"Resource": "arn:aws:s3:::backups-empresa/*"
}
]
}
```
**Resultado:** Backups no se pueden eliminar, solo agregar nuevos.
**Acceso:**
- Solo Admin de TI tiene credenciales de S3
- MFA requerido para acceder a S3 console
- Logs de acceso activados (CloudTrail)
---
## ✅ Verificación de Integridad
### Checksums MD5/SHA-256
**Al crear backup:**
```bash
# Crear backup
pg_dump -F c -f backup.dump erp_construccion
# Calcular checksum
sha256sum backup.dump > backup.dump.sha256
```
**Al restaurar:**
```bash
# Verificar checksum antes de restaurar
sha256sum -c backup.dump.sha256
# Si OK, proceder con restauración
```
### Validación de Contenido
**Tests automáticos post-backup:**
```bash
#!/bin/bash
# validate-backup.sh
# Restaurar en DB temporal
createdb backup_test
pg_restore -d backup_test backup.dump
# Ejecutar queries de validación
psql -d backup_test -c "SELECT COUNT(*) FROM users;" > users_count.txt
psql -d backup_test -c "SELECT COUNT(*) FROM projects;" > projects_count.txt
# Comparar con producción
diff users_count.txt /backups/validation/users_count_prod.txt
# Si diff vacío, backup OK
if [ $? -eq 0 ]; then
echo "✅ Backup válido"
else
echo "❌ Backup corrupto, enviar alerta"
fi
# Limpiar
dropdb backup_test
```
---
## 📋 Modelo de Datos de Backup
```typescript
interface BackupRecord {
// Identificación
id: string; // UUID
timestamp: Date;
backupType: BackupType; // full | incremental | files | snapshot
// Ubicación
storagePath: string; // "/backups/full/backup-2025-11-20.dump"
s3Url?: string; // "s3://backups-empresa/backup-2025-11-20.dump"
storageTier: 'local' | 's3_standard' | 's3_glacier';
// Tamaño y compresión
sizeBytes: number;
sizeCompressed?: number;
compressionRatio?: number; // %
// Integridad
checksum: string; // SHA-256
checksumAlgorithm: 'md5' | 'sha256';
isVerified: boolean;
verifiedAt?: Date;
// Metadata
databaseVersion: string; // "PostgreSQL 15.3"
schemaVersion: string; // "v2.5.0"
recordCount?: {
users: number;
projects: number;
budgets: number;
// ...
};
// Estado
status: BackupStatus; // pending | in_progress | completed | failed | verified
startedAt: Date;
completedAt?: Date;
duration?: number; // Segundos
// Retención
retentionDays: number; // 7, 30, 365
expiresAt: Date;
isDeleted: boolean;
// Errores
errorMessage?: string;
errorDetails?: string;
// Restauración
lastRestoreTest?: Date;
restoreTestSuccess?: boolean;
}
enum BackupType {
FULL = 'full',
INCREMENTAL = 'incremental',
FILES = 'files',
SNAPSHOT = 'snapshot'
}
enum BackupStatus {
PENDING = 'pending',
IN_PROGRESS = 'in_progress',
COMPLETED = 'completed',
FAILED = 'failed',
VERIFIED = 'verified'
}
```
---
## 🚨 Alertas de Backups
### Configuración de Alertas
| Condición | Severidad | Destinatarios | Canal |
|-----------|-----------|---------------|-------|
| **Backup fallido** | Critical | Admin TI + Director | Email + SMS |
| **Backup > 2 horas** | High | Admin TI | Email |
| **Checksum inválido** | Critical | Admin TI | Email + SMS |
| **Disco > 80% lleno** | High | Admin TI | Email |
| **Prueba restauración fallida** | Critical | Admin TI + Director | Email + SMS |
| **Backup no ejecutado** | Critical | Admin TI | Email + SMS |
### Ejemplo de Alerta
**Asunto:** 🚨 CRÍTICO: Backup Full Fallido
```
Estimado Administrador,
El backup full programado para hoy falló:
Tipo: Full Backup
Fecha/Hora: 2025-11-20 03:00 AM
Duración: 35 minutos (abortado)
Error: "Disk quota exceeded"
Detalles del error:
- Disco /backups al 98% de capacidad
- Backup abortado tras escribir 45 GB de 50 GB
Acciones recomendadas:
1. Liberar espacio en disco /backups
2. Ejecutar backup manualmente
3. Verificar integridad del último backup exitoso (2025-11-19)
Último backup exitoso: 2025-11-19 03:00 AM (24 horas atrás)
⚠️ Acción inmediata requerida
---
Sistema de Backups Automáticos
Constructora ABC
```
---
## 📋 Casos de Uso
### Caso 1: Prueba Mensual de Restauración
**Actor:** Admin de TI (automatizado)
**Flujo:**
1. Primer domingo del mes a las 02:00 AM
2. Cron job ejecuta script: `monthly-restore-test.sh`
3. Script:
- Descarga último full backup desde S3
- Verifica checksum
- Crea base de datos temporal `erp_restore_test`
- Restaura backup completo
- Ejecuta 20 queries de validación
- Compara resultados con producción
- Genera reporte HTML
4. Si exitoso:
- Marca backup como `verified`
- Envía reporte a Admin TI y Director
5. Si falla:
- Alerta crítica por email + SMS
- Reporte de error detallado
**Resultado:** Confianza mensual de que backups funcionan.
---
### Caso 2: Ataque Ransomware
**Contexto:** Ransomware cifra toda la base de datos de producción
**Flujo:**
1. 08:30 AM - Usuarios reportan: "Sistema no funciona, pide pago de $50K BTC"
2. Admin identifica ransomware
3. **Decisión: No pagar, restaurar desde backup**
4. Admin:
- Aísla servidor infectado (desconecta red)
- Provisiona nuevo servidor limpio
- Descarga último backup (ayer 03:00 AM)
- Restaura base de datos
- Restaura archivos desde S3
5. 12:00 PM - Sistema en línea
6. Pérdida de datos: 5.5 horas (desde 03:00 AM backup hasta 08:30 AM ataque)
7. Post-mortem:
- Identificar vector de ataque
- Actualizar firewall rules
- Capacitar usuarios en phishing
**Resultado:** Ataque mitigado sin pagar rescate, pérdida < 6 horas.
---
## ✅ Criterios de Aceptación
### AC1: Backups Automáticos sin Falla
**DADO** el sistema configurado correctamente
**CUANDO** se ejecuta cron job de backup full a las 03:00 AM
**ENTONCES**
- Backup se ejecuta automáticamente (sin intervención)
- Backup se completa exitosamente en < 4 horas
- Archivo generado con checksum SHA-256
- Backup subido a S3 con encriptación
- Backup local guardado en NAS
- Registro creado en tabla `backup_records`
- Si falla, alerta enviada inmediatamente
### AC2: Estrategia 3-2-1 Implementada
**DADO** un backup full exitoso
**CUANDO** se valida la estrategia
**ENTONCES**
- 3 copias existen:
- Producción (activa)
- Backup local (NAS)
- Backup cloud (S3)
- 2 medios diferentes:
- Local (NAS)
- Cloud (S3)
- 1 copia offsite:
- S3 en región diferente (us-west-2)
### AC3: Restauración < RTO
**DADO** un desastre que requiere restauración completa
**CUANDO** se ejecuta plan de DR
**ENTONCES**
- Sistema completamente restaurado en < 4 horas (RTO)
- Pérdida de datos < 1 hora (RPO)
- Integridad de datos validada (checksums OK)
- Aplicación funcional y accesible
### AC4: Pruebas Mensuales Exitosas
**DADO** el primer domingo del mes
**CUANDO** se ejecuta prueba de restauración
**ENTONCES**
- Backup se restaura en DB temporal exitosamente
- Queries de validación retornan resultados esperados
- Reporte HTML generado automáticamente
- Email enviado a Admin y Director
- Si falla, alerta crítica enviada
### AC5: Retención Automática
**DADO** backups con diferentes retenciones
**CUANDO** pasa el periodo de retención
**ENTONCES**
- Backups diarios eliminados tras 7 días
- Backups incrementales eliminados tras 48 horas
- Backups mensuales conservados 1 año
- Proceso de limpieza ejecuta automáticamente
---
## 🧪 Escenarios de Prueba
### Test 1: Backup Full Exitoso
```typescript
describe('RF-ADM-005: Full Backup', () => {
it('should create full backup successfully', async () => {
const backupService = new BackupService();
const result = await backupService.createFullBackup();
expect(result.status).toBe('completed');
expect(result.sizeBytes).toBeGreaterThan(0);
expect(result.checksum).toBeDefined();
expect(result.isVerified).toBe(true);
expect(result.s3Url).toContain('s3://backups-empresa');
// Verificar archivo existe
const fileExists = await fs.pathExists(result.storagePath);
expect(fileExists).toBe(true);
});
});
```
### Test 2: Restauración Point-in-Time
```typescript
describe('RF-ADM-005: Point-in-Time Recovery', () => {
it('should restore database to specific timestamp', async () => {
// Crear datos iniciales
await createProject({ name: 'Proyecto 1' });
const snapshot1 = new Date();
await sleep(1000);
// Crear más datos
await createProject({ name: 'Proyecto 2' });
// Restaurar a snapshot1 (antes de Proyecto 2)
await restoreToPointInTime(snapshot1);
// Validar
const projects = await db.query('SELECT * FROM projects');
expect(projects.rows).toHaveLength(1);
expect(projects.rows[0].name).toBe('Proyecto 1');
});
});
```
---
## 🔗 Referencias
- **Especificación técnica:** [ET-ADM-004](../especificaciones/ET-ADM-004-backups-dr.md)
- **Historia de usuario:** [US-ADM-005](../historias-usuario/US-ADM-005-backups-automaticos.md), [US-ADM-006](../historias-usuario/US-ADM-006-restaurar-backup.md)
- **RF relacionado:** [RF-ADM-004](./RF-ADM-004-auditoria.md)
- **Módulo:** [README.md](../README.md)
---
**Generado:** 2025-11-20
**Versión:** 1.0
**Autor:** Sistema de Documentación Técnica
**Estado:** Completo