DBAtlas · 数据库运维图谱

使用行级安全实现租户隔离

PostgreSQL安全

命令

ALTER TABLE app.orders ENABLE ROW LEVEL SECURITY;
-- Make the table owner subject to the policy too
ALTER TABLE app.orders FORCE ROW LEVEL SECURITY;

CREATE POLICY orders_tenant_isolation ON app.orders
  FOR ALL
  TO app_readwrite
  USING (tenant_id = NULLIF(current_setting('app.tenant_id', true), '')::int)
  WITH CHECK (tenant_id = NULLIF(current_setting('app.tenant_id', true), '')::int);

-- The application sets the tenant at the start of every transaction (pooler-friendly)
BEGIN;
SET LOCAL app.tenant_id = '42';
SELECT * FROM app.orders;
COMMIT;

-- Configured policies
SELECT schemaname, tablename, policyname, roles, cmd, qual, with_check
FROM pg_policies
WHERE tablename = 'orders';

作用

在表上启用 RLS,并定义一个策略:按会话变量中的租户 id 过滤行(USING),并阻止写入其他租户的数据(WITH CHECK)。

适用场景

用于在数据库中为多租户应用强制实施数据隔离,而不是依赖应用代码。

注意

超级用户和具有 BYPASSRLS 属性的角色总是绕过策略;表所有者只有在 FORCE ROW LEVEL SECURITY 时才受其约束。启用 RLS 但没有匹配的策略时,结果为空(不报错)。变量未定义时 current_setting(..., true) 返回 NULL;NULLIF 可防止 RESET 后留下的空字符串因 ''::int 而失败。用户可以用 SET 修改 app.tenant_id;只能由受信任的应用层设置,终端用户不得获得 SQL 访问权限。使用 transaction 模式的连接池时,请用 SET LOCAL 代替 SET。为策略中使用的 tenant_id 列建立索引。以受 RLS 约束的用户运行 pg_dump 会失败;请用 BYPASSRLS 角色进行备份。

在 DBAtlas 中打开 →

相关内容