行级访问控制

为了便于控制用户或角色对MaxCompute表中特定数据的访问,MaxCompute提供了行级访问控制功能,通过在原表上定义用户与数据(被允许访问的数据)的匹配规则,控制特定用户或角色仅可见其有权限访问的数据,从而提升数据安全性和合规性。

背景信息

MaxCompute表中包含大量数据,在数据共享场景下,数据管理者通常希望特定的用户只能访问其被授权访问的数据行。以前为了控制用户对特定数据行的访问,通常需要为每个用户创建一张视图来过滤数据,或者通过ETL任务过滤数据,并将其转存到另一张表中再授权。

行级访问控制功能简化了管理者授权用户访问特定表数据的操作流程,无需搬移、复制数据,或创建、维护视图,即可实现该功能。

行级访问控制功能适用于以下场景:

  • SQL查询。

  • 通过Tunnel下载表数据。

  • 通过外部引擎(如Spark、Flink)读取表数据。

说明

不支持MaxCompute行级访问控制的引擎(如Hologres),会被禁止访问受保护的数据,但您仍然可以通过视图或转存表方式实现数据过滤共享。

使用限制

  • 行级访问控制的限制如下:

    • 仅支持管理员(Admin角色、表Owner)配置行级访问规则(Row Access Policy)。

    • 暂不支持对Transactional表、视图和物化视图等对象配置行级访问规则;不支持在添加了行级访问规则的表上创建物化视图,或在物化视图的基础表上增加行级访问规则;但您可以基于配置了行级访问规则的表创建视图,对视图的查询结果由基础表上配置的行级访问规则与视图Owner定义的视图规则共同决定。

    • 不支持在配置了行级访问规则的表上进行Schema Evolution操作。

    • 不支持将配置了行级访问规则的表添加为UDF的表资源,或者对已经添加为UDF的表资源再配置行级访问规则。目前添加或配置阶段不报错,只在运行阶段报错。

    • 不支持在配置了行级访问规则的表上增加字段脱敏规则。

    • 行级访问控制当前暂不支持分区裁剪。假如ds是分区字段,即使在filter_expr中指定了类似于ds='20220101'的过滤条件,也可能需要启动全表扫描来过滤数据。filter_expr详情请参见filter_expr说明

  • 通过Package跨项目共享增加了行级权限的表的限制如下:

    • 支持对未加入项目的用户(当前租户的主账号或RAM子账号)配置行级权限。

    • 跨项目使用增加了行级权限的表时,只有用户或Default规则可能命中并产生过滤效果。

    • 不允许对Package中增加了行级权限的表再次增加行级权限。

注意事项

  • filter_expr中使用的运算符或函数可能会受各种Flag参数的影响。系统会检查Query运行时和创建policy时的参数设置是否一致,若不一致则会出现如下报错信息。

    FAILED: ODPS-0130071:[0,0] Semantic analysis exception - physical plan generation failed: java.lang.IllegalArgumentException: Row access policy flag mismatch for: xxx
  • 执行行级访问控制相关命令(如CREATE、DROP、DESC或LIST)前,您需要在Session级别设置如下GUC参数,启用行级访问控制功能。

    说明

    系统后续会默认在Session级别启用,请关注文档公告或此处说明。

    SET odps.sql.row.policy.enabled=true;
  • 使用SQL查询添加了行级访问控制的表时,由于行级访问控制不支持分区裁剪,所以后付费计量中的输入数据量不会因过滤而减少;同时被设置行级访问规则的用户即使在SQL表达式中定义了查询全表数据,仍然可能得到过滤后的结果,扫描源表的数据量可能会大于用户通过结果判断的大小,请您注意费用控制。

  • 面向不同用户和各自过滤规则创建多个视图或表并进行共享的方式,可实现行级访问控制,并且可以在已过滤数据的基础上进行计算,操作更为简便和直观。详情请参见行级别权限控制。相较于面向使用者创建共享对象的方式,行级访问控制会让基于原表的查询执行计划更复杂,但是免去为每个使用者逐个创建共享对象的工作,并避免了共享对象的冗余存储,且更适合针对大量用户定义规则,您可以根据需求灵活使用。

语法说明

您可以通过CREATE/REPLACE、DROP、DESC、LIST命令创建(或修改)、删除或查看行级访问规则。

CREATE/REPLACE

  • 命令格式

    CREATE [OR REPLACE] ROW ACCESS POLICY [IF NOT EXISTS] <policy_name> 
    ON <table_name> 
    TO <authorized_objects> 
    FILTER USING <filter_expr>
    [AS <clause>];
  • 命令说明

    创建(或修改)行级访问规则,为指定的对象(用户或角色)授权。

  • 参数说明

    参数

    描述

    policy_name

    行级访问控制权限的名称,可自定义。

    table_name

    访问的表名称。

    authorized_objects

    授权对象。取值如下:

    • USER <user_list>:待授权的用户名称列表,多个用户名称之间以半角逗号分隔。

    • ROLE <role_list>:待授权的角色名称列表,多个角色名称之间以半角逗号分隔。

    • DEFAULT:未命中用户规则或角色规则时的缺省规则。

    filter_expr

    过滤条件表达式,详情请参见filter_expr说明

    clause

    行级访问规则的属性。取值为PERMISSIVERESTRICTIVE,详情请参见指定PERMISSIVE或RESTRICTIVE属性

    • filter_expr说明。

      当前版本对filter_expr做了较严格的约束:

      • filter_expr必须是一个标量表达式(Scalar Expression),并且取值类型必须为BOOLEAN类型。

      • 不允许其中存在子查询和SELECT、CREATE、UPDATE等语句。

      • filter_expr只能引用常量或者所授权表的字段,不允许引用其他表的字段。

      • 支持使用MaxCompute内建的运算符,包括关系运算符、算数运算符、位运算符和逻辑运算符。详情请参见运算符

      • 关于函数:只允许使用部分内建的标量函数(Builtin Scalar Function),不允许调用用户自定义的UDF,也不允许调用聚合函数、窗口函数等。支持使用的函数如下:

        • 字符串函数:CONCAT、CONCAT_WS、GET_JSON_OBJECT、INSTR、LENGTH、LENGTHB、REGEXP_EXTRACT、REGEXP_REPLACE、REVERSE、SUBSTR、TOLOWER、TOUPPER、TRIM、LTRIM、RTRIM、REPLACE。

        • 数学函数:ABS、ROUND。

        • 时间函数:DATEADD、TO_DATE、TO_CHAR。

        • 其他函数:SIZE、FIELD、COALESCE、IF、SPLIT。

    • 指定PERMISSIVE或RESTRICTIVE属性。

      对某一个用户来说,可能会有多个Policy对其生效,因此需要将多个Policy结合在一起来确定用户最终是否可以访问某一行数据。创建Row Access Policy时,可以通过AS {PERMISSIVE | RESTRICTIVE}指定Policy为PERMISSIVE或者RESTRICTIVE属性,若不指定属性,则默认为PERMISSIVE。示例如下:

      假如有多个Policy对某个用户生效:

      • 若Policy属性都为PERMISSIVE,则Policy之间是OR的关系,即对某一行数据而言,只要这些Policy中的任何一个filter_expr的取值为true,用户就可以访问此行数据。

      • 若Policy属性都为RESTRICTIVE,则Policy之间是AND的关系,即对某一行数据而言,必须满足所有Policy,用户才可以访问此行数据。

      • 若其中一部分Policy属性为PERMISSIVE,另外一部分属性为RESTRICTIVE,对某一行数据而言,必须同时满足以下两点,用户才可以访问此行数据。

        • 至少满足PERMISSIVE属性的Policy中的其中一条。

        • 满足所有RESTRICTIVE属性的Policy。

      说明

      每次对表增加新的行级权限规则,都需要整体评估表上所有的行级权限规则组合效果。例如当用户同时存在一条RESTRICTIVE规则和一条PERMISSIVE规则时,这条PERMISSIVE规则也必须被满足。

  • 使用场景

    • 为指定的用户(User)单独授权。

      假设表名为table01,其中存在一个数据类型为STRING,且列名为region的字段,为某些用户设置行级访问规则,限制其只能访问region字段中值为china的记录。命令示例如下:

      CREATE ROW ACCESS POLICY policy01
      ON table01
      TO USER (aliyun$odps_test01@aliyun.com,aliyun$odps_test02@aliyun.com)
      FILTER USING (region = "china");
    • 为指定的角色(Role)单独授权。

      假设系统中有两个角色,分别为role1role2,为这两个角色授权,使其只能访问region字段中取值为china的记录。命令示例如下:

      CREATE ROW ACCESS POLICY policy02
      ON table01
      TO ROLE (role1, role2)
      FILTER USING (region = "china");
    • 为Default用户授权。

      假设存在一张表,大约有100个潜在的用户可能访问该表。管理员已经针对其中的某个用户,使用指定用户授权命令为其单独进行了授权。对于其余未指定授权的用户,也希望能够进行权限控制。首先,给某个表增加某个用户或角色的访问控制,则代表这张表已经被行级访问控制策略管理,其他用户由于没有在允许访问的列表中,所以都失去对表中数据的访问权限。此时管理员可以使用如下命令修改Default用户的访问授权。

      默认禁止其他用户访问的行为,等同于指定Default用户都没有访问权限。

      CREATE ROW ACCESS POLICY policy03 
      ON table01
      TO DEFAULT 
      FILTER USING (false);

      假如想限制Default用户只能访问region字段中值为other的记录,命令示例如下:

      CREATE ROW ACCESS POLICY policy04 
      ON table01
      TO default 
      FILTER USING (region = "other");
      重要

      对表增加行级规则时,需要考虑被控制的用户之外的其他用户的访问行为,如果该表之前已经被其他用户访问,则需要为他们设置明确的规则,避免产生非预期的禁止访问报错。

  • 鉴权处理逻辑

    用户访问某一张table,假如table上配置了行级访问规则,则鉴权处理流程如下:

    image

DROP

  • 删除某张表中的某个特定Policy。

    DROP ROW ACCESS POLICY <policy_name> ON <table_name>;
  • 删除某张表中的所有Policy。

    DROP ALL ROW ACCESS POLICY ON <table_name>;

DESC

查看某张表中某个Policy的权限详情。

DESC ROW ACCESS POLICY <policy_name> ON <table_name>;

LIST

  • 列出某张表中的所有Policy。

    LIST ROW ACCESS POLICY ON <table_name>;
  • 查看某张表中针对某个用户配置的Policy。

    LIST ROW ACCESS POLICY ON <table_name> TO USER <user_name>;
  • 查看某张表中针对某个角色配置的Policy。

    LIST ROW ACCESS POLICY ON <table_name> TO ROLE <role_name>;

示例数据

创建名为policy_test的表,并插入数据。SQL命令如下:

--创建表
CREATE TABLE policy_test(a bigint, b string);

--插入数据
INSERT overwrite TABLE policy_test VALUES(1L, "1"), (2L, "2"), (3L, "3"), (4L, "4");

--检查插入的数据
SELECT * FROM policy_test;
--返回结果:
+------------+---+
| a          | b |
+------------+---+
| 1          | 1 |
| 2          | 2 |
| 3          | 3 |
| 4          | 4 |
+------------+---+

使用示例

此处以Default用户授权场景为例,为您介绍行级访问权限的使用。在此之前,您需要提前准备好示例数据

  • 示例1:对一张表增加行级权限,允许Default用户访问policy_test表中a=2L的数据。

    1. 创建行级访问权限policy01。

      CREATE row access policy policy01 ON policy_test TO default filter using (a = 2L);
    2. 查看policy_test表中policy01的具体权限。

      DESC row access policy policy01 on policy_test;

      返回结果:

      --返回结果如下,注意Restrictive取默认值false
      Authorization Type: Row Access Policy
      Name: policy01
      Objects: acs:odps:*:projects/clone_table_2/tables/policy_test
      FilterExpr: (a = 2L)
      NormalizedFilterExpr: (policy_test.a = 2L)
      Restrictive: false
      Settings: 
      
      
      OK
    3. 查询policy_test表数据,验证授权操作是否生效。

      SELECT * FROM policy_test;

      返回结果:

      --返回结果如下,注意policy生效,只返回了部分记录
      +------------+---+
      | a          | b |
      +------------+---+
      | 2          | 2 |
      +------------+---+
  • 示例2:对一张表增加两个permissive的行级权限,允许Default用户访问policy_test表中a=2La=3L的数据。

    1. 创建行级访问权限policy02。

      CREATE row access policy policy02 ON policy_test TO default filter using (a = 3L);
    2. 列出policy_test表中的所有policy。

      LIST row access policy ON policy_test;

      返回结果:

      --返回结果如下:
      Authorization Type: Row Access Policy
      Name: policy01
      Objects: acs:odps:*:projects/clone_table_2/tables/policy_test
      FilterExpr: (a = 2L)
      NormalizedFilterExpr: (policy_test.a = 2L)
      Restrictive: false
      Settings: 
      Name: policy02
      Objects: acs:odps:*:projects/clone_table_2/tables/policy_test
      FilterExpr: (a = 3L)
      NormalizedFilterExpr: (policy_test.a = 3L)
      Restrictive: false
      Settings: 
      
      
      OK
    3. 查询policy_test表数据,验证授权操作是否生效。

      SELECT * FROM policy_test;

      返回结果:

      --有两个policy,policy01和policy02同时起作用,它们都是permissive的,因此返回了两条记录
      +------------+---+
      | a          | b |
      +------------+---+
      | 2          | 2 |
      | 3          | 3 |
      +------------+---+
  • 示例3:对一张表增加两个permissive和一个restrictive的行级权限,允许Default用户访问policy_test表中满足(a=2L||a=3L)&&a<3L的数据。

    1. 创建行级访问权限policy03,并将其属性设置为RESTRICTIVE。

      CREATE row access policy policy03 ON policy_test TO default filter using (a < 3L) as restrictive;
    2. 查看policy_test表中policy03的具体权限。

      DESC row access policy policy03 ON policy_test;

      返回结果:

      --返回结果如下,注意其Restrictive取值为true
      Authorization Type: Row Access Policy
      Name: policy03
      Objects: acs:odps:*:projects/clone_table_2/tables/policy_test
      FilterExpr: (a < 3L)
      NormalizedFilterExpr: (policy_test.a < 3L)
      Restrictive: true
      Settings: 
      
      
      OK
    3. 查询policy_test表数据,验证授权操作是否生效。

      select * from policy_test;

      返回结果:

      --返回结果如下,这里policy01/policy02/policy03同时起作用,
      --policy01和policy02是permisive的,只要其中有一个满足就可以。
      --而policy03是restrictive的,必须要满足条件。
      +------------+---+
      | a          | b |
      +------------+---+
      | 2          | 2 |
      +------------+---+
  • 示例4:对一张表增加一个permissive和一个restrictive的行级权限,Default用户访问表数据需要同时满足这两个条件。

    1. 删除行级访问权限policy01。

      SET odps.sql.row.policy.enabled=true;
      DROP ROW ACCESS POLICY policy01 ON policy_test;
    2. 查看policy_test表上的行级权限。

      SET odps.sql.row.policy.enabled=true;
      LIST ROW ACCESS POLICY ON policy_test;

      返回结果:

      Authorization Type: Row Access Policy
      Name: policy02
      Objects: acs:odps:*:projects/clone_table_2/tables/policy_test
      FilterExpr: (a = 3L)
      NormalizedFilterExpr: (policy_test.a = 3L)
      Restrictive: false
      Settings: 
      Name: policy03
      Objects: acs:odps:*:projects/clone_table_2/tables/policy_test
      FilterExpr: (a < 3L)
      NormalizedFilterExpr: (policy_test.a < 3L)
      Restrictive: true
      Settings: 
      
      
      OK
    3. 查询policy_test表数据,验证授权结果。

      --检查插入的数据
      SELECT * FROM policy_test;

      返回结果:

      --返回结果为空,因为=3和小于3同时生效。
      +------------+------------+
      | a          | b          | 
      +------------+------------+
      +------------+------------+

附录

兼容行为检查

MaxCompute在对过滤表达式进行计算时,其行为可能会受Flag参数的影响。如果用户在某种兼容行为下定义了行级访问规则,但在另一种兼容行为下定义了其他行级访问规则,则会由于结果不符合预期而产生数据泄露,因此执行行级访问控制时,会检查其定义时的兼容行为,如果不一致则会报错,并禁止访问。

示例:此处基于示例数据,为您展示不同兼容行为下Policy的应用。

  1. SUBSTR函数的第2个参数取值为0时的行为,受Hive兼容模式的影响。详情请参见SUBSTR

    • Hive兼容模式下,SUBSTR函数的起始位置为0时,与起始位置为1时的结果相同。

      SET odps.sql.hive.compatible=true;
      SELECT substr('abc', 0);
      --在hive兼容模式下,起始位置为0时,与起始位置为1时的结果相同。
      +-----+
      | _c0 |
      +-----+
      | abc |
      +-----+
    • 非Hive兼容模式下,当起始位置为0时,返回值为空字符串。

      SET odps.sql.hive.compatible=false;
      SELECT substr('abc', 0);
      --在非hive兼容模式下,当起始位置为0时,返回值为空字符串
      +-----+
      | _c0 |
      +-----+
      |     |
      +-----+
  2. 在创建行级访问规则时,系统会检查filter_expr中使用的运算符和函数,假如它们的行为依赖于某些Flag参数,则会将这些Flag参数记录在Settings中,您可以通过DESC命令查看相关Flag参数。

    --删除表上配置的所有policy
    DROP ALL row access policy ON policy_test;
    
    --在Hive兼容模式下配置policy,filter_expr中使用了SUBSTR函数
    SET odps.sql.hive.compatible=true;
    CREATE row access policy policy04 ON policy_test TO default filter using(substr(b, 0)='1');
    
    --查看policy_test表中配置的policy详情
    DESC row access policy policy04 on policy_test;

    返回结果如下:Settings中记录了odps.sql.hive.compatible参数的取值。

    Authorization Type: Row Access Policy
    Name: policy04
    Objects: acs:odps:*:projects/sql_optimizer/tables/policy_test
    FilterExpr: substr(b, 0) = '1'
    NormalizedFilterExpr: ::substr(policy_test.b, 0) = '1'
    Restrictive: false
    Settings: odps.sql.hive.compatible=true
  3. 后续应用Policy时,会判断当前环境中的Settings和创建Policy时的Settings是否一致,若不一致则会报错。

    • Hive兼容模式下,应用Policy。

      SET odps.sql.hive.compatible=true;
      SELECT * FROM policy_test;

      返回结果:

      +------------+---+
      | a          | b |
      +------------+---+
      | 1          | 1 |
      +------------+---+
    • 非Hive兼容模式,由于odps.sql.hive.compatible参数与创建Policy时的取值不一致,导致Query执行失败。

      SET odps.sql.hive.compatible=false;
      SELECT * FROM policy_test;

      返回结果:

      FAILED: ODPS-0130071:[0,0] Semantic analysis exception - physical plan generation failed: java.lang.IllegalArgumentException: Row access policy flag mismatch for: odps.sql.hive.compatible, flag value when grant this policy is true, while at runtime is false. please set odps.sql.hive.compatible = true or contact your project manager.

Tunnel下载行为说明

对于配置了行级访问规则的表,使用Tunnel下载表数据时也需要遵守行级访问控制的规则,但Tunnel本身没有可以执行行级访问控制过滤逻辑的计算能力,需要启动SQL任务按照规则进行过滤,然后再下载任务计算的结果。

因此使用Tunnel命令或Tunnel SDK下载配置了行级访问规则的MaxCompute表数据时,会存在一段等待执行SQL任务的时间。

管理员禁止新建行级权限

如果项目管理员希望禁止在该项目内新建Row Access Policy,可以通过如下命令来修改项目空间属性。

重要

只允许管理员通过setproject命令在Project级别进行修改,用户在Session级别无法修改该参数值。

setproject odps.sql.create.row.policy.disable=true;

取值范围如下:

  • false(默认值):允许新建Row Access Policy。

  • true:不允许新建Row Access Policy,但是允许对已有的Policy进行修改和删除。