ロールやテーブルレベルの権限が「玄関のガードマン」だとしたら、Row-Level Securityは「建物の各部屋ごとに入れるかチェックする専属ガードマン」って感じだよ。
RLSを使うと、ユーザーは許可されたテーブルの行だけ操作できるようになる。例えば:
- ネットショップなら、マネージャーは自分の注文だけ見れる。
- CRMプラットフォームでは、社員は自分のチームの顧客だけ見れる。
- 銀行システムなら、クライアントは自分の口座だけアクセスできる。
RLSの仕組み
RLSの基本はアクセス・ポリシーの考え方だよ。ポリシーで、どの行がどのロールやユーザーに見えるか、どの操作(INSERT, UPDATE, DELETE)ができるか決めるんだ。
デフォルトだとRLSは無効になってて、手動で有効化する必要があるよ。
テーブルでRLSを有効化する
ネットショップの注文を保存するordersテーブルを作ってみよう:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
product_name TEXT NOT NULL,
price NUMERIC NOT NULL
);
テスト用のデータをいくつか追加しよう:
INSERT INTO orders (user_id, product_name, price)
VALUES
(1, 'スマートフォン', 500),
(2, 'ノートパソコン', 1000),
(1, 'イヤホン', 100),
(3, 'キーボード', 50);
次に、このテーブルでRLSを有効化しよう:
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
これでRLSの仕組みを有効にしたけど、まだポリシー自体は設定してない。ポリシーを作るまでは、RLSは実際にはテーブルのアクセスに影響しないよ。
アクセス・ポリシーの作成
アクセス制御のルールを追加するには、次のコマンドを使うよ:
CREATE POLICY ポリシー名
ON テーブル名
[FOR { SELECT | INSERT | UPDATE | DELETE }]
TO ロール
USING (アクセス条件)
WITH CHECK (チェック条件);
FOR: どの操作にポリシーを適用するか決める(SELECT,INSERT,UPDATE,DELETE)。省略すると全操作に適用されるよ。TO: どのロールにポリシーを有効にするか指定。省略すると全ロールに適用。USING: この条件を満たす行だけユーザーに見える。WITH CHECK:INSERTやUPDATEの時にこの条件をチェックする。
例:自分の注文だけアクセスできるようにする
ユーザーが自分の注文だけ見れるようにするポリシーを作ろう。今のユーザーのIDがテーブルのuser_idと一致する場合だけ見れるようにする:
CREATE POLICY user_can_view_own_orders
ON orders
FOR SELECT
USING (user_id = current_user::INT);
これってどういうこと?
- ポリシー名は
user_can_view_own_orders。 SELECT操作に適用される。user_idが今のユーザーID(current_user)と一致する行だけ見える。
つまり、user_id = 1のユーザーでログインしてたら、自分の注文だけ見れるってこと!
RLSの動作確認
ユーザーuser1とuser2を作ってみよう。
CREATE ROLE user1 LOGIN PASSWORD 'password1';
CREATE ROLE user2 LOGIN PASSWORD 'password2';
このテーブルへのSELECT権限をロールに付与する:
GRANT SELECT ON orders TO user1, user2;
次に、user1で接続してクエリを実行してみる:
SELECT * FROM orders;
結果:user_id = 1の行だけ見えるよ。
INSERT用のポリシー
ユーザーが自分の注文だけ追加できるようにしたい場合(つまり、user_idが今のユーザーIDと一致する行だけ追加できるようにする)。
INSERT用のポリシーを作ろう:
CREATE POLICY user_can_insert_own_orders
ON orders
FOR INSERT
WITH CHECK (user_id = current_user::INT);
これで、user1がuser_idが1じゃない注文を追加しようとすると、エラーになるよ。
UPDATEとDELETE用のポリシー
同じように、データの更新や削除用のポリシーも作れる。例えば:
自分のデータだけ更新できるように:
CREATE POLICY user_can_update_own_orders
ON orders
FOR UPDATE
USING (user_id = current_user::INT)
WITH CHECK (user_id = current_user::INT);
自分のデータだけ削除できるように:
CREATE POLICY user_can_delete_own_orders
ON orders
FOR DELETE
USING (user_id = current_user::INT);
複数ポリシーの適用
1つのテーブルに複数のポリシーを作れるよ。全部同時に適用される。例えば、1つのロールに複数のルールがある場合、PostgreSQLは全部(論理AND)チェックする。
RLSの確認とデバッグ
テーブルにどんなポリシーが設定されてるか確認したいときは、このコマンドを使おう:
\di+ テーブル名
一時的にRLSを無効化したい(例えば管理者用)場合は:
ALTER TABLE orders DISABLE ROW LEVEL SECURITY;
管理者ロールSUPERUSERはデフォルトでRLSの制限を受けないから、全部のデータが見れるよ。
RLS設定時のよくあるミス
こんなミスがよくあるから注意:
ALTER TABLE ... ENABLE ROW LEVEL SECURITYでRLSを有効化し忘れる。- 全操作(
SELECT,INSERT,UPDATE,DELETE)用のポリシーをちゃんと作ってない。 USINGやWITH CHECKの条件を正しく書いてない。例えばuser_idをチェックしないと、全行にアクセスできちゃう。
Row-Level SecurityはPostgreSQLで一番強力なセキュリティ機能の1つだよ。行単位でアクセス制御できて、アクセス管理を自動化できるから、データ保護が重要な複雑なアプリには特におすすめ!
GO TO FULL VERSION