pg_anonymize, nueva extensión para anonimizar datos de forma sencilla y transparente
Taipei, Taiwán – 9 de marzo de 2023
Me complace anunciar la versión beta de pg_anonymize.
pg_anonymize es una extensión de PostgreSQL que proporciona una infraestructura simple, robusta y transparente para la anonimización de datos. Su objetivo es asegurar que cualquier persona conectada con un rol anonimizado vea únicamente la versión anonimizada de los datos sin ninguna restricción relativa al cliente utilizado (puede ser psql, pg_dump, una aplicación propia o incluso otras herramientas como pg_sample…) o el número de esquemas y relaciones.
La anonimización se realiza mediante un enfoque declarativo, basado en SECURITY LABELs (etiquetas de seguridad) : es suficiente con declarar una expresión para cada columna que se vaya a anonimizar y que realizará la anonimización de forma dinámica. Puesto que es posible utilizar cualquier expresión válida que produzca el tipo correcto, podemos escribirlas en sql plano, plpgsql o cualquier otro lenguaje de procedimientos de nuestra elección.
Esta extensión es compatible con PostgreSQL 10 y superiores. Para más detalles sobre cómo usarla, consulte la sección de uso que aparece a continuación o la documentación.
No duden en crear una incidencia si encuentran algún problema o desean solicitar nuevas características.
Configuración
pg_anonymize ofrece las siguientes opciones de configuración:
- pg_anonymize.enabled (bool): permite activar o desactivar pg_anonymize a nivel global. El valor por defecto es on.
- pg_anonymize.check_labels (bool): realiza comprobaciones de integridad (validez de la expresión, sólo lectura, tipo devuelto y ausencia de inyección SQL) en la expresión definida al declarar etiquetas de seguridad. El valor por defecto es on.
NOTA: aunque pg_anonymize.check_labels esté desactivado, pg_anonymize seguirá comprobando que la expresión definida no contenga ninguna inyección SQL.
Uso
pg_anonymize debe ser cargado antes de su uso. Existen varias formas de hacerlo. Normalmente, sólo unos pocos roles deben requerir la anonimización de datos, por lo que la forma recomendada es cargar la extensión sólo para dichos roles. Por ejemplo, suponiendo que se deba utilizar el rol “alice”:
ALTER ROLE alice SET session_preload_libraries = 'pg_anonymize';
NOTA: sólo las sesiones abiertas por “alice” tras la correcta ejecución de este comando cargarán pg_anonymize.
También pueden cargarlo de manera explícita, por ejemplo:
LOAD 'pg_anonymize';
NOTA: LOAD requiere privilegios de superusuario.
A continuación, deberá declararse que el rol o roles deseados necesitan datos anonimizados. Para hacerlo, es necesario añadir una SECURITY LABEL anonymize en el rol o roles de destino. Por ejemplo:
-- pg_anonymize need to be loaded before declaring SECURITY LABEL LOAD 'pg_anonymize'; SECURITY LABEL FOR pg_anonymize ON ROLE alice IS 'anonymize';
NOTA: para declarar una SECURITY LABEL en un rol se requiere el privilegio CREATEROLE.
A continuación, es posible declarar cómo anonimizar cada columna con SECURITY LABELs, definiendo una expresión para sustituir el contenido real.
Por ejemplo, supongamos contar con una simple tabla de clientes:
«` CREATE TABLE public.customer(id integer, first_name text, last_name text, birthday date, phone_number text);
INSERT INTO public.customer VALUES (1, ‘Nice’, ‘Customer’, ‘1970-03-04’, ‘+886 1234 5678’);
GRANT SELECT ON TABLE public.customer TO alice; «`
Anonimicemos el apellido, la fecha de nacimiento y el número de teléfono:
SECURITY LABEL FOR pg_anonymize ON COLUMN public.customer.last_name IS $$substr(last_name, 1, 1) || '*****'$$; SECURITY LABEL FOR pg_anonymize ON COLUMN public.customer.birthday IS $$date_trunc('year', birthday)::date$$; SECURITY LABEL FOR pg_anonymize ON COLUMN public.customer.phone_number IS $$regexp_replace(phone_number, '\d', 'X', 'g')$$;
NOTA: para declarar una SECURITY LABEL en una columna es necesario ser propietario de la relación subyacente.
El rol “alice” ahora verá automáticamente los datos anonimizados. Por ejemplo:
«` — current role sees the normal data =# SELECT * FROM public.customer; id | first_name | last_name | birthday | phone_number —-+————+———–+————+—————- 1 | Nice | Customer | 1970-03-04 | +886 1234 5678 (1 row)
— but alice will see anonymized data =# \c – alice You are now connected to database «rjuju» as user «alice».
=> SELECT * FROM public.customer; id | first_name | last_name | birthday | phone_number —-+————+———–+————+—————- 1 | Nice | C* | 1970-01-01 | +XXX XXXX XXXX (1 row)
— pg_dump will also see anonymized data $ pg_dump -U alice -t public.customer -a rjuju | grep «COPY» -A2 COPY public.customer (id, first_name, last_name, birthday, phone_number) FROM stdin; 1 Nice C* 1970-01-01 +XXX XXXX XXXX . «`