Retención de datos y bloqueos legales
Las políticas de retención chocan: derecho de supresión del GDPR, pistas de auditoría SOC2 y congelaciones de litigios por bloqueo legal. Postgres implementa la política a través de particionamiento, borrado lógico y tablas de auditoría inmutables con propiedad clara.
Receta
Tarjeta de receta de referencia rápida, lista para copiar y pegar.
-- Metadatos de retención en eventos particionados
CREATE TABLE events (
id bigint GENERATED ALWAYS AS IDENTITY,
tenant_id uuid NOT NULL,
occurred_at timestamptz NOT NULL,
payload jsonb NOT NULL,
PRIMARY KEY (id, occurred_at)
) PARTITION BY RANGE (occurred_at);
-- Indicador de bloqueo legal (tabla separada evita reescribir el historial)
CREATE TABLE legal_holds (
subject_type text NOT NULL,
subject_id uuid NOT NULL,
hold_until date,
PRIMARY KEY (subject_type, subject_id)
);Cuándo usar esto: Solicitudes de supresión del GDPR, retención de auditoría financiera, bloqueo legal o crecimiento del disco de tablas de registro.
Ejemplo de trabajo
El cliente solicita la eliminación según el GDPR. Finanzas requiere retención de facturas durante 7 años.
-- Pseudonimizar PII en la fila de factura compartida (conservar hechos financieros)
UPDATE customers
SET email = 'deleted-' || id::text || '@invalid.local',
name = 'REDACTED',
deleted_at = now()
WHERE id = $1;
-- Bloquear eliminación si hay un bloqueo legal activo
SELECT 1 FROM legal_holds
WHERE subject_type = 'customer' AND subject_id = $1
AND (hold_until IS NULL OR hold_until >= current_date);-- Eliminar particiones de eventos antiguas que superan la retención (sin filas de bloqueo en la partición)
ALTER TABLE events DETACH PARTITION events_2023_q1;
DROP TABLE events_2023_q1;Lo que esto demuestra:
- La pseudonimización satisface algunas solicitudes de supresión mientras se conservan las facturas.
- Se verifica el bloqueo legal antes de la DML destructiva.
- El desadjunto/eliminación de particiones es el mecanismo de retención escalable.
- La política vive en la documentación del producto y legal, y se aplica en trabajos de SQL.
Análisis Profundo
Matriz de Políticas
| Clase de datos | Retención típica | Supresión |
|---|---|---|
| Eventos de marketing | 13-24 meses | Borrado físico |
| Facturas | 7 años fiscales | Solo pseudonimizar PII |
| Acciones administrativas de auditoría | 3-7 años | Inmutable de solo escritura |
| Registros de aplicación en la base de datos | 30-90 días | Eliminación de partición |
Implementación de Supresión GDPR
-- Patrón de borrado lógico
ALTER TABLE customers ADD COLUMN deleted_at timestamptz;
CREATE INDEX customers_active_idx ON customers (id) WHERE deleted_at IS NULL;
-- RLS oculta las filas eliminadas del rol de la aplicación
CREATE POLICY customers_active ON customers
FOR SELECT TO app_role
USING (deleted_at IS NULL);El borrado físico en cascada solo ocurre cuando legal confirma que no hay bloqueo y no hay retención legal.
Inmutabilidad de Auditoría
REVOKE UPDATE, DELETE ON audit_log FROM PUBLIC;
GRANT INSERT ON audit_log TO app_audit_role;
-- Opcional: pgaudit o trigger para aplicar la inmutabilidadTrabajo de Retención
# Cron mensual: eliminar particiones más antiguas que la política
psql -c "SELECT drop_expired_event_partitions(24);" # mesesPeligros
- DELETE sin revisión legal - Riesgo de espurio durante un litigio. Solución: Tabla de bloqueo y ticket de flujo de trabajo legal.
- Borrado lógico sin RLS - Las aplicaciones aún filtran filas "eliminadas". Solución: RLS o vistas con
deleted_at IS NULL. - Supresión en copias de seguridad - Las copias de seguridad retienen datos hasta su caducidad. Solución: Documentar la retención de copias de seguridad; política de cifrado y destrucción.
- Sorpresa de CASCADE - La eliminación GDPR elimina facturas no intencionadamente. Solución: FK
ON DELETE RESTRICTen elementos hijos regulados. - DELETE de tabla completa para retención - Bloqueos e hinchazón. Solución: Eliminación de partición o eliminación por lotes con rangos de claves.
Alternativas
| Alternativa | Usar cuándo | No usar cuándo |
|---|---|---|
| Archivar a almacenamiento en frío | Retención a largo plazo barata | Necesidad de consulta SQL sobre el archivo |
| Clúster de auditoría separado | Cumplimiento intensivo | Carga operativa para equipos pequeños |
| Transmisión de eventos a SIEM | Los registros salen de Postgres | La base de datos es el sistema de registro |
| Función de anonimización | Supresión repetible | El riesgo de reidentificación persiste |
Preguntas Frecuentes
¿Requiere el GDPR un borrado físico?
A menudo, la pseudonimización es suficiente cuando se aplica la retención legal; decide el departamento legal por solicitud.
¿Cómo implementar un bloqueo legal?
Indicador en legal_holds; los trabajos omiten la eliminación/eliminación de particiones para los sujetos marcados.
¿Pueden las particiones acelerar la supresión?
Sí, para datos limitados por tiempo; los datos limitados por inquilino pueden requerir purga a nivel de fila o partición por inquilino.
¿Qué pasa con las réplicas?
Las eliminaciones se replican; asegúrese de que el comportamiento en cascada sea idéntico en los suscriptores.
¿Retención vs vacuum?
La retención reduce el recuento de filas; vacuum recupera espacio después de la eliminación o el desadjunto.
¿Quién es el propietario de la política de retención?
Legal y producto son los propietarios de la política; ingeniería implementa la automatización y audita.
¿PCI en la misma base de datos?
Aislar el esquema de datos del titular de la tarjeta; retención y registro de acceso más estrictos.
¿Cómo probar la eliminación?
Entrada de registro de auditoría con ID de solicitud, tablas afectadas, recuentos de filas, marca de tiempo.
¿Derecho de acceso?
El trabajo de exportación une la clave del cliente; separado del manual de eliminación.
¿Qué debo leer a continuación?
Relacionado
- Fundamentos de las partes interesadas - marco ejecutivo
- Seguridad a Nivel de Fila - aislamiento de inquilinos
- pgaudit y Registro de Cumplimiento - pista de auditoría
- Fundamentos del Particionamiento - retención de tiempo
Versiones de la pila: Esta página fue escrita para PostgreSQL 18.4 (estable 18, mantenimiento 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x y PostGIS 3.5+.