-
2024-11-10 PostgreSQL
PostgreSQLのCREATE ROLEで指定するINHERIT属性
CREATE ROLE で指定する INHERIT 属性と NOINHERIT 属性
本記事では PostgreSQL のロールに指定できる INHERIT 属性(と NOINHERIT 属性)について、挙動を確認した結果を記載しています。
PostgreSQL 文書での説明を確認
まずは、PostgreSQL 文書で INHERIT 属性がどのように説明されているかを確認します。
【 PostgreSQL 16.4文書 - CREATE ROLE - 】
https://www.postgresql.jp/document/16/html/sql-createrole.html
これは、このロールが別のロールのメンバとして追加された場合、このロールと将来のコマンドの両方でメンバ資格継承状態に影響します。 特に、このコマンドで追加されたメンバ資格の継承状態は、IN ROLE句を使用して制御され、後のコマンドではROLE句を使用して制御されます。 また、GRANTコマンドを使用してこのロールをメンバとして追加する際のデフォルトの継承状態としても使用されます。 指定しない場合、INHERITがデフォルトです。
少し分かりにくい部分があるかと思いますので、説明を要約しますと
- ロールを付与された場合、その付与元のロールの権限を自動的に利用できるように
- なる => INHERIT 属性
- ならない => NOINHERIT 属性
ということになります。
もう少し補足しますと、PostgreSQL文書の中にある「メンバ資格の継承状態」というのは、ロールのメンバシップ(所属関係)を指しています。
その後、CREATE ROLE コマンドの IN ROLE 句を使用して、これから作成するロールにロールを付与することができるという説明があります。
また、「後のコマンドでは」という部分は、GRANT コマンドを指しているものだと考えられます。
検証用 SQL を実行して挙動を確認
ここで実際に INHERIT と NOINHERIT について、検証用の SQL を実行して挙動を確認します。
検証した環境は下記となります。
- RockeyLinux 9.4
- PostgreSQL 16.4
test_role ロールと、test_user_inherit ユーザ および test_user_noinherit ユーザを作成し、それぞれ利用できる権限を確認します。
-- 検証用のロールとユーザを作成
postgres=# CREATE ROLE test_role;
CREATE ROLE
postgres=# CREATE ROLE test_user_inherit WITH LOGIN INHERIT;
CREATE ROLE
postgres=# CREATE ROLE test_user_noinherit WITH LOGIN NOINHERIT;
CREATE ROLE
-- test_role に statsrepo.snapshot テーブルを参照できる権限を付与
postgres=# GRANT USAGE ON SCHEMA statsrepo TO test_role;
GRANT
postgres=# GRANT SELECT ON statsrepo.snapshot TO test_role;
GRANT
-- test_role を test_user_inherit と test_user_noinherit に付与
postgres=# GRANT test_role TO test_user_inherit;
GRANT ROLE
postgres=# GRANT test_role TO test_user_noinherit;
GRANT ROLE
これでロールの作成と権限の付与が完了しました。
この状態で test_user_inherit と test_user_noinherit でログインし、statsrepo.snapshot を参照できるかどうかを確認します。
-- INHERIT のユーザで statsrepo.snapshot を参照
$ psql -U test_user_inherit -d postgres -c "SELECT * FROM statsrepo.snapshot"
snapid | instid | time | comment | exec_time | snapshot_increase_size | xid_current
--------+--------+-------------------------------+---------+-----------------+------------------------+-------------
1 | 1 | 2024-09-09 08:09:55.910061+00 | | 00:00:00.178096 | 221184 | 761
(1 row)
-- NOINHERIT のユーザで statsrepo.snapshot を参照
$ psql -U test_user_noinherit -d postgres -c "SELECT * FROM statsrepo.snapshot"
ERROR: permission denied for schema statsrepo
LINE 1: SELECT * FROM statsrepo.snapshot
上記の通り、INHERIT のユーザは test_role の権限を自動的に利用できるため statsrepo.snapshot を参照できます。NOINHERIT のユーザは test_role の権限を自動的に利用できないため、statsrepo.snapshot を参照できません。
SET ROLE コマンドでロールを切り替える
では、NOINHERIT のユーザが、付与元ロールの権限を利用するにはどのようにするかというと SET ROLE コマンドを利用します。
-- NOINHERIT のユーザでログイン
$ psql -U test_user_noinherit -d postgres
psql (16.4)
Type "help" for help.
-- ロールを変更して statsrepo.snapshot を参照
postgres=> SET ROLE test_role;
SET
postgres=> SELECT * FROM statsrepo.snapshot;
snapid | instid | time | comment | exec_time | snapshot_increase_size | xid_current
--------+--------+-------------------------------+---------+-----------------+------------------------+-------------
1 | 1 | 2024-09-09 08:09:55.910061+00 | | 00:00:00.178096 | 221184 | 761
(1 row)
上記のように SET ROLE コマンドで一時的に別のロールに切り替わることにより、その切り替わった先のロールの権限で SQL を実行できます。
SET ROLE でロールを切り替えた場合、切り替え元のロールが持つ権限は利用できなくなりますので注意してください。
元のロールの権限を利用したい場合には、以下のように RESET ROLE コマンドを実行します。
-- SET ROLE を戻す
postgres=> RESET ROLE;
RESET
これで元のロールの権限を利用できるようになりました。
CREATE ROLE で INHERIT 属性がデフォルトになっている理由
CREATE ROLE では INHERIT 属性がデフォルト値になっています。この理由について、PostgreSQL 文書に記載がありましたので下記に引用します。
【 PostgreSQL 16.4文書 - 22.3. ロールのメンバ資格 - 】
https://www.postgresql.jp/document/16/html/role-membership.html
注記
標準SQLでは、ユーザとロールとの間に明確な違いがあり、ユーザはロールのように自動的に権限を継承することができません。 PostgreSQLでこの振舞いを実現させるには、SQLロールとして使用するロールにはINHERIT属性を付与し、SQLユーザとして使用するロールにはNOINHERIT属性を付与します。 しかし、8.1リリースより前との互換性を保持するために、PostgreSQLはデフォルトで、すべてのロールにINHERIT属性を付与します。
標準 SQL では NOINHERIT がデフォルトのようですが、PostgreSQL では互換性を保持するために INHERIT がデフォルトとなっているようです。
まとめ
本記事では CREATE ROLE で指定する INHERIT 属性について確認しました。PostgreSQL では、デフォルトで付与元のロールの権限を自動的に利用できますので、便利でもありますがロールを付与した際に意図しない権限まで付与してしまう可能性があります。
そういった場合に備えて、定期的にロールが持つ権限を確認することが推奨となります。また、CREATE ROLE 時に NOINHERIT 属性を指定することも検討するのもよいと思います。