-
2023-09-01 PostgreSQL
PostgreSQL のブートストラップ・ユーザーについて
ブートストラップ・ユーザーから SUPERUSER 属性を削除できなくなりました。
PostgreSQL 16 で予定されている変更点を確認していると、「ブートストラップ・ユーザーから SUPERUSER 属性を削除できなくなりました。」というものがありました。
ブートストラップ・ユーザーに対して SUPERUSER 属性を除去するような ALTER 文を実行すると、PostgreSQL 16 からはエラーとなります。
実際の挙動を下記に例示します。
PostgreSQL 15 以前の挙動
postgres=# ALTER USER postgres NOSUPERUSER ;
ALTER ROLE
postgres=# \du postgres
List of roles
Role name | Attributes | Member of
-----------+-------------------------------------------------+-----------
postgres | Create role, Create DB, Replication, Bypass RLS | {}
- PostgreSQL 15 では、postgres ユーザーから SUPERUSER 属性を除去できました。
PostgreSQL 16 以降の挙動
postgres=# ALTER USER postgres NOSUPERUSER ;
ERROR: permission denied to alter role
DETAIL: The bootstrap user must have the SUPERUSER attribute.
postgres=# \du postgres
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
- PostgreSQL 16 では、postgres ユーザーから SUPERUSER 属性を除去できなくなりました。
ブートストラップ・ユーザー
この「ブートストラップ・ユーザー」というものは、postgres ユーザが該当するようですが、PostgreSQL では、あまり聞きなれない単語だと思います。
そのため、内部的にどのような条件で判定しているのか気になり、実際に確認しました。
本記事ではその確認結果をご報告したいと思います。
ソースコードの確認
まずソースコードの変更内容を確認しますと
if (!should_be_super && roleid == BOOTSTRAP_SUPERUSERID)
という「roleid が BOOTSTRAP_SUPERUSERID かどうか」を判定している if 文が追加されています。
roleid は Oid 型の変数のようですので、ユーザーの oid と考えられます。
その roleid と比較している BOOTSTRAP_SUPERUSERID が、その名の通りブートスラップ・ユーザーに該当する ID となっていることになりそうです。
BOOTSTRAP_SUPERUSERID は src/backend/catalog/pg_authid_d.h で、下記のように定義されています。
#define BOOTSTRAP_SUPERUSERID 10
つまり、oid = 10 に該当するユーザーが BOOTSTRAP_SUPERUSEID であるということになりそうです。
実際に oid = 10 のユーザーが何かを確認してみました。
postgres=# SELECT * FROM pg_roles WHERE oid = 10;
rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolconnlimit | rolpassword | rolvaliduntil | rolbypassrls | rolconfig | oid
----------+----------+------------+---------------+-------------+-------------+----------------+--------------+-------------+---------------+--------------+-----------+-----
postgres | t | t | t | t | t | t | -1 | ******** | | t | | 10
(1 row)
想定通り oid = 10 は postgres ユーザーでしたので、postgres ユーザが BOOTSTRAP_SUPERUSERID、つまり「ブートストラップ・ユーザー」であることを確認できました。
oid = 10 のユーザー名
ちなみに、oid = 10 のユーザー名はデータベースクラスタを作成(initdb)した OS ユーザーの名前が設定されます。
例えば ubuntu という OS ユーザーが作成したデータベースクラスタでは、oid = 10 のユーザー名は ubuntu となります。
postgres=# SELECT * FROM pg_roles WHERE oid = 10;
rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolconnlimit | rolpassword | rolvaliduntil | rolbypassrls | rolconfig | oid
----------+----------+------------+---------------+-------------+-------------+----------------+--------------+-------------+---------------+--------------+-----------+-----
ubuntu | t | t | t | t | t | t | -1 | ******** | | t | | 10
(1 row)
とはいっても基本的には postgres ユーザーでデータベースクラスタを作成することになると思いますので、それほど気にする仕様ではありません。
確認の確認
念の為、oid = 10 が本当にブートストラップ・ユーザーであるかどうかを確かめてみます。
検証の方法は、postgres ユーザの oid を 10 以外に変更し、ALTER 文で SUPERUSER 属性を除去できるか、という手順です。
postgres=# SELECT current_user;
current_user
--------------
super_user
(1 row)
postgres=# UPDATE pg_authid SET oid = 9999 WHERE oid = 10;
UPDATE 1
- postgres ユーザーの oid を 10 から 9999 に変更
postgres=# ALTER USER postgres NOSUPERUSER ;
ALTER ROLE
postgres=# \du postgres
List of roles
Role name | Attributes | Member of
-----------+-------------------------------------------------+-----------
postgres | Create role, Create DB, Replication, Bypass RLS | {}
- postgres ユーザーから SUPERUSER 属性を除去
以上のとおり、postgres ユーザーの oid を 10 以外にすることで、postgres ユーザーから SUPERUSER 属性を除去することができました。
ブートストラップ・ユーザーかどうかは、やはり oid = 10 かどうかで判定しているようです。
蛇足
上記の確認は postgres ユーザ以外の SUPERUSER 属性を持つユーザーで検証しました。
postgres ユーザーで検証してみると、また違った挙動となりました。
postgres=# SELECT current_user;
current_user
--------------
postgres
(1 row)
postgres=# UPDATE pg_authid SET oid = 9999 WHERE oid = 10;
UPDATE 1
- postgres ユーザーの oid を 10 から 9999 に変更
postgres=# ALTER USER postgres NOSUPERUSER ;
ERROR: permission denied to alter role
DETAIL: Only roles with the SUPERUSER attribute may alter roles with SUPERUSER.
- postgres ユーザーから SUPERUSER 属性を除去しようとすると、SUPERUSER 属性を変更できるのは SUPERUSER 属性のユーザーだけ、というエラーが発生
postgres=# UPDATE pg_authid SET oid = 10 WHERE rolname = 'postgres';
ERROR: permission denied for table pg_authid
- postgres ユーザーの oid を 10 に戻そうとするとエラーが発生
postgres=# \du postgres
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
postgres=# CREATE ROLE super_user WITH SUPERUSER LOGIN;
ERROR: permission denied to create role
DETAIL: Only roles with the CREATEROLE attribute may create roles.
postgres=# CREATE ROLE ippan_user WITH LOGIN;
ERROR: permission denied to create role
DETAIL: Only roles with the CREATEROLE attribute may create roles.
- postgres ユーザーには SUPERUSER 属性および、CREATEROLE 属性がついていることを確認
- にもかかわらず、SUPERUSER 属性をもつユーザーを作成しようとするとエラーが発生
ということで postgres ユーザが自分の oid を 10 以外にした場合には、少し不可解な挙動になりました。
まとめ
今回の検証で oid = 10 がブートストラップ・ユーザーであることを確認できました。
実際にソースコードを確認した上で検証を行い、(一部、不可解な挙動となりましたが)想定通りの結果がでましたのでスッキリできました。
注意点
今回は検証のために、postgres ユーザーの属性や oid を変更しましたが、基本的にデフォルトで用意されているオブジェクトやユーザに対しては変更しないことが推奨となります。