TECH BLOG
技術ブログ
  • 2023-09-01 PostgreSQL

    PostgreSQL のブートストラップ・ユーザーについて

ブートストラップ・ユーザーから SUPERUSER 属性を削除できなくなりました。

PostgreSQL 16 で予定されている変更点を確認していると、「ブートストラップ・ユーザーから SUPERUSER 属性を削除できなくなりました。」というものがありました。

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=e530be2c5ce77475d56ccf8f4e0c4872b666ad5f

ブートストラップ・ユーザーに対して 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 を変更しましたが、基本的にデフォルトで用意されているオブジェクトやユーザに対しては変更しないことが推奨となります。

CATEGORY

ARCHIVE

PostgreSQLに関するご相談は
株式会社インサイトまで
お気軽にお問い合わせください。

CONTACT