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の代わりにSET LOCALを使用する。ポリシーで使用するtenant_id列にインデックスを作成する。RLSの対象となるユーザーで実行するとpg_dumpは失敗するため、バックアップはBYPASSRLSロールで取得する。

DBAtlas で開く →

関連項目