
pg_anon encontró los emails de mi base, pero no los RUT
Probé pg_anon, la herramienta rusa que enmascara datos personales en Postgres. Con las reglas de fábrica detectó 1 de 8 columnas con PII en una base chilena; con reglas propias, las 8. Medí recall, integridad y velocidad contra pg_dump.
Quiero darle a un desarrollador una copia de la base de producción. El problema es obvio: esa base tiene nombres, correos, teléfonos y RUT (el número de identificación nacional chileno) de gente real. Copiarla tal cual a un ambiente de pruebas es filtrar datos personales, y la nueva ley chilena que castiga eso entra en vigencia en diciembre de 2026. Lo que necesito es un pg_dump que además tape lo sensible en el camino.
Eso promete pg_anon, una herramienta abierta de TantorLabs que apareció en Habr y que, hasta donde busqué, nadie ha probado en español. La instalé, le pasé una base chilena de juguete y medí tres cosas: cuánto de la información personal encuentra sola, si la copia enmascarada sigue siendo una base coherente, y cuánto cuesta contra un pg_dump normal.
Qué es, y en qué se distingue de pg_dump
pg_anon no reemplaza a pg_dump: lo envuelve. El flujo tiene cuatro pasos. Primero init crea en la base de origen un esquema anon_funcs con las funciones que después reemplazan valores. Luego create-dict escanea la base y arma un diccionario de qué columnas son sensibles. dump exporta los datos aplicando ese diccionario, y ahí ocurre el enmascarado. Por último restore carga la copia limpia en una base vacía.
La pieza que decide todo es el escaneo. Y el escaneo funciona con reglas que uno le da, en una cascada de dos filtros: primero lee el nombre de cada columna contra unas expresiones regulares; a las que sobran les abre los datos y prueba otras expresiones sobre el valor. Lo que ningún filtro atrapa, pasa de largo. Ahí está el detalle que las reseñas que leí pasan por alto.
create_dict.pynombreapellidoemailtelefonorutdireccionfecha_nactarjeta_ult4field.rulesdata_regexemail, por su nombre y su @La instalación, con sus tropiezos
Levanté un PostgreSQL 17 en Docker y una base con dos tablas: clientes (500 filas, con nombre, apellido, email, teléfono, RUT, dirección, comuna, fecha de nacimiento y notas) y pedidos (2000 filas, con clave foránea a clientes y los últimos cuatro dígitos de la tarjeta). Ocho de esas columnas son datos personales. Datos falsos pero con la forma real de los datos chilenos: RUT calculados con su módulo 11, celulares +569, correos armados con nombre y apellido.
Instalar pg_anon adentro del contenedor pidió pip install --break-system-packages, porque Debian bloquea pip global desde bookworm, y nada más. Versión 1.11.0. Necesita pg_dump y pg_restore de la misma versión mayor que el servidor, cosa que el contenedor ya trae.
El hallazgo: detecta lo que sabe nombrar
Corrí el escaneo dos veces sobre la misma base. Primero con el meta-dict de fábrica (el archivo de reglas que guía el escaneo), con sus patrones en inglés. Después con un meta-dict propio: los mismos nombres de columna pero en español, más una expresión regular para el RUT.
nombretext✗✓apellidotext✗✓emailtext✓✓telefonotext✗✓ruttext✗✓direcciontext✗✓fecha_nacdate✗✓tarjeta_ult4char(4)✗✓Con las reglas de fábrica, pg_anon marcó una sola de las ocho columnas con datos personales: email. La pescó porque email se escribe igual en inglés y calza con una regla de nombre de fábrica; su contenido, con el arroba, la confirma por partida doble. Las otras siete (nombre, apellido, teléfono, dirección, fecha de nacimiento, los cuatro dígitos de la tarjeta y el RUT) pasaron de largo. El RUT es el caso más claro: ninguna regla de fábrica reconoce un identificador chileno, y su forma (siete u ocho dígitos, un guion y un dígito verificador) no se parece a nada que el diccionario por defecto busque.
Con el meta-dict adaptado, el recall saltó a ocho de ocho, sin un solo falso positivo: dejó intactas la comuna, las notas y las columnas que no son datos personales. La herramienta detecta bien; el trabajo es enseñarle el idioma y los identificadores del país.
La copia sí es una base coherente
Con el diccionario completo, el dump y el restore reconstruyeron la base en una copia vacía. Verifiqué lo que importa de un enmascarado: que lo sensible esté tapado y que lo demás siga sirviendo.
| Comprobación | Resultado |
|---|---|
| Columnas con PII enmascaradas | 8 de 8 |
| Filas preservadas | 500 clientes, 2000 pedidos (idéntico) |
| Pedidos huérfanos tras el restore | 0 |
| Emails únicos tras el hash | 499 de 500 |
El cliente 1 pasó de Fernanda / fernanda.diaz4@outlook.com / 7917183-2 a tres hashes SHA-256. La integridad referencial quedó perfecta: cero pedidos apuntando a un cliente inexistente, porque las claves foráneas van por id, que no se toca. Y el hash conserva la unicidad: el origen tenía 499 correos distintos entre las 500 filas, y tras el hash siguen siendo 499, así que agrupar por correo cuenta lo mismo.
Lo que cuesta
Sobre 2500 filas, el enmascarado se paga en tiempo y en tamaño:
| Operación | pg_anon | pg_dump normal |
|---|---|---|
| Exportar (dump) | 0,33 s | 0,064 s |
| Tamaño del volcado | 168 KB | 72 KB |
Cinco veces más lento y más del doble de pesado. Es esperable: por cada valor sensible ejecuta una función SQL, y un hash de 64 caracteres pesa más que el correo o el RUT que reemplaza. En una base de 2500 filas no se nota; en una de millones habría que medirlo de nuevo antes de prometer nada.
Cuándo lo usaría, y cuándo no
Sí, cuando necesito una copia de producción para desarrollo o pruebas y el esquema es estable: el trabajo de escribir el diccionario se hace una vez y queda. La integridad referencial que preserva es el punto fuerte, porque es justo lo que se rompe cuando uno intenta anonimizar a mano con UPDATE.
No, si espero que detecte los datos personales sola en una base en español. No lo hace: hay que escribirle las reglas, columna por columna, y verificar el recall con una base conocida antes de confiar en la copia. Y una advertencia que la propia documentación hace y conviene repetir: esto es seudonimización, no anonimización en el sentido de la GDPR. El hash lo deja claro: sin sal, un RUT tiene solo unos 25 millones de valores posibles, así que quien tenga el hash lo revierte enumerando en minutos, y lo mismo vale para un teléfono o una fecha. Reduce la exposición; no la elimina.
pg_anon es una buena herramienta a la que hay que hablarle en su idioma. Para una base chilena, ese idioma incluye una regla para el RUT que nadie va a escribir por ti. Así que la dejé escrita: el meta-dict en español, con la regla del RUT, está en un repositorio público para que no tengas que empezar de cero.
Fuentes
- pg_anon, de TantorLabs (repositorio), versión 1.11.0, probada contra PostgreSQL 17.
- Documentación del escaneo (create-dict) y del dump.
- pg-anon-rules-es: el meta-dict en español con la regla del RUT, listo para usar.
Comentarios
Todavía no hay comentarios. El primero es tuyo.