CodeGym /コース /SQL SELF /行レベルのアクセス制御: Row-Level Security (RLS)

行レベルのアクセス制御: Row-Level Security (RLS)

SQL SELF
レベル 47 , レッスン 3
使用可能

ロールやテーブルレベルの権限が「玄関のガードマン」だとしたら、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: INSERTUPDATEの時にこの条件をチェックする。

例:自分の注文だけアクセスできるようにする

ユーザーが自分の注文だけ見れるようにするポリシーを作ろう。今のユーザーの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の動作確認

ユーザーuser1user2を作ってみよう。

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);

これで、user1user_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)用のポリシーをちゃんと作ってない。
  • USINGWITH CHECKの条件を正しく書いてない。例えばuser_idをチェックしないと、全行にアクセスできちゃう。

Row-Level SecurityはPostgreSQLで一番強力なセキュリティ機能の1つだよ。行単位でアクセス制御できて、アクセス管理を自動化できるから、データ保護が重要な複雑なアプリには特におすすめ!

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION