はじめに
にゃーん
この記事は、PostgreSQL 10全部ぬこ Advent Calendar 2017 の6日目のエントリです。
今日はPGCONF.Asia 2017のDay-2。その後のパーティーにも出席する予定。
ロールとは
PostgreSQLではロールという概念で、ユーザの権限を設定することができます。といってもPostgreSQLの場合は、ログイン権限のないユーザ、とも言えますが。ロールは他の複数のロールを含むことが可能ですし、ネストも可能です。
(そのために、このロールはどんなロールの権限ももっているのか分かりにくくなることも。そういうときには、指定したロールに属するロールを再帰クエリで検索するで紹介したようなクエリでロールの関係を調べてみるのもいいかと)。
デフォルトロール
PostgreSQL 9.6からはPostgreSQLがデフォルトで利用可能なロールが追加されました。
そして、PostgreSQL 10ではデフォルトロールが3つ追加されました。
デフォルトロールについては昨日のPGCONF.Asiaのセッションでもちょっと話がありましたね。
ロール名 | サポートバージョン | 役割 |
---|---|---|
pg_signal_backend | 9.6 | 他のバックエンドにシグナルを送信する |
pg_read_all_settings | 10 | PostgreSQLパラメータのうち特権ユーザでないと参照できないパラメータも参照可能にする。 |
pg_read_all_stats | 10 | pg_stat_* ビューについて、特権ユーザでないと参照できない情報を参照可能にする。 |
pg_stat_scan_tables | 10 | 統計情報に関するSQL関数のうち、特権ユーザでないと実行できない関数を実行可能にする。 |
pg_monitor | 10 | 上記のpg_read_all_settings, pg_read_all_stats, pg_stat_scan_tablesをメンバとして持つロール。監視に関しては権限を強化したロール。監視のみを行うユーザなんかに付与すると良さげ。 |
要するにPostgreSQL 10で追加されたロールは、特権ユーザでないと参照できない情報を一般ユーザでも可能にするためのものです。
誤解
このロールが追加されたときに、「もしかして、一般ユーザではpg_stat_* ビューや、pg_* システムカタログが参照できなくなった?」と思ったのですが、実はそーでもなかった。
デフォルトロールを付与することによる効果
PostgreSQL 10で追加されたロールが、どういった効果をもたらすのか、実際に動作させて確認してみる。
この検証のために、以下の3つのロール(ユーザ)を設定しておく。
postgres=# \du
List of roles
Role name | Attributes | Member of
------------------+------------------------------------------------------------+------------------------
general_user | | {}
monitor_user | | {pg_monitor}
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
scan_tables_user | | {pg_stat_scan_tables}
settings_user | | {pg_read_all_settings}
stats_user | | {pg_read_all_stats}
pg_read_all_settingsロール
pg_read_all_settingsロールは、特権ロールしか参照できないパラメータを、一般ユーザにも与えることができるロールである。
特権ロールしか参照できないパラメータ
みんなお馴染みのSHOW ALLコマンドをpostgresユーザとgeneral_userで実行してみる。
まず、general_userで実行。
[nuko@localhost ~]$ psql -U general_user postgres -c "SHOW ALL"
name | setting |
description
-------------------------------------+--------------------+-------------------------------------------------------------------------------------------------------------------------------
allow_system_table_mods | off | Allows modifications of the structure of system tables.
application_name | psql | Sets the application name to be reported in statistics and logs.
(中略)
xmloption | content | Sets whether XML data in implicit parsing and serialization operations is to be considered as documents or content fragments.
zero_damaged_pages | off | Continues processing past damaged page headers.
(253 rows)
次に、postgresユーザで実行。
[nuko@localhost ~]$ psql postgres -U postgres -c "SHOW ALL"
name | setting | description
-------------------------------------+--------------------------------------+-------------------------------------------------------------------------------------------------------------------------------
allow_system_table_mods | off | Allows modifications of the structure of system tables.
application_name | psql | Sets the application name to be reported in statistics and logs.
(中略)
xmloption | content | Sets whether XML data in implicit parsing and serialization operations is to be considered as documents or content fragments.
zero_damaged_pages | off | Continues processing past damaged page headers.
(269 rows)
おわかりいただけただろうか...
general_userで実行したときに見えなかったのに、postgresユーザで実行するとパラメータが見えちゃった...。
いや、当たり前だけどね。
では、一体どのPostgreSQLパラメータが、特権ロールでないと見えないのか。
自分はてっきり、contextがsuperuserのもの、だと思いこんでいたが、実際にはそう単純な話ではない。
PostgreSQL 10.1環境で、一般ロールと特権ロールを用いて、pg_settingsを検索して、その結果の差分をとると、これらのパラメータが特権ロールでないとパラメータとして表示すらされないことが分かった。
name | context |
---|---|
config_file | postmaster |
data_directory | postmaster |
external_pid_file | postmaster |
hba_file | postmaster |
ident_file | postmaster |
shared_preload_libraries | postmaster |
unix_socket_directories | postmaster |
krb_server_keyfile | sighup |
log_directory | sighup |
log_filename | sighup |
ssl_ciphers | sighup |
ssl_dh_params_file | sighup |
ssl_ecdh_curve | sighup |
stats_temp_directory | sighup |
dynamic_library_path | superuser |
session_preload_libraries | superuser |
へぇー。これは知らんかった。やっぱり調べてみるもんだな。
本題
前置きが長くなってしまった。このように、一般ユーザでは参照できない、PostgreSQLパラメータは存在するが、pg_read_all_settingsロールは、特権ロールでなくても、これらのパラメータを参照可能にするロールになる。
以下、ただのユーザ(general_user)、特権ユーザ(postgres)、pg_read_all_settingsロール(settings_user)で、PostgreSQLパラメータ hba_file を参照する例を示す。
[nuko@localhost ~]$ psql postgres -U general_user -c "SHOW hba_file"
ERROR: must be superuser or a member of pg_read_all_settings to examine "hba_file"
[nuko@localhost ~]$ psql postgres -U postgres -c "SHOW hba_file"
hba_file
----------------------------------
/home/nuko/pgdata/10/pg_hba.conf
(1 row)
[nuko@localhost ~]$ psql postgres -U settings_user -c "SHOW hba_file"
hba_file
----------------------------------
/home/nuko/pgdata/10/pg_hba.conf
(1 row)
pg_read_all_statsロール
pg_read_all_statsロールは、特権ユーザでないと参照できない情報を、一般ユーザでも参照可能にするロールである。
例えば、セッションの監視でお馴染み、pg_stat_acitivityの、一部の列が特権ロールまたは、pg_read_all_statsロールを持つユーザでないと参照することはできない(権限エラーではなく、モザイク空白や、特殊な文字列で表示される)
まず、特権ロール(postgres)ユーザで検索してみる。
[nuko@localhost ~]$ psql postgres -U postgres -c "SELECT pid, usename, state, query,backend_type FROM pg_stat_activity"
pid | usename | state | query
| backend_type
-------+--------------+---------------------+----------------------------------------------------------------------+---------------------
39444 | | | | autovacuum launcher
39446 | postgres | | | background worker
48462 | user_a | idle | | client backend
48723 | user_b | idle in transaction | SELECT 'b'; | client backend
48975 | general_user | idle | SELECT 'general'; | client backend
48984 | postgres | active | SELECT pid, usename, state, query,backend_type FROM pg_stat_activity | client backend
39442 | | | | background writer
39441 | | | | checkpointer
39443 | | | | walwriter
(9 rows)
次に、一般ユーザ(general_user)ユーザで検索してみる。
そうすると、行数は同じなのだが、以下のように一部の情報が見えなくなっている。
- 自分と同じユーザ以外のstate, backend_typeが空白になる。
- 自分と同じユーザ以外のqueryは
<insufficient privilege>
と表示される。- 特殊な文字列を出すのはqueryの値域が確定していないからなんだろうな。
[nuko@localhost ~]$ psql postgres -U general_user -c "SELECT pid, usename, state, query,backend_type FROM pg_stat_activity"
pid | usename | state | query | backend_type
-------+--------------+--------+----------------------------------------------------------------------+------
----------
39444 | | | <insufficient privilege> |
39446 | postgres | | <insufficient privilege> |
48462 | user_a | | <insufficient privilege> |
48723 | user_b | | <insufficient privilege> |
48975 | general_user | idle | SELECT 'general'; | client backend
49087 | general_user | active | SELECT pid, usename, state, query,backend_type FROM pg_stat_activity | client backend
39442 | | | <insufficient privilege> |
39441 | | | <insufficient privilege> |
39443 | | | <insufficient privilege> |
(9 rows)
最後に、pg_read_all_statsロールをもつユーザ(stats_user)ユーザで検索してみる。
これは特権ユーザによる検索と同じ結果となる。
[nuko@localhost ~]$ psql postgres -U stats_user -c "SELECT pid, usename, state, query,backend_type FROM pg_stat_activity"
pid | usename | state | query
| backend_type
-------+--------------+---------------------+----------------------------------------------------------------------+---------------------
39444 | | | | autovacuum launcher
39446 | postgres | | | background worker
48462 | user_a | idle | | client backend
48723 | user_b | idle in transaction | SELECT 'b'; | client backend
48975 | general_user | idle | SELECT 'general'; | client backend
49192 | stats_user | active | SELECT pid, usename, state, query,backend_type FROM pg_stat_activity | client backend
39442 | | | | background writer
39441 | | | | checkpointer
39443 | | | | walwriter
(9 rows)
[nuko@localhost ~]$
正直、どの稼働統計情報ビューのどの列が、特権ユーザのみ表示対象となるのか、全部は確認しきれていないが、いずれにせよ稼働統計情報ビューを参照するユーザにはpg_read_all_statsをつけておくべき、ということだろう。
pg_stat_scan_tablesロール
pg_stat_scan_tablesロール・・・これは最初文書を読んだときに、何を言っているのかさっぱりわからなかった。
文書にはこう書かれている。
Execute monitoring functions that may take ACCESS SHARE locks on tables, potentially for a long time.
長時間、テーブルに対して共有ロックをとる可能性のある監視機能を実行する。という文章に読めるのだが・・・
良くわからなかったので、PostgreSQL 10.1のソースアカイブから、このロールを使っている箇所が力技(findとgrep)で探してみる。と・・・見つかった。
どうやら、現状は、contrib/pgstattuple モジュールの関数で使われているようだ。たしかに、contrib/pgstattupleを巨大なテーブルに対して実行すると、長時間かかるし、それにロックも取るよなあ。
ということで実際に動かしてみた。
まず、特権ロール(postgres)ユーザで検索してみる。
[nuko@localhost ~]$ psql bench -U postgres -c "SELECT * FROM pgstattuple('pgbench_accounts');"
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
13434880 | 100000 | 12100000 | 90.06 | 0 | 0 | 0 | 188960 | 1.41
(1 row)
次に一般ユーザ(general_user)で実行。これは権限エラーになる。
[nuko@localhost ~]$ psql bench -U general_user -c "SELECT * FROM pgstattuple('pgbench_accounts');"
ERROR: permission denied for function pgstattuple
最後に、pg_stat_scan_tablesロールをもつユーザ(scan_table_user)で実行。これは実行可能。
[nuko@localhost ~]$ psql bench -U scan_tables_user -c "SELECT * FROM pgstattuple('pgbench_accounts');"
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
13434880 | 100000 | 12100000 | 90.06 | 0 | 0 | 0 | 188960 | 1.41
(1 row)
他に該当する関数があるかどうかは調べていない。悪しからず・・・。
pg_monitorロール
pg_monitorロールは、ここまで説明したpg_read_all_settings, pg_read_all_stats, pg_stat_scan_tablesのロールを全て包含するロールになる。
なので、監視の役割を詳細に分離するのでなければ、pg_monitorを設定しておけばOK!
おわりに
今日はPostgreSQL 10に追加された、デフォルトロールについて書いてみました。今後、これらのロールが更に充実していくと、postgresユーザのような特権ロールをもつユーザをなるべく使わなくする運用が可能になりそうです。
まあ、この辺はまだまだOracleには大きく及ばないところですが・・・
おわりに
このエントリ、予想以上に書くのに時間かかった・・・。
なお、PostgreSQL 10のデフォルトロールに少し関連したネタを、PGCONF.Asia 2017のDAY-2 オフィシャルパーティーのライトニングトークで発表予定です。
諸事情により今日のLTのテーマは変更しますが、お暇なら聞きに来てくださいね!にゃーん!
参考:該当するリリースノート
本エントリに関連するPostgreSQL 10リリースノートの記載です。
E.2.3.1.6. Monitoring
- Add default monitoring roles (Dave Page)