RLS
Row Level Security
https://www.postgresql.jp/document/current/html/sql-createpolicy.html
CREATE POLICY
create new row-level security policy
example usage
1. use current_settings
create a role and set tenant_id as settings
code:sql
-- create role
CREATE ROLE app;
-- role authority
GRANT USAGE ON SCHEMA "public" TO app;
GRANT ALL ON ALL TABLES IN SCHEMA "public" TO app;
GRANT ALL ON ALL SEQUENCES IN SCHEMA "public" TO app;
-- enable RLS to "users" table
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- create RLS policy to "users" table
CREATE POLICY tenant_isolation_policy ON users TO app
USING (tenant_id = (current_setting('app.current_tenant_id')::text));
--- create connection
SET LOCAL ROLE app;
SET LOCAL app.current_tenant_id = :tenant_id;
-- select/update/delete
-- inserted implicity
-- WHERE tenant_id = (current_setting('app.tenant_id')::text)
-- insert
INSERT INTO users (tenant_id,user_id) VALUES (
(current_setting('app.current_tenant_id')::text),
:user_id,
);
2. use CURRENT_USER
create a role for each tenant IDs
code:sql
-- create role
CREATE ROLE "tenant_id_1";
-- role authority
GRANT USAGE ON SCHEMA "public" TO "tenant_id_1";
GRANT ALL ON ALL TABLES IN SCHEMA "public" TO "tenant_id_1";
GRANT ALL ON ALL SEQUENCES IN SCHEMA "public" TO "tenant_id_1";
-- enable RLS to "users" table
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- create RLS policy to "users" table
CREATE POLICY tenant_isolation_policy ON users TO app
USING tenant_id = CURRENT_USER;
-- create connection
SET LOCAL ROLE "tenant_id_1";
ref
soudai san
https://soudai.hatenablog.com/entry/2022/11/11/110825
Bypassの権限を持っている接続アカウントはRLSが設定されないため注意が必要
super userはRLSが設定されていないため注意が必要
https://speakerdeck.com/soudai/utilizing-rsl-in-multi-tenancy
AWS guide
https://aws.amazon.com/jp/blogs/news/multi-tenant-data-isolation-with-postgresql-row-level-security/
Sansan
https://buildersbox.corp-sansan.com/entry/2021/05/10/110000
コネクション取得時に以下のチェックをかけている
2件の異なるテナントのデータのみが挿入されたテーブルを用意しておき、このテーブルをWHERE条件無しでSELECTして、(2件ではなく)1件または0件のデータを取得できること
pg_catalog.pg_tables テーブルからSELECTして、 rowsecurity がfalseになっているテーブルが、想定されたもの(後述の tenant テーブルなど)以外に存在しないこと
NStock
https://zenn.dev/nstock/articles/multi-tenant-saas-using-rls
注意点 1. RLSポリシーが適用されないロールがある
デフォルトでは、テーブルの所有者は RLS ポリシーを無視したアクセスが可能です。そのため、テーブルを作成するDBロールとRLSを利用するテーブルロールは分割しましょう。テーブルの所有者に対してもRLSポリシーを適用するには FORCE ROW LEVEL SECURITY を利用します。
Nstockの場合、DBマイグレーションを行うDBロールと、アプリケーションでつかうDBロールを分けています。これによって、テーブルの所有者にRLSポリシーが適用されない問題を回避して、アプリケーション用のDBロールにRLSポリシーを適用しています。
注意点 2. RLSポリシーを設定してもインデックスは自動で貼られない
RLSポリシーを設定すると、USING句で指定したカラムを使った問い合わせが頻繁に走ることになります。しかしながらRLSポリシーを作成してもインデックスは自動で貼られません。そのため、RLSポリシーを追加する場合は、インデックスも併せて検討する必要があります。
https://zenn.dev/yunbopiao/articles/c5548a672c44f8
https://speakerdeck.com/sh0he1666/secure-data-access-with-go-rls-in-multi-tenant-environment?slide=16
NTT Data
https://www.slideshare.net/nttdata-tech/postgresql-roles-osc2022-online-osaka-nttdata
LayerX (RLSは採用していない)
https://speakerdeck.com/yyoshiki41/marutitenantofalseapurikesiyonshi-zhuang-shi-jian-bian-in-2022-dot-04-dot-20-saas-dot-tech-number-2
use Defined Type type TenantID string
gorm のcallback で tenant_id を WHERE にセット
ZOZO (RLS 見送り)
https://techblog.zozo.com/entry/building-multi-tenant-system-with-zozometry
HR Brain
https://times.hrbrain.co.jp/entry/postgresql-row-level-security-go
go の database/sql SessionResetter interface を使い、テナントごとにセッションプールを管理