使用动态数据掩码¶
本主题说明如何在 Snowflake 中配置和使用动态数据掩码。
要了解有关使用带有标签的掩码策略的更多信息,请参阅 基于标签的掩码策略。
使用动态数据掩码¶
下面列出了在 Snowflake 中配置和使用动态数据掩码的简要步骤:
向安全或隐私官的自定义角色授予掩码策略管理权限。
将该自定义角色授予相应的用户。
安全或隐私官创建和定义掩码策略,并将其应用于包含敏感数据的列。
在 Snowflake 中执行查询。请注意以下事项:
Snowflake 会动态重写查询,并将掩码策略 SQL 表达式应用于列。
对于在掩码策略中指定的列,查询中出现该列的每个位置(例如投影、join 谓词、where 子句谓词、order by 和 group by)都会发生列重写。
用户根据掩码策略中定义的执行上下文条件查看掩码数据。有关动态数据掩码策略中的执行上下文的更多信息,请参阅 高级列级安全主题。
第 1 步:向自定义角色授予掩码策略权限¶
安全或隐私官 应担任掩码策略管理员(即自定义角色:MASKING_ADMIN
),并应具有掩码策略的定义、管理和应用到列的权限。
Snowflake 为列级安全掩码策略提供以下可授予安全或隐私官的权限:
权限 |
描述 |
---|---|
CREATE MASKING POLICY |
此架构级权限控制谁可以创建掩码策略。 |
APPLY MASKING POLICY |
此账户级权限控制谁可以在列上设置和取消设置掩码策略,并且默认授予 ACCOUNTADMIN 角色。. 此权限仅允许将掩码策略应用于列,并且 不 提供 访问控制权限 中描述的任何其他表权限。 |
APPLY ON MASKING POLICY |
可选。策略所有者可以使用此策略级权限,将在列上设置和取消设置给定掩码策略的操作分散给对象所有者(即具有对象的 OWNERSHIP 权限的角色)。. Snowflake 支持 自主访问控制,其中对象所有者也视为数据管理员。. 如果策略管理员信赖对象所有者是受保护列的数据管理员,则策略管理员可以使用此权限来分散策略设置和取消设置操作的应用。 |
以下示例创建 MASKING_ADMIN
角色,并向该角色授予掩码策略权限。
创建掩码策略管理员自定义角色:
use role useradmin; CREATE ROLE masking_admin;
向 masking_admin
角色授予权限:
use role securityadmin; GRANT CREATE MASKING POLICY on SCHEMA <db_name.schema_name> to ROLE masking_admin; GRANT APPLY MASKING POLICY on ACCOUNT to ROLE masking_admin;
允许 table_owner
角色设置或取消设置 ssn_mask
掩码策略(可选):
GRANT APPLY ON MASKING POLICY ssn_mask to ROLE table_owner;
其中:
db_name.schema_name
指定应为其授予权限的架构的标识符。
有关更多信息,请参阅:
第 2 步:向用户授予自定义角色¶
将 MASKING_ADMIN
自定义角色授予充当安全或隐私官的用户。
GRANT ROLE masking_admin TO USER jsmith;
第 3 步:创建掩码策略¶
使用 MASKING_ADMIN 角色创建掩码策略并将其应用于列。
在此代表性示例中,具有 ANALYST 角色的用户将看到未掩码的值。没有 ANALYST 角色的用户将看到完整的掩码。
CREATE OR REPLACE MASKING POLICY email_mask AS (val string) RETURNS string ->
CASE
WHEN CURRENT_ROLE() IN ('ANALYST') THEN val
ELSE '*********'
END;
小技巧
如果您想要更新现有的掩码策略,并需要查看该策略的当前定义,请调用 GET_DDL 函数或运行 DESCRIBE MASKING POLICY 命令。
第 4 步:将掩码策略应用于表或视图列¶
这些示例假定在创建表时未将掩码策略应用于表列,在创建视图时也未应用于视图列。在使用 CREATE TABLE 语句创建表,或者在使用 CREATE VIEW 语句创建视图时,可以根据需要将掩码策略应用于表列或视图列。
执行以下语句,以将策略应用于表列或视图列。
-- apply masking policy to a table column
ALTER TABLE IF EXISTS user_info MODIFY COLUMN email SET MASKING POLICY email_mask;
-- apply the masking policy to a view column
ALTER VIEW user_info_v MODIFY COLUMN email SET MASKING POLICY email_mask;
第 5 步:查询 Snowflake 中的数据¶
在 Snowflake 中执行两个不同的查询(一个使用 ANALYST 角色,另一个使用其他角色),以验证没有 ANALYST 角色的用户是否看到完整的掩码。
-- using the ANALYST role
USE ROLE analyst;
SELECT email FROM user_info; -- should see plain text value
-- using the PUBLIC role
USE ROLE PUBLIC;
SELECT email FROM user_info; -- should see full data mask
具有可记忆函数的掩码策略¶
此示例使用 可记忆函数 来缓存映射表上的查询结果,该结果用于确定某个角色是否有权查看 PII 数据。数据工程师使用掩码策略来保护表中的列。
下面的过程将引用这些对象:
包含 PII 数据的表
employee_data
:+----------+-------------+---------------+ | USERNAME | ID | PHONE_NUMBER | +----------+-------------+---------------+ | JSMITH | 12-3456-89 | 1555-523-8790 | | AJONES | 12-0124-32 | 1555-125-1548 | +----------+-------------+---------------+
确定特定角色是否有权查看数据的映射表
auth_role_t
:+---------------+---------------+ | ROLE | IS_AUTHORIZED | +---------------+---------------+ | DATA_ENGINEER | TRUE | | DATA_STEWARD | TRUE | | IT_ADMIN | TRUE | | PUBLIC | FALSE | +---------------+---------------+
完成以下步骤,创建一个可调用带实参的可记忆函数的掩码策略:
创建一个可记忆函数,用于查询映射表。该函数根据
is_authorized
列的值返回角色数组:CREATE FUNCTION is_role_authorized(arg1 VARCHAR) RETURNS BOOLEAN MEMOIZABLE AS $$ SELECT ARRAY_CONTAINS( arg1::VARIANT, (SELECT ARRAY_AGG(role) FROM auth_role WHERE is_authorized = TRUE) ) $$;
调用可记忆函数,缓存查询结果。在本例中,传递值
TRUE
作为实参值,因为结果数组充当允许访问受掩码策略保护的数据的角色来源:SELECT is_role_authorized(IT_ADMIN);
+---------------------------------------------+ | is_role_authorized(IT_ADMIN) | +---------------------------------------------+ | TRUE | +---------------------------------------------+
创建一个掩码策略来保护
id
列。该策略会调用可记忆函数,来确定用于查询表的角色是否获得授权来查看受保护列中的数据:CREATE OR REPLACE MASKING POLICY empl_id_mem_mask AS (val VARCHAR) RETURNS VARCHAR -> CASE WHEN is_role_authorized(CURRENT_ROLE()) THEN val ELSE NULL END;
使用 ALTER TABLE ...ALTER COLUMN 命令设置表的掩码策略:
ALTER TABLE employee_data MODIFY COLUMN id SET MASKING POLICY empl_id_mem_mask;
查询表以测试策略:
USE ROLE data_engineer; SELECT * FROM employee_data;
该查询返回未掩码数据。
但是,如果将角色切换为 PUBLIC 角色并重复本步骤中的查询,则
id
中的值将替换为NULL
。
其他掩码策略示例¶
以下是可在动态数据掩码策略正文中使用的其他代表性示例。
允许生产 账户 查看未掩码的值,并允许所有其他账户(例如开发、测试)查看掩码值。
case when current_account() in ('<prod_account_identifier>') then val else '*********' end;
为未经授权的用户返回 NULL:
case when current_role() IN ('ANALYST') then val else NULL end;
为未经授权的用户返回静态的掩码值:
CASE WHEN current_role() IN ('ANALYST') THEN val ELSE '********' END;
使用 SHA2、SHA2_HEX 为未经授权的用户返回哈希值。在掩码策略中使用哈希函数可能会导致冲突,因此,请谨慎使用此方法。有关更多信息,请参阅 高级列级安全主题。
CASE WHEN current_role() IN ('ANALYST') THEN val ELSE sha2(val) -- return hash of the column value END;
应用部分掩码或完整掩码:
CASE WHEN current_role() IN ('ANALYST') THEN val WHEN current_role() IN ('SUPPORT') THEN regexp_replace(val,'.+\@','*****@') -- leave email domain unmasked ELSE '********' END;
使用时间戳。
case WHEN current_role() in ('SUPPORT') THEN val else date_from_parts(0001, 01, 01)::timestamp_ntz -- returns 0001-01-01 00:00:00.000 end;重要
目前,Snowflake 不支持掩码策略中的不同输入和输出数据类型,例如定义掩码策略时以时间戳为目标,但返回字符串(例如
***MASKED***
);输入和输出数据类型必须匹配。解决方法是使用虚构的时间戳值转换实际时间戳值。有关更多信息,请参阅 DATE_FROM_PARTS 和 CAST、::。
使用 UDF:
CASE WHEN current_role() IN ('ANALYST') THEN val ELSE mask_udf(val) -- custom masking function END;
作用于变体数据:
CASE WHEN current_role() IN ('ANALYST') THEN val ELSE OBJECT_INSERT(val, 'USER_IPADDRESS', '****', true) END;
使用自定义授权表。请注意在 WHEN 子句中使用了 EXISTS。在掩码策略正文中包含子查询时,请务必使用 EXISTS。有关 Snowflake 支持的子查询的更多信息,请参阅 使用子查询。
CASE WHEN EXISTS (SELECT role FROM <db>.<schema>.entitlement WHERE mask_method='unmask' AND role = current_role()) THEN val ELSE '********' END;
在以前使用 ENCRYPT 或 ENCRYPT_RAW 加密的数据上使用 DECRYPT,并使用加密数据上的密码:
case when current_role() in ('ANALYST') then DECRYPT(val, $passphrase) else val -- shows encrypted value end;
对 JSON 使用 <JavaScript UDF (VARIANT):
在此示例中,JavaScript UDF 掩码了 JSON 字符串中的位置数据。在 UDF 和掩码策略中,将数据类型设置为 VARIANT 非常重要。如果表列、UDF 和掩码策略签名中的数据类型不匹配,则 Snowflake 将返回错误消息,因为它无法解析 SQL。
-- Flatten the JSON data create or replace table <table_name> (v variant) as select value::variant from @<table_name>, table(flatten(input => parse_json($1):stationLocation)); -- JavaScript UDF to mask latitude, longitude, and location data CREATE OR REPLACE FUNCTION full_location_masking(v variant) RETURNS variant LANGUAGE JAVASCRIPT AS $$ if ("latitude" in V) { V["latitude"] = "**latitudeMask**"; } if ("longitude" in V) { V["longitude"] = "**longitudeMask**"; } if ("location" in V) { V["location"] = "**locationMask**"; } return V; $$; -- Grant UDF usage to ACCOUNTADMIN grant ownership on function FULL_LOCATION_MASKING(variant) to role accountadmin; -- Create a masking policy using JavaScript UDF create or replace masking policy json_location_mask as (val variant) returns variant -> CASE WHEN current_role() IN ('ANALYST') THEN val else full_location_masking(val) -- else object_insert(val, 'latitude', '**locationMask**', true) -- limited to one value at a time END;
使用 GEOGRAPHY 数据类型:
在此示例中,对于 CURRENT_ROLE 不是
ANALYST
的用户,掩码策略使用 TO_GEOGRAPHY 函数将列中的所有 GEOGRAPHY 数据转换为固定点,即 Snowflake 在加利福尼亚州圣马特奥市的经度和纬度。create masking policy mask_geo_point as (val geography) returns geography -> case when current_role() IN ('ANALYST') then val else to_geography('POINT(-122.35 37.55)') end;在数据类型为 GEOGRAPHY 的列上设置掩码策略,并将会话的 GEOGRAPHY_OUTPUT_FORMAT 值设置为
GeoJSON
:alter table mydb.myschema.geography modify column b set masking policy mask_geo_point; alter session set geography_output_format = 'GeoJSON'; use role public; select * from mydb.myschema.geography;Snowflake 返回以下结果:
---+--------------------+ A | B | ---+--------------------+ 1 | { | | "coordinates": [ | | -122.35, | | 37.55 | | ], | | "type": "Point" | | } | 2 | { | | "coordinates": [ | | -122.35, | | 37.55 | | ], | | "type": "Point" | | } | ---+--------------------+B 列中的查询结果值取决于会话的 GEOGRAPHY_OUTPUT_FORMAT 参数值。例如,如果该参数值设置为
WKT
,Snowflake 将返回以下结果:alter session set geography_output_format = 'WKT'; select * from mydb.myschema.geography; ---+----------------------+ A | B | ---+----------------------+ 1 | POINT(-122.35 37.55) | 2 | POINT(-122.35 37.55) | ---+----------------------+
有关使用其他上下文函数和角色层次结构的示例,请参阅 高级列级安全主题。
后续主题: