CREATE MASKING POLICY

在当前/指定的架构中创建新的掩码策略或替换现有掩码策略。

创建掩码策略后,使用 ALTER TABLE ...ALTER COLUMN 命令将掩码策略应用于表中的列,或使用 ALTER VIEW 命令将其应用于视图。

另请参阅:

选择集中式、混合式或分散式方法高级列级安全主题

掩码策略 DDL

语法

CREATE [ OR REPLACE ] MASKING POLICY [ IF NOT EXISTS ] <name> AS
( <arg_name_to_mask> <arg_type_to_mask> [ , <arg_1> <arg_type_1> ... ] )
RETURNS <arg_type_to_mask> -> <body>
[ COMMENT = '<string_literal>' ]
[ EXEMPT_OTHER_POLICIES = { TRUE | FALSE } ]
Copy

必填参数

name

掩码策略的标识符;对于架构必须是唯一的。

标识符值必须以字母字符开头,且不能包含空格或特殊字符,除非整个标识符字符串放在双引号内(例如 "My object")。放在双引号内的标识符也区分大小写。

有关更多详细信息,请参阅 标识符要求

AS ( arg_name_to_mask arg_type_to_mask [ , arg_1 arg_type_1 ... ] )

掩码策略的签名;指定在查询运行时要评估的输入列和数据类型。

有关更多详细信息,请参阅 SQL 数据类型参考

arg_name_to_mask arg_type_to_mask

第一列 及其数据类型 始终 指示在后续策略条件下要进行掩码或标记化处理的列数据类型值。

请注意,在条件掩码策略中,不能 将虚拟列指定为第一列实参。

[ , arg_1 arg_type_1 ... ]

指定要评估的条件列及其数据类型,以确定策略条件是否应对查询结果每行第一列中的数据进行掩码或标记化。

如果未指定这些额外的列和数据类型,Snowflake 会将策略评估为常规掩码策略。

RETURNS arg_type_to_mask

返回数据类型必须与指定为输入列的第一列的输入数据类型相匹配。

body

SQL 表达式,用于转换 arg_name_to_mask 指定的列中的数据。

表达式可以包括表示条件逻辑的 条件表达式函数、内置函数或用于转换数据的 UDFs。

如果在掩码策略的正文中使用了 UDF 或外部函数,则策略所有者必须对 UDF 或外部函数具有 USAGE 权限。如果角色用于查询已应用掩码策略的列,则无需 UDF 或外部函数的 USAGE 权限。

如果在条件掩码策略正文中使用了 UDF 或外部函数,则策略所有者必须具有 UDF 或外部函数的 OWNERSHIP 权限。用户如果查询已应用条件掩码策略的列,则不需要对 USAGE 或外部函数具有 UDF 权限。

可选参数

COMMENT = 'string_literal'

为掩码策略添加注释,或者覆盖现有注释。

EXEMPT_OTHER_POLICIES = TRUE | FALSE

根据使用情况,执行以下操作之一:

  • 指定行访问策略或条件掩码策略能否引用已受此掩码策略保护的列。

  • 指定分配给虚拟列的掩码策略是否替换虚拟列从 VALUE 列继承的掩码策略。使用外部表时,请在保护 VALUE 列的掩码策略中指定此属性。

TRUE

允许其他策略引用掩码列,或允许在虚拟列上设置的掩码策略替换虚拟列从外部表中的 VALUE 列继承的掩码策略。

FALSE

不允许其他策略引用掩码列或允许掩码策略,并且不允许虚拟列从外部表中的 VALUE 列继承的掩码策略。

请注意以下事项:

  • 在对表或视图设置掩码策略后,此属性在掩码策略中的值不能更改。若要更新此属性设置的值,请对掩码策略执行 CREATE MASKING OR REPLACE POLICY 语句。

  • 该属性设置为 true 时,它包含在对策略调用 GET_DDL 函数的输出之中。

访问控制要求

用于执行此操作的 角色 必须至少具有以下 权限

权限

对象

备注

CREATE MASKING POLICY

架构

要对架构中的任何对象执行操作,需要对父数据库和架构的 USAGE 权限。请注意,如果某个角色获授某个架构的任意权限,该角色便能够解析该架构。例如,若某角色被授予 CREATE 权限,则可以在该架构上创建对象,而无需 同时 被授予该架构的 USAGE 权限。

有关创建具有指定权限集的自定义角色的说明,请参阅 创建自定义角色

有关对 安全对象 执行 SQL 操作的相应角色和权限授予的一般信息,请参阅 访问控制概述

在掩码策略中指定 EXEMPT_OTHER_POLICIES 属性时,拥有掩码策略的角色(即对策略具有 OWNERSHIP 权限的角色)必须位于拥有行访问策略或条件掩码策略的角色的角色层次结构中。

例如,策略管理员自定义角色可以构成如下所示的 角色层次结构

masking_admin » rap_admin » SYSADMIN

masking_admin » cond_masking_admin » SYSADMIN

其中:

masking_admin

指定自定义角色,该自定义角色拥有对在行访问策略或条件掩码策略的签名中指定的列设置的掩码策略。

rap_admin

指定拥有行访问策略的自定义角色。

cond_masking_admin

指定拥有条件掩码策略的自定义角色。

有关掩码策略 DDL 和权限的其他详细信息,请参阅 管理列级安全性

使用说明

  • 如果您想要替换现有掩码策略并需要查看该策略的当前定义,请调用 GET_DDL 函数或运行 DESCRIBE MASKING POLICY 命令。

  • 对于在掩码策略正文中包含子查询的掩码策略,请在 CASE 函数的 WHEN 分支中使用 EXISTS。如需查看代表性示例,请参阅本主题的 常规掩码策略 部分中的自定义授权表示例。

  • 如果策略 body 包含映射表查找,请创建一个集中式映射表,并将映射表存储在受保护表所在的数据库中。在 body 调用 IS_DATABASE_ROLE_IN_SESSION 函数时,这一点尤其重要。有关详细信息,请参阅函数使用说明。

  • 给定的表或视图列可以在掩码策略签名或行访问策略签名中指定。换句话说,同一列不能同时在掩码策略签名和行访问策略签名中指定。

    有关更多信息,请参阅 CREATE ROW ACCESS POLICY

  • 数据共享提供商无法在 :doc:` 阅读者账户 </user-guide/data-sharing-reader-create>` 中创建掩码策略。

  • 如果在掩码策略中使用 UDF,请确保列的数据类型 UDF 与掩码策略匹配。有关更多信息,请参阅 掩码策略中的用户定义函数

  • 如果在掩码或行访问策略的正文中指定 CURRENT_DATABASECURRENT_SCHEMA 函数,该函数会返回包含受保护表的数据库或架构,而不是用于会话的数据库或架构。

  • 关于元数据:

    注意

    客户应确保在使用 Snowflake 服务时,不会将个人数据(用户对象除外)、敏感数据、出口管制数据或其他受监管数据作为元数据输入。有关更多信息,请参阅 Snowflake 中的元数据字段

  • The OR REPLACE and IF NOT EXISTS clauses are mutually exclusive. They can't both be used in the same statement.

  • CREATE OR REPLACE <object> 语句是原子的。也就是说,当对象被替换时,旧对象将被删除,新对象将在单个事务中创建。

示例:常规掩码策略

您可以使用 条件表达式函数上下文函数 和 UDFs 来编写 SQL 表达式。

以下是策略正文的代表性示例,演示了如何使用不同的 SQL 表达式、函数和数据类型创建掩码策略条件。

这些示例主要使用 CURRENT_ROLE 上下文函数。如果策略条件需要角色激活和角色层次结构,请使用 IS_ROLE_IN_SESSION

完整的掩码:

analyst 自定义角色可以看到纯文本值。没有 analyst 自定义角色的用户将看到完整的掩码。

CREATE OR REPLACE MASKING POLICY email_mask AS (val string) returns string ->
  CASE
    WHEN current_role() IN ('ANALYST') THEN VAL
    ELSE '*********'
  END;
Copy

允许生产 账户 查看未掩码的值,并允许所有其他账户(例如开发、测试)查看掩码值。

case
  when current_account() in ('<prod_account_identifier>') then val
  else '*********'
end;
Copy

为未经授权的用户返回 NULL:

case
  when current_role() IN ('ANALYST') then val
  else NULL
end;
Copy

为未经授权的用户返回静态的掩码值:

CASE
  WHEN current_role() IN ('ANALYST') THEN val
  ELSE '********'
END;
Copy

使用 SHA2、SHA2_HEX 为未经授权的用户返回哈希值。在掩码策略中使用哈希函数可能会导致冲突,因此,请谨慎使用此方法。有关更多信息,请参阅 高级列级安全主题

CASE
  WHEN current_role() IN ('ANALYST') THEN val
  ELSE sha2(val) -- return hash of the column value
END;
Copy

应用部分掩码或完整掩码:

CASE
  WHEN current_role() IN ('ANALYST') THEN val
  WHEN current_role() IN ('SUPPORT') THEN regexp_replace(val,'.+\@','*****@') -- leave email domain unmasked
  ELSE '********'
END;
Copy

使用时间戳。

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;
Copy

重要

目前,Snowflake 不支持掩码策略中的不同输入和输出数据类型,例如定义掩码策略时以时间戳为目标,但返回字符串(例如 ***MASKED***);输入和输出数据类型必须匹配。

解决方法是使用虚构的时间戳值转换实际时间戳值。有关更多信息,请参阅 DATE_FROM_PARTSCAST、::

使用 UDF:

CASE
  WHEN current_role() IN ('ANALYST') THEN val
  ELSE mask_udf(val) -- custom masking function
END;
Copy

作用于变体数据:

CASE
   WHEN current_role() IN ('ANALYST') THEN val
   ELSE OBJECT_INSERT(val, 'USER_IPADDRESS', '****', true)
END;
Copy

使用自定义授权表。请注意在 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;
Copy

在以前使用 ENCRYPTENCRYPT_RAW 加密的数据上使用 DECRYPT,并使用加密数据上的密码:

case
  when current_role() in ('ANALYST') then DECRYPT(val, $passphrase)
  else val -- shows encrypted value
end;
Copy

对 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;
Copy

使用 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;
Copy

在数据类型为 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;
Copy

Snowflake 返回以下结果:

---+--------------------+
 A |         B          |
---+--------------------+
 1 | {                  |
   |   "coordinates": [ |
   |     -122.35,       |
   |     37.55          |
   |   ],               |
   |   "type": "Point"  |
   | }                  |
 2 | {                  |
   |   "coordinates": [ |
   |     -122.35,       |
   |     37.55          |
   |   ],               |
   |   "type": "Point"  |
   | }                  |
---+--------------------+
Copy

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) |
---+----------------------+
Copy

有关使用其他上下文函数和角色层次结构的示例,请参阅 高级列级安全主题

示例:条件掩码策略

以下示例返回 CURRENT_ROLEadmin 自定义角色或可见性列中的值为 Public 的用户的未掩码数据。所有其他条件都会得出固定的掩码值。

-- Conditional Masking

create masking policy email_visibility as
(email varchar, visibility string) returns varchar ->
  case
    when current_role() = 'ADMIN' then email
    when visibility = 'Public' then email
    else '***MASKED***'
  end;
Copy

以下示例返回 CURRENT_ROLEadmin 自定义角色,且不同列中的值为 Public 的用户的去标记化数据。所有其他条件都会生成标记化值。

-- Conditional Tokenization

create masking policy de_email_visibility as
 (email varchar, visibility string) returns varchar ->
   case
     when current_role() = 'ADMIN' and visibility = 'Public' then de_email(email)
     else email -- sees tokenized data
   end;
Copy

示例:在行访问策略或条件掩码策略中允许掩码列

替换允许查看电子邮件地址、仅查看电子邮件地址域或查看固定掩码值的掩码策略:

create or replace masking policy governance.policies.email_mask
as (val string) returns string ->
case
  when current_role() in ('ANALYST') then val
  when current_role() in ('SUPPORT') then regexp_replace(val,'.+\@','*****@')
  else '********'
end
comment = 'specify in row access policy'
exempt_other_policies = true
;
Copy

现在可对列设置此策略,行访问策略或条件掩码策略可以按需引用受此掩码策略保护的列。

语言: 中文