PostgreSQL

PostgreSQL 15 から public スキーマにテーブルを作れない(permission denied for schema public)

PostgreSQL 15からはデフォルトでpublicスキーマにテーブルを作れない

PostgreSQL 15 のサーバーに一般のユーザで接続して、いつものように create table したら「permission denied for schema public」と怒られました。14 までは、どのユーザでも public スキーマにテーブルを作れていたので、びっくりしました、、。

sooni >> psql -h localhost -d udondb -U sooni
ユーザー sooni のパスワード:
psql (14.7、サーバー 15.3 (Debian 15.3-1.pgdg120+1))
警告: psql のメジャーバージョンは 14 ですが、サーバーのメジャーバージョンは 15 です。
         psql の機能の中で、動作しないものがあるかもしれません。
"help"でヘルプを表示します。

udondb=> create table ex01 (
udondb(> execseq serial
udondb(>  ,completion        boolean default false
udondb(>  ,rid               integer
udondb(>  ,name              character varying (30)
udondb(>  ,memo              character varying (30)
udondb(>  ,created           timestamp default current_timestamp
udondb(>  ,last_modification timestamp default current_timestamp
udondb(> );
ERROR:  permission denied for schema public
行 1: create table ex01 (
                   ^
-- publicスキーマへのアクセス権限を確認する
--
udondb=>  select n.nspname as "schema",pg_catalog.pg_get_userbyid(n.nspowner) as "owner"
udondb-> ,n.nspacl
udondb-> from pg_catalog.pg_namespace n
udondb-> where n.nspname !~ '^pg_' and n.nspname <> 'information_schema'
udondb-> order by 1;
 schema |       owner       |                            nspacl
--------+-------------------+---------------------------------------------------------------
 public | pg_database_owner | {pg_database_owner=UC/pg_database_owner,=U/pg_database_owner}
(1 行)


udondb=>

nspacl の中身は、次のように読みます。

書き方意味
pg_database_owner=UC/…データベースの所有者は、U(使う)と C(作る)の両方ができる
=U/…「=」の左が空なのは「全員(PUBLIC)」のこと。全員は U(使う)だけ

つまり、データベースの所有者でなければ、public スキーマにテーブルを作れません。

-- postgres ユーザにてsooniユーザに対し、create権限を付与する
--
udondb=# grant create on schema public to sooni;
GRANT
udondb=#
-- 付与した権限を確認する
--
udondb=> \g
 schema |       owner       |                                         nspacl
--------+-------------------+-----------------------------------------------------------------------------------------
 public | pg_database_owner | {pg_database_owner=UC/pg_database_owner,=U/pg_database_owner,sooni=C/pg_database_owner}
(1 行)

-- 再度create tableの実行
--
udondb=> create table ex01 (
udondb(>   execseq serial
udondb(>  ,completion        boolean default false
udondb(>  ,rid               integer
udondb(>  ,name              character varying (30)
udondb(>  ,memo              character varying (30)
udondb(>  ,created           timestamp default current_timestamp
udondb(>  ,last_modification timestamp default current_timestamp
udondb(> );
CREATE TABLE
udondb=>

-- 今度は無事作成できました。

なぜこうなったのか

PostgreSQL 15 で、誰でも public スキーマにオブジェクトを作れる権限がなくなりました。public スキーマの所有者も、データベースの所有者(pg_database_owner)に変わっています。

理由はセキュリティです。誰でも public スキーマに関数などを作れると、悪意のあるユーザが、ほかのユーザが使う関数と同じ名前の関数を置いて、すり替えることができてしまいます。

※ 14 まではどのユーザでも作れたこと、変更の理由は、PostgreSQL 15 のリリースノートなどで調べたものです。手元の 14 では確かめていません。

もう一つのやり方:ユーザ名と同じスキーマを作る

GRANT で public スキーマに権限を付ける代わりに、ユーザ名と同じ名前のスキーマを作る方法もあります。search_path の初期値が "$user", public なので、スキーマ名を付けずにテーブルを作ると、ユーザ名と同じスキーマに作られます。

-- postgres ユーザにて
CREATE SCHEMA sooni AUTHORIZATION sooni;

-- sooni ユーザにて
SHOW search_path;
--    search_path
-- -----------------
--  "$user", public

CREATE TABLE ex01 (a int);
SELECT schemaname, tablename FROM pg_tables WHERE tablename = 'ex01';
--  schemaname | tablename
-- ------------+-----------
--  sooni      | ex01

(PostgreSQL 15 で確認)ユーザごとにテーブルを分けられるので、Oracle の「ユーザ=スキーマ」に近い使い方になります。

関連記事

スポンサーリンク
タイトルとURLをコピーしました