Anonymizer 数据脱敏

Anonymizer 是一个 YMatrix 扩展功能 ,用于屏蔽或替换 YMatrix 数据库中的个人身份信息(personally identifiable information,PII)或商业敏感数据。该能力采用声明式的匿名化方法,使用者可通过 YMatrix 数据定义语言(DDL)来声明匿名规则,并在表定义中指定匿名化策略。

注意! 当前功能仅 YMatrix 企业版支持,如需使用点击立即咨询进行演示预约。

前置条件

在使用 Anonymizer 功能时,需确保目标数据库已经引入 anon 扩展。以下示例统一使用 demo 数据库,请先连接到 demo 后执行扩展创建命令。设置 session_preload_libraries 后,需要重新建立数据库连接,预加载的扩展才会用于新会话。

-- 在 demo 数据库中引入 anon 扩展
CREATE EXTENSION anon;
ALTER DATABASE demo SET session_preload_libraries = 'anon';

如果 demo 数据库已经配置了其他 session_preload_libraries,请将 anon 追加到现有配置中,避免覆盖原有预加载库。

一、使用示例

1.静态脱敏

静态脱敏是指直接修改表中敏感字段的值,将其替换为脱敏结果;后续查询读取的是修改后的数据。它适用于需要生成脱敏副本或将脱敏结果持久化的场景。执行前应确认原始数据已按需要备份。

1.1 使用示例

  1. 建表
demo=# CREATE TABLE customer (
  id serial PRIMARY KEY,
  firstname text,
  lastname text,
  phone text,
  birth date,
  postcode text
);
CREATE TABLE
  1. 写入数据
demo=# INSERT INTO customer VALUES
       (100, 'jane', 'conor', '18888888888', '1965-10-10', '1001'),
       (101, 'marco', 'skywalker', NULL, '1951-10-09', '1004'),
       (103, 'eralle', 'conor', '17777777777', '1965-07-10', '1003'),
       (108, 'rika', 'Wang', '19999999999', '1981-10-09', '1004');
INSERT 0 4
  1. 查看静态脱敏前的数据
demo=# select * FROM customer;
 id  | firstname | lastname  |    phone    |   birth    | postcode
-----+-----------+-----------+-------------+------------+----------
 103 | eralle    | conor     | 17777777777 | 1965-07-10 | 1003
 101 | marco     | skywalker |             | 1951-10-09 | 1004
 100 | jane      | conor     | 18888888888 | 1965-10-10 | 1001
 108 | rika      | Wang      | 19999999999 | 1981-10-09 | 1004
(4 rows)
  1. 定义脱敏规则
demo=# SECURITY LABEL FOR anon ON COLUMN customer.lastname
       IS 'MASKED WITH FUNCTION anon.dummy_last_name()';
SECURITY LABEL
demo=# SECURITY LABEL FOR anon ON COLUMN customer.phone
       IS 'MASKED WITH FUNCTION anon.partial(phone,2,$$******$$,2)';
  1. 让脱敏规则永久生效
  • 仅对指定字段执行脱敏
demo=# SELECT anon.anonymize_column('customer','phone');
 anonymize_column
------------------
 t
(1 row)

demo=# select * from customer;
 id  | firstname | lastname  |   phone    |   birth    | postcode
-----+-----------+-----------+------------+------------+----------
 103 | eralle    | conor     | 17******77 | 1965-07-10 | 1003
 101 | marco     | skywalker |            | 1951-10-09 | 1004
 100 | jane      | conor     | 18******88 | 1965-10-10 | 1001    +
     |           |           |            |            |
 108 | rika      | Wang      | 19******99 | 1981-10-09 | 1004
(4 rows)
  • 根据设定的脱敏规则对整个表进行脱敏
demo=# SELECT anon.anonymize_table('customer');
 anonymize_table
-----------------
 t
(1 row)

demo=# select * from customer;
 id  | firstname | lastname  |   phone    |   birth    | postcode
-----+-----------+-----------+------------+------------+----------
 103 | eralle    | Kertzmann | 17******77 | 1965-07-10 | 1003
 101 | marco     | McKenzie  |            | 1951-10-09 | 1004
 100 | jane      | Ward      | 18******88 | 1965-10-10 | 1001    +
     |           |           |            |            |
 108 | rika      | Schulist  | 19******99 | 1981-10-09 | 1004
(4 rows)

2.透明动态脱敏

透明动态脱敏不会修改表中保存的原始数据,而是在被标记为脱敏角色的用户查询时,按列规则处理查询结果。未被标记为脱敏的角色仍可查看原始值。因此,静态脱敏会改变表中数据,透明动态脱敏则根据访问角色改变查询结果的呈现方式。

本例通过数据库级参数 anon.transparent_dynamic_masking 启用透明动态脱敏,通过 SECURITY LABEL FOR anon 声明列的脱敏表达式并标记需要脱敏的角色。数据库级设置对新建会话生效;完成扩展预加载和参数设置后,请重新连接数据库再测试。本节仅介绍透明动态脱敏,不介绍 anon.start_dynamic_masking() 的旧版启停流程。

2.1 数据访问权限说明

  • CFO 可查询全部用户记录并查看原始敏感信息;
  • VIP 客户经理(vip_mgr)可查询全部记录,但 super vip 用户的 pii 字段会被掩码;
  • 普通员工(bank_emp)可查询全部记录,但所有用户的 pii 字段都会被掩码。

2.2 使用示例

  1. 创建表
demo=# CREATE TABLE customers(
  id     int PRIMARY KEY,
  status text,          -- regular / vip / super vip
  pii    text           -- 敏 感 字 段
) using mars3;

demo=# INSERT INTO customers VALUES (1,'regular','Wang Wei'), (2,'vip','Liu Han'), (3,'super vip','Ma teng');
  1. 启用透明动态脱敏
demo=# ALTER DATABASE demo SET anon.transparent_dynamic_masking = on;

该命令为 demo 数据库设置参数,不会影响其他数据库。= on 表示启用;设置后需要重新建立连接,使新的会话加载数据库级配置。

  1. 检查数据库中是否存在特定的用户角色(cfo、vip_mgr 和 bank_emp),如果不存在,则创建这些角色,并赋予它们登录权限。
demo=# DO $$
demo$# BEGIN
demo$#   IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='cfo') THEN CREATE ROLE cfo LOGIN; END IF;
demo$#   IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='vip_mgr') THEN CREATE ROLE vip_mgr LOGIN; END IF;
demo$#   IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='bank_emp') THEN CREATE ROLE bank_emp LOGIN; END IF;
demo$# END$$;
DO
  1. 授权用户查询权限
demo=# GRANT SELECT ON customers TO cfo, vip_mgr, bank_emp;
  1. 声明屏蔽规则
demo=# SECURITY LABEL FOR anon ON COLUMN customers.pii
IS 'MASKED WITH FUNCTION anon.ternary(
        (CURRENT_ROLE = ''bank_emp'')
        OR (CURRENT_ROLE = ''vip_mgr'' AND status = ''super vip''),
        ''****''::text,
        pii
    )';
demo=# SECURITY LABEL FOR anon ON ROLE vip_mgr  IS 'MASKED';
demo=# SECURITY LABEL FOR anon ON ROLE bank_emp IS 'MASKED';

这组规则分两部分:列上的 SECURITY LABEL 定义何时替换 pii 值;角色上的 MASKED 标签指定哪些角色应用脱敏规则。表达式中,当前角色为 bank_emp 时条件恒为真,返回 ****;当前角色为 vip_mgr 且客户状态为 super vip 时也返回 ****;其他情况返回原始的 pii 值。cfo 没有标记为 MASKED,因此看到原始值。

GRANT SELECT 只授予查询表的权限,不会自动授予查看原始敏感值的权限;是否显示原值由脱敏角色标签和列规则共同决定。被标记的角色仍需具备查询该表的权限。

  1. 使用不同角色用户进行查询。

以下 \c 命令会以对应的 LOGIN 角色建立新连接;这些角色需能按目标集群现有的认证配置连接数据库。

demo=# \c demo bank_emp
You are now connected to database "demo" as user "bank_emp".
demo=> select * from customers ;
 id |  status   | pii
----+-----------+------
  1 | regular   | ****
  2 | vip       | ****
  3 | super vip | ****
(3 rows)

demo=> \c demo cfo
You are now connected to database "demo" as user "cfo".
demo=> select * from customers ;
 id |  status   |    pii
----+-----------+------------
  1 | regular   | Wang Wei
  2 | vip       | Liu Han
  3 | super vip | Ma teng
(3 rows)

demo=> \c demo vip_mgr
You are now connected to database "demo" as user "vip_mgr".
demo=> select * from customers ;
 id |  status   |   pii
----+-----------+----------
  1 | regular   | Wang Wei
  2 | vip       | Liu Han
  3 | super vip | ****
(3 rows)