台湾,台北 - 2023 年 3 月 9 日
我很高兴地宣布 pg_anonymize 的测试版发布。
pg_anonymize 是一个 PostgreSQL 扩展,它为数据匿名化提供了简单、健壮且透明的基础设施。其目标是确保任何以匿名角色连接的用户,都只能看到数据的匿名版本,而不会对使用的客户端(可以是 psql、pg_dump、您自己的应用程序,甚至是像 pg_sample 这样的其他工具)或模式和关系的数量造成任何限制。
匿名化是使用声明式方法完成的,依赖于 SECURITY LABEL:您只需要为每个需要匿名化的列声明一个表达式,该表达式将动态执行匿名化。可以使用任何产生正确类型的有效表达式,因此您可以使用纯 SQL、plpgsql 或您选择的任何其他过程语言编写它们。
此扩展与 PostgreSQL 10 及更高版本兼容。有关其使用情况的更多详细信息,请查看下面的 使用 部分或 文档。
如果您遇到任何问题或想要求新功能,请随时 打开 issue。
pg_anonymize 提供以下配置选项
pg_anonymize.enabled (bool):允许全局启用或禁用 pg_anonymize。默认值为 on。
pg_anonymize.check_labels (bool):在声明安全标签时,对定义的表达式执行健全性检查(表达式有效性、只读性、返回类型和缺少 SQL 注入)。默认值为 on。
注意:即使禁用 pg_anonymize.check_labels,pg_anonymize 仍会检查定义的表达式是否包含任何 SQL 注入。
必须先加载 pg_anonymize 才能使用它。有多种方法可以做到这一点。通常,只有少数角色需要数据匿名化,因此建议的方法是仅为这些角色加载扩展。例如,假设应使用角色 alice
ALTER ROLE alice SET session_preload_libraries = 'pg_anonymize';
注意:只有在成功运行此命令 之后 由 alice 打开的会话才会加载 pg_anonymize。
您也可以显式加载它,例如
LOAD 'pg_anonymize';
注意:LOAD 需要超级用户权限。
然后,您需要声明所需角色为需要匿名数据的角色。这是通过在目标角色上添加一个 SECURITY LABEL anonymize 来完成的。例如
-- pg_anonymize 需要在声明 SECURITY LABEL 之前加载 LOAD 'pg_anonymize'; SECURITY LABEL FOR pg_anonymize ON ROLE alice IS 'anonymize';
注意:在角色上声明 SECURITY LABEL 需要 CREATEROLE 权限。
然后,您可以使用 SECURITY LABELS 声明如何匿名化每一列,定义一个表达式来替换实际内容。
例如,假设有一个简单的客户表
``` 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; ```
让我们匿名化姓氏、生日和电话号码
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')$$;
注意:在列上声明 SECURITY LABEL 需要是基础关系的所有者。
角色 alice 现在将自动看到匿名数据。例如
``` -- 当前角色看到正常数据 =# SELECT * FROM public.customer; id | first_name | last_name | birthday | phone_number ----+------------+-----------+------------+---------------- 1 | Nice | Customer | 1970-03-04 | +886 1234 5678 (1 row)
-- 但是 alice 将看到匿名数据 =# \c - alice 您现在以用户 "alice" 的身份连接到数据库 "rjuju"。
=> 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 也将看到匿名数据 $ 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 . ```