PostgreSQL | SQLite+MySQL経験者向け、30日で習得するPostgreSQL:プロレベル運用 - Day26 権限管理

SQL PostgreSQL
スポンサーリンク

Day26 前半のゴール

「“何でもできるユーザー”をやめて、“役割ごとに守る”感覚を持つ」

Day26 は「権限管理」です。
ここまで性能や自動処理を見てきたけれど、本番運用で一番怖いのは「やってはいけない人が、やってはいけない操作をできてしまうこと」です。
今日は、その入口となる「ロール・権限設計」の前半戦です。

前半のゴールはこうです。
PostgreSQL の「ロール」が、ユーザーとグループの両方の役割を持つことを理解する。
権限(プリビレッジ)が「何をしていいか」を細かく制御するものだと分かる。
アプリ用ユーザー・開発者・管理者をざっくり分けた権限イメージを持てる。

まずは、「ロールって何者?」からいきます。


ロールとは何か

「ユーザーでもあり、グループでもある“箱”」

PostgreSQL では、「ユーザー」と「グループ」を厳密に分けず、
どちらも「ロール(role)」という概念で扱います。

イメージとしては、「権限をぶら下げるための箱」です。

あるロールは「ログインできるユーザー」として使える。
別のロールは「ログインはしないけど、権限の束(グループ)」として使える。
ロール同士で「このロールはあのロールの権限を引き継ぐ」という関係を作れる。

例えば、こんな感じの設計ができます。

アプリ用のログインロール:app_user
開発者向けのロール:dev_role
読み取り専用のロール:read_only_role

そして、「app_user に read_only_role を付与する」といった形で、
権限を組み合わせていきます。

ここで重要なのは、「ロール=ログインIDそのもの」ではなく、
「ログインできるロール」「権限だけ持つロール」を柔軟に作れる、という感覚です。


権限(プリビレッジ)とは何か

「“どのオブジェクトに対して、何をしていいか”のルール」

ロールが「誰か・どんな役割か」だとすると、
権限(privilege)は「そのロールが何をしていいか」です。

PostgreSQL では、オブジェクトごとに権限の種類が決まっています。
代表的なものだけ、イメージで押さえましょう。

テーブルに対する権限
SELECT(読み取り)
INSERT(追加)
UPDATE(更新)
DELETE(削除)
TRUNCATE(全削除)
REFERENCES(外部キー参照)
TRIGGER(トリガー作成)

データベースに対する権限
CONNECT(接続)
CREATE(スキーマなどの作成)

スキーマに対する権限
USAGE(そのスキーマ内のオブジェクトを参照できる)
CREATE(そのスキーマ内にテーブルなどを作れる)

これらを組み合わせて、「このロールは、このテーブルに対して SELECT だけ」「このロールは、このスキーマに CREATE できる」といったルールを作ります。

大事なのは、「権限は“オブジェクト×操作”の組み合わせで考える」という視点です。


例題:アプリ用ユーザーの権限をイメージする

「本番DBに“スーパーユーザーで接続”をやめる」

よくある悪いパターンから、逆に学びましょう。

ありがちなNG構成:
アプリケーションが、本番DBにスーパーユーザー(何でもできるユーザー)で接続している。

これだと、アプリのバグやSQLインジェクションが起きたときに、
テーブル削除・権限変更・他DBへのアクセスなど、何でもできてしまいます。
セキュリティ的には最悪です。

理想に近づけるために、まずは「アプリ用ロール」をこうイメージします。

アプリ用ロール app_user は、
特定のデータベースに CONNECT できる。
アプリが使うスキーマに USAGE できる。
必要なテーブルに対して、SELECT / INSERT / UPDATE / DELETE だけ持つ。
テーブル定義の変更(ALTER TABLE)や DROP はできない。
他のユーザーやロールの管理は一切できない。

これだけでも、「アプリからの事故で壊せる範囲」がかなり小さくなります。

実際のGRANT文のイメージはこんな感じです。

-- DBへの接続を許可
GRANT CONNECT ON DATABASE myapp_db TO app_user;

-- スキーマの利用を許可
GRANT USAGE ON SCHEMA public TO app_user;

-- テーブルへの操作を許可
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;
SQL

ここでの重要ポイントは、「アプリ用ユーザーには“本当に必要な最小限”だけを与える」という考え方です。


ロールの“継承”という考え方

「権限の束を“役割”としてまとめる」

ロールは、「他のロールをメンバーとして持つ」ことができます。
これは、グループにユーザーを所属させるイメージに近いです。

例えば、こういう設計を考えます。

読み取り専用ロール:read_only_role
→ テーブルに対して SELECT だけ持つ。

アプリ用ロール:app_user
read_only_role を継承しつつ、追加で INSERT / UPDATE / DELETE を持つ。

開発者ロール:dev_role
read_only_role を継承しつつ、一部の管理系権限も持つ。

このとき、read_only_role に対して権限をGRANTしておけば、
それを継承しているロールは自動的にその権限を使えます。

イメージとしては、

「権限の束(read_only_role)」を作る。
「実際にログインするロール(app_user, dev_role)」は、その束を引き継ぐ。

という構造です。

これにより、

「読み取り専用の範囲を変えたい」ときは read_only_role だけを直せばよい。
アプリ用・開発者用など、複数のロールに一括で反映される。

というメリットが出てきます。

ここでの学びは、「ロールを“ログインID”としてだけでなく、“権限の束”としても設計する」という視点です。


例題:開発者と本番運用者のロールを分ける

「“何でもできる人”を減らす設計」

もう一つ、現実に近い例を考えます。

小さなチームだと、「開発者がそのまま本番DBにも入る」ということがよくあります。
それ自体は仕方ない場面もありますが、「何でもできる権限」を渡す必要はありません。

例えば、こう分けられます。

dev_role(開発者ロール)
開発用DBでは、ほぼ何でもできる(CREATE TABLE, ALTER TABLE, DROP TABLE など)。
本番DBでは、基本的に SELECT のみ、必要に応じて一部UPDATEを許可。

ops_role(運用ロール)
本番DBで、メンテナンスやリカバリに必要な権限を持つ。
ただし、アプリデータの直接編集は極力避ける。

superuser(スーパーユーザー)
本当に必要なときだけ使う“最後の鍵”。
日常運用では使わない。

このように、「役割ごとにロールを分ける」ことで、
「誰がどこまでできるか」を明確にできます。

ここで大事なのは、「スーパーユーザーを日常的に使わない」「アプリ用・開発用・運用用を分ける」という2つの軸です。


Day26 前半のまとめ

PostgreSQL のロールは「ユーザー」と「グループ」を兼ねる“権限の箱”であり、ロールに対して「どのオブジェクト(DB・スキーマ・テーブル…)に、どの操作(SELECT / INSERT / UPDATE / DELETE / CONNECT / USAGE…)を許すか」という形で権限(プリビレッジ)をGRANTしていくことで、「アプリ用ユーザーはこのDBに接続できて、このスキーマのテーブルを読み書きできるが、定義変更や他DB操作はできない」といった細かいルールを作れる。
さらに、ロール同士を継承させることで「read_only_role のような権限の束」を作り、それを app_user や dev_role が引き継ぐ構造にすると、「読み取り専用の範囲を変えたいときに1箇所直せば全体に反映される」ようになり、「スーパーユーザーで本番に接続する」「何でもできるユーザーが常に使われている」といった危険な状態から一歩抜け出せる――ここまでのイメージが持てれば、Day26 前半としてはとても良いスタートです。

タイトルとURLをコピーしました