Cumplimiento y auditoría
Cumplimiento normativo y auditoría en sistemas distribuidos: logs de auditoría, GDPR, cifrado de datos, retención y trazabilidad de acciones.
Por qué el cumplimiento importa en arquitectura
El cumplimiento normativo no es solo un tema legal — tiene implicaciones directas en cómo se diseña y opera un sistema. Regulaciones como GDPR, PCI-DSS o SOC 2 imponen requisitos técnicos concretos sobre cómo se almacenan, procesan y protegen los datos.
Ignorar el cumplimiento durante el diseño de la arquitectura significa tener que hacer cambios costosos después, o peor, enfrentar sanciones legales y pérdida de confianza de los usuarios.
Logs de auditoría
Los logs de auditoría registran quién hizo qué, cuándo y sobre qué recurso. Son la base de cualquier estrategia de cumplimiento.
Qué registrar
No todo necesita un log de auditoría. Enfócate en:
- Autenticación: login exitoso, login fallido, logout, cambio de contraseña
- Autorización: acceso denegado, cambio de roles o permisos
- Datos sensibles: lectura, creación, modificación o eliminación de datos personales
- Configuración: cambios en configuración del sistema, despliegues
- Operaciones críticas: transacciones financieras, eliminación de cuentas, exportación de datos
Estructura de un log de auditoría
{
"timestamp": "2024-01-15T14:30:00.000Z",
"eventType": "DATA_ACCESS",
"action": "READ",
"actor": {
"userId": "user-456",
"role": "admin",
"ip": "192.168.1.100",
"userAgent": "Mozilla/5.0..."
},
"resource": {
"type": "user_profile",
"id": "user-789",
"fields": ["email", "phone", "address"]
},
"result": "SUCCESS",
"metadata": {
"service": "users-service",
"requestId": "req-abc-123",
"traceId": "trace-xyz-789"
}
}
Propiedades de un buen log de auditoría
| Propiedad | Descripción |
|---|---|
| Inmutable | Una vez escrito, no se puede modificar ni eliminar |
| Completo | Contiene toda la información necesaria para reconstruir el evento |
| Trazable | Se puede correlacionar con otros logs mediante requestId o traceId |
| Seguro | Protegido contra acceso no autorizado y manipulación |
| Retenido | Almacenado durante el período requerido por la regulación |
Implementación práctica
class AuditLogger {
async log(event) {
const auditEntry = {
timestamp: new Date().toISOString(),
eventType: event.type,
action: event.action,
actor: {
userId: event.userId,
role: event.userRole,
ip: event.clientIp,
},
resource: {
type: event.resourceType,
id: event.resourceId,
},
result: event.result,
metadata: {
service: process.env.SERVICE_NAME,
requestId: event.requestId,
traceId: event.traceId,
}
};
// Escribir en un almacenamiento inmutable
await this.auditStore.append(auditEntry);
// Nunca fallar silenciosamente en auditoría
// Si no se puede registrar, la operación debe fallar
}
}
Almacenamiento de logs de auditoría
Los logs de auditoría requieren almacenamiento especial:
- Append-only: solo se pueden agregar registros, nunca modificar o eliminar
- Separado: en una base de datos o servicio diferente al de la aplicación
- Cifrado: los logs pueden contener datos sensibles
- Replicado: copias en múltiples ubicaciones para prevenir pérdida
Opciones comunes:
- Amazon S3 con Object Lock (inmutabilidad)
- Elasticsearch con índices de solo lectura
- Base de datos dedicada con permisos de solo inserción
- Servicios especializados como Splunk o Datadog
GDPR y protección de datos personales
El Reglamento General de Protección de Datos (GDPR) de la Unión Europea establece requisitos estrictos sobre cómo se manejan los datos personales. Aunque es una regulación europea, afecta a cualquier sistema que procese datos de residentes de la UE.
Principios clave del GDPR
- Minimización de datos: solo recopilar los datos estrictamente necesarios
- Limitación de propósito: usar los datos solo para el fin declarado
- Limitación de almacenamiento: no retener datos más tiempo del necesario
- Integridad y confidencialidad: proteger los datos contra acceso no autorizado
- Responsabilidad proactiva: demostrar cumplimiento, no solo cumplir
Derechos del usuario que afectan la arquitectura
Derecho de acceso (Art. 15)
El usuario puede solicitar todos los datos que el sistema tiene sobre él:
// El sistema debe poder recopilar datos de TODOS los servicios
async function getUserData(userId) {
const [profile, orders, payments, logs] = await Promise.all([
usersService.getData(userId),
ordersService.getData(userId),
paymentsService.getData(userId),
auditService.getData(userId),
]);
return {
personalData: profile,
orderHistory: orders,
paymentHistory: payments,
activityLog: logs,
exportedAt: new Date().toISOString()
};
}
Esto implica que cada microservicio debe poder exportar los datos de un usuario específico.
Derecho al olvido (Art. 17)
El usuario puede solicitar la eliminación de todos sus datos:
async function deleteUserData(userId) {
// Eliminar de todos los servicios
await usersService.deleteUser(userId);
await ordersService.anonymizeOrders(userId);
await paymentsService.anonymizePayments(userId);
// Algunos datos no se pueden eliminar (obligaciones legales)
// pero se pueden anonimizar
await auditService.anonymizeEntries(userId);
// Registrar la eliminación (paradójicamente, esto sí se retiene)
await auditLogger.log({
type: 'DATA_DELETION',
action: 'DELETE',
userId: 'ANONYMIZED',
resourceId: userId
});
}
Derecho a la portabilidad (Art. 20)
El usuario puede solicitar sus datos en un formato legible por máquina:
{
"format": "JSON",
"exportDate": "2024-01-15",
"userData": {
"profile": { "name": "María García", "email": "maria@ejemplo.com" },
"orders": [
{ "id": "ord-001", "date": "2024-01-10", "total": 150.00 }
]
}
}
Implicaciones arquitectónicas del GDPR
- Cada servicio debe saber qué datos personales almacena
- Debe existir un mecanismo centralizado para ejecutar derechos del usuario
- Los datos deben poder anonimizarse sin romper la integridad del sistema
- Los logs de auditoría deben balancear retención con derecho al olvido
Cifrado de datos
Cifrado en tránsito
Todo dato que viaja por la red debe estar cifrado:
- TLS 1.2+ para comunicación externa
- mTLS para comunicación entre servicios
- Cifrado de mensajes en colas y buses de eventos
Cifrado en reposo
Los datos almacenados deben estar cifrados:
Niveles de cifrado en reposo:
1. Cifrado de disco (transparente)
- AWS EBS encryption, Azure Disk Encryption
- Protege contra robo físico del disco
2. Cifrado de base de datos (TDE)
- Transparent Data Encryption en PostgreSQL, MySQL
- Protege contra acceso directo a archivos de BD
3. Cifrado a nivel de campo (application-level)
- Campos específicos cifrados por la aplicación
- Protege incluso si la BD es comprometida
Cifrado a nivel de campo
Para datos especialmente sensibles, cifra campos individuales:
const crypto = require('crypto');
class FieldEncryption {
constructor(key) {
this.key = Buffer.from(key, 'hex');
}
encrypt(plaintext) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-gcm', this.key, iv);
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
encrypted += cipher.final('hex');
const tag = cipher.getAuthTag().toString('hex');
return `${iv.toString('hex')}:${tag}:${encrypted}`;
}
decrypt(ciphertext) {
const [ivHex, tagHex, encrypted] = ciphertext.split(':');
const iv = Buffer.from(ivHex, 'hex');
const tag = Buffer.from(tagHex, 'hex');
const decipher = crypto.createDecipheriv('aes-256-gcm', this.key, iv);
decipher.setAuthTag(tag);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
}
// Uso
const encryption = new FieldEncryption(process.env.ENCRYPTION_KEY);
const encryptedSSN = encryption.encrypt('123-45-6789');
Gestión de claves
Las claves de cifrado son tan sensibles como los datos que protegen:
- Nunca almacenar claves en el código fuente
- Usar un servicio de gestión de claves (KMS): AWS KMS, Azure Key Vault, HashiCorp Vault
- Rotar claves periódicamente
- Mantener claves separadas por entorno (desarrollo, staging, producción)
- Implementar envelope encryption para datos a gran escala
Retención de datos
Cada tipo de dato tiene un período de retención diferente según la regulación y el propósito:
| Tipo de dato | Retención típica | Razón |
|---|---|---|
| Logs de auditoría | 1–7 años | Cumplimiento regulatorio |
| Datos de transacciones | 5–10 años | Obligaciones fiscales |
| Datos personales | Mientras sea necesario | GDPR: minimización |
| Logs de aplicación | 30–90 días | Debugging y operaciones |
| Backups | 30–365 días | Recuperación ante desastres |
Implementación de políticas de retención
# Política de retención por tipo de dato
retention_policies:
audit_logs:
retention_days: 2555 # 7 años
storage: s3-archive
encryption: aes-256
immutable: true
application_logs:
retention_days: 90
storage: elasticsearch
auto_delete: true
user_data:
retention: until_deletion_request
anonymization: on_request
backup_retention_days: 30
transaction_data:
retention_days: 3650 # 10 años
storage: database
anonymization: after_retention
Trazabilidad de acciones
En un sistema distribuido, una acción del usuario puede involucrar múltiples servicios. La trazabilidad permite reconstruir el camino completo:
Usuario solicita eliminar su cuenta
→ API Gateway (request recibido)
→ BFF (orquesta eliminación)
→ Users Service (elimina perfil)
→ Orders Service (anonimiza órdenes)
→ Payments Service (anonimiza pagos)
→ Notifications Service (envía confirmación)
→ Audit Service (registra la operación completa)
Correlation ID
Cada request genera un ID único que se propaga a todos los servicios:
// Middleware que genera o propaga el correlation ID
function correlationMiddleware(req, res, next) {
const correlationId = req.headers['x-correlation-id'] || uuid();
req.correlationId = correlationId;
res.setHeader('x-correlation-id', correlationId);
// Incluir en todos los logs
req.logger = logger.child({ correlationId });
next();
}
Con el correlation ID, puedes buscar en los logs de todos los servicios y reconstruir exactamente qué pasó en cada paso.
Checklist de cumplimiento
Para verificar que tu arquitectura cumple con los requisitos básicos:
- Los logs de auditoría son inmutables y están cifrados
- Cada servicio puede exportar los datos de un usuario específico
- Existe un mecanismo para eliminar o anonimizar datos de un usuario
- Los datos en tránsito están cifrados (TLS/mTLS)
- Los datos en reposo están cifrados
- Las claves de cifrado se gestionan en un KMS, no en el código
- Existen políticas de retención definidas por tipo de dato
- Cada request tiene un correlation ID para trazabilidad
- Los accesos a datos sensibles se registran en el log de auditoría
- Los datos personales se recopilan con consentimiento explícito
Resumen
El cumplimiento normativo y la auditoría son responsabilidades arquitectónicas, no solo legales. Los logs de auditoría inmutables proporcionan la base para demostrar cumplimiento. El GDPR impone requisitos concretos sobre cómo se almacenan, exportan y eliminan datos personales — y estos requisitos afectan directamente el diseño de cada microservicio. El cifrado protege los datos en tránsito y en reposo, y la gestión de claves es tan crítica como el cifrado mismo. La trazabilidad mediante correlation IDs permite reconstruir cualquier acción a través de múltiples servicios. Diseñar para cumplimiento desde el inicio es mucho más económico que adaptarse después.