Azure Cosmos DB for PostgreSQL 中的行级安全性

适用对象: Azure Cosmos DB for PostgreSQL(由 PostgreSQL 的 Citus 数据库扩展提供支持)

PostgreSQL 行级安全策略限制哪些用户可以修改或访问哪些表行。 在多租户群集中,行级安全性特别有用。 它允许单个租户对数据库具有完全的 SQL 访问权限,同时对其他租户隐藏每个租户的信息。

为多租户应用实现

我们可以通过使用与表行级安全策略相关的数据库角色的命名约定来实现租户数据的分离。 我们将按编号顺序为每个租户分配一个数据库角色:tenant1tenant2 等。租户将使用这些单独的角色连接到 Azure Cosmos DB for PostgreSQL。 行级安全策略可以将角色名称与 tenant_id 分布列中的值进行比较,以决定是否允许访问。

以下是如何在 tenant_id 分发的简化事件表上应用该方法。 首先创建角色 tenant1tenant2。 然后以 citus 管理员用户身份运行以下 SQL 命令:

CREATE TABLE events(
  tenant_id int,
  id int,
  type text
);

SELECT create_distributed_table('events','tenant_id');

INSERT INTO events VALUES (1,1,'foo'), (2,2,'bar');

-- assumes that roles tenant1 and tenant2 exist
GRANT select, update, insert, delete
  ON events TO tenant1, tenant2;

就目前而言,任何对该表具有选择权限的人都可以看到这两行。 来自任一租户的用户可以查看并更新其他租户的行。 可以使用行级表安全策略解决数据泄漏问题。

每个策略由以下两个子句组成:USING 和 WITH CHECK。 当用户尝试读取或写入行时,数据库会针对这些子句计算每一行。 PostgreSQL 根据 USING 子句中指定的表达式检查现有表行,并根据 WITH CHECK 子句检查将通过 INSERT 或 UPDATE 创建的行。

-- first a policy for the system admin "citus" user
CREATE POLICY admin_all ON events
  TO citus           -- apply to this role
  USING (true)       -- read any existing row
  WITH CHECK (true); -- insert or update any row

-- next a policy which allows role "tenant<n>" to
-- access rows where tenant_id = <n>
CREATE POLICY user_mod ON events
  USING (current_user = 'tenant' || tenant_id::text);
  -- lack of CHECK means same condition as USING

-- enforce the policies
ALTER TABLE events ENABLE ROW LEVEL SECURITY;

现在角色 tenant1tenant2 针对其各自的查询获得不同的结果:

作为 tenant1 连接:

SELECT * FROM events;
┌───────────┬────┬──────┐
│ tenant_id │ id │ type │
├───────────┼────┼──────┤
│         1 │  1 │ foo  │
└───────────┴────┴──────┘

作为 tenant2 连接:

SELECT * FROM events;
┌───────────┬────┬──────┐
│ tenant_id │ id │ type │
├───────────┼────┼──────┤
│         2 │  2 │ bar  │
└───────────┴────┴──────┘
INSERT INTO events VALUES (3,3,'surprise');
/*
ERROR:  new row violates row-level security policy for table "events_102055"
*/

后续步骤