行安全策略

一般情况下,数据库账号拥有表的读写权限后,就可以对表中所有的行进行查询或更新。云原生数据仓库 AnalyticDB PostgreSQL 版7.0新增了行安全策略特性(Row Security Policies),该特性可以约束数据库账号,使数据库账号只能查询或更新指定行。

注意事项

  • 行安全策略对高权限账号、拥有BYPASSRLS属性的账号不生效。

  • 使用ENABLE的方式开启行安全策略时,行安全策略对表的拥有者不生效。如需对表的拥有者进行限制,需使用ALTER TABLE ... FORCE ROW LEVEL SECURITY语句。

  • 当表上同时存在多个行安全策略时,多个策略会同时生效。例如A策略只允许返回1和2行,B策略只允许返回4行,查询时会同时返回1、2和4行。

行安全策略参数

行安全策略的参数及说明具体信息,请参见行安全策略官方文档创建策略官方文档

配置表的行安全策略

  1. 使用客户端工具连接数据库

  2. 创建一张测试表logtest,并插入测试数据。

    CREATE TABLE logtest (
         id serial primary key,
         username text,
         log_event text);
    
    INSERT INTO logtest VALUES (1,'report','DELETE issued'),
                               (2,'messaging', 'Message queue purged'),
                               (3,'messaging','Reset accounts'),
                               (4,'report', 'Reset accounts');
  3. 创建两个普通账号report和messaging,并授予表logtest的SELECT权限。

    CREATE ROLE report WITH LOGIN ENCRYPTED PASSWORD '111111';
    CREATE ROLE messaging WITH LOGIN ENCRYPTED PASSWORD '111111';
    
    GRANT SELECT ON logtest TO report;
    GRANT SELECT ON logtest TO messaging;
  4. 创建一个行安全策略,限制用户只能看到表中username列中与当前数据库账号名一致的行。

    CREATE POLICY policy_user_log ON logtest
       FOR ALL
       TO PUBLIC
       USING (username = current_user);
  5. 在表logtest中开启行安全策略。开启后,该表的所有行安全策略都将生效。

    ALTER TABLE logtest ENABLE ROW LEVEL SECURITY;
    重要
    • 通过上述方法开启行安全策略不会对表的拥有者生效,如果想要对表的拥有者也生效,需使用ALTER TABLE ... FORCE ROW LEVEL SECURITY语句。

    • 同一张表可以定义多条行安全策略。

  6. 分别使用普通账号和高权限账号查询表logtest。

    • 使用账号report查询表logtest。

      SELECT * FROM logtest;

      返回信息中只返回了username列为report的行。

      id| username | log_event
      --+----------+--------------
      1 | report   | DELETE issued
      4 | report   | Reset accounts
      (2 rows)
    • 使用账号messaging查询表logtest。

      SELECT * FROM logtest;

      返回信息中只返回了username列为messaging的行。

      id| username  | log_event
      --+-----------+---------------------
      2 | messaging | Message queue purged
      3 | messaging | Reset accounts
      (2 rows)
    • 使用高权限账号查询表logtest。

      SELECT * FROM logtest;

      返回信息返回了所有行。

      id| username  | log_event
      --+-----------+---------------------
      1 | report    | DELETE issued
      2 | messaging | Message queue purged
      3 | messaging | Reset accounts
      4 | report    | Reset accounts
      (4 rows)
  7. 再添加一个行安全策略,仅返回id列为偶数的行。

     CREATE POLICY policy_even_ids_only ON logtest
       FOR ALL
       TO PUBLIC
       USING (id % 2 = 0);
  8. 使用账号report查询表logtest。

    SELECT * FROM logtest;

    返回信息中不仅返回了id列为偶数的列,还返回了username列为report的列。

    id| username  | log_event
    --+-----------+---------------------
    1 | report    | DELETE issued
    2 | messaging | Message queue purged
    4 | report    | Reset accounts
    (3 rows)

行安全策略透传视图

前提条件

  • 本功能仅支持云原生数据仓库 AnalyticDB PostgreSQL 版实例V7.0.6.0及以上版本。

  • 声明为security_invoker的视图内部的所有查询将以调用者的权限执行,因此调用者需要具备视图内部涉及到的全部内容的SELECT权限。

功能介绍

用户可能会有对基表建立视图的需求,但在基表上的行安全策略对普通账号不会生效。您需要创建安全视图,安全视图会继承基表的行安全策略。

行安全策略对普通账号不生效的示例

  1. 对上表logtest创建视图v1,并授予账号report SELECT权限。

    CREATE VIEW v1 as SELECT * FROM logtest;
    GRANT SELECT ON v1 TO report;
  2. 使用账号report查询视图v1。

    SELECT * FROM v1;
  3. 基表logtest上的行级权限不生效。

    id| username  | log_event
    --+-----------+---------------------
    1 | report    | DELETE issued
    2 | messaging | Message queue purged
    3 | messaging | Reset accounts
    4 | report    | Reset accounts
    (4 rows)

创建安全视图

如果要将行安全策略透传到视图,必须在创建视图时指定选项security_invoker,以提高数据安全性。当启用security_invoker时,意味着视图内部的所有查询将以调用者的权限而非视图定义者的权限来执行。

CREATE VIEW v1 WITH (security_invoker) AS SELECT * FROM logtest;

修改视图的行安全策略

您可以修改已有视图的行安全策略,开启或关闭行安全策略。

-- 开启行安全策略
ALTER VIEW v1 SET (security_invoker = on);

-- 关闭行安全策略
ALTER VIEW v1 SET (security_invoker = off);

查询安全视图

开启行安全策略后,再使用账号report查询视图v1。

SELECT * FROM v1;

基表logtest上的行级权限已经生效。

id| username  | log_event
--+-----------+---------------------
1 | report    | DELETE issued
2 | messaging | Message queue purged
4 | report    | Reset accounts
(3 ROWS)

配置物化视图的行安全策略

  1. 对上述测试表logtest建立一个物化视图mv_logtest,并授权SELECT给report账号。

CREATE MATERIALIZED VIEW mv_logtest
AS
  SELECT * FROM logtest;

GRANT SELECT ON mv_logtest TO report;
  1. 使用report账号查询物化视图mv_logtest,可以看到所有行。

SELECT * FROM mv_logtest;

 id | username  | log_event
----+-----------+----------------------
  2 | messaging | Message queue purged
  3 | messaging | Reset accounts
  4 | report    | Reset accounts
  1 | report    | DELETE issued
(4 ROWS)
  1. 对物化视图mv_logtest创建一个行安全策略,限制用户只能看到其中username列中与当前数据库账号名一致的行。

CREATE POLICY policy_user_log ON mv_logtest
   FOR ALL
   TO PUBLIC
   USING (username = current_user);
  1. 在物化视图mv_logtest中开启行安全策略。开启后,该物化视图的所有行安全策略都将生效。

ALTER MATERIALIZED VIEW mv_logtest ENABLE ROW LEVEL SECURITY;
说明
  • 通过上述方法开启行安全策略不会对物化视图的拥有者生效,如果想要对物化视图的拥有者也生效,需使用ALTER MATERIALIZED VIEW ... FORCE ROW LEVEL SECURITY语句。

  • 一个物化视图可以定义多条行安全策略。

  • 行安全策略支持物化视图和实时物化视图。

  1. 再次使用report账号查询物化视图mv_logtest。

SELECT * FROM mv_logtest;

返回信息中只返回了username列为report的行。

id| username | log_event
--+----------+--------------
1 | report   | DELETE issued
4 | report   | Reset accounts
(2 ROWS)