MENU

【PostgreSQL】第3回 ユーザーを作成し権限管理をしてみよう(後編)

~これは、雑魚技術者の勉強記録~

f:id:g071067:20200613191805p:plain

おつかれさまです。後編をスタートさせていただきます。

シリーズ

tecsak.hatenablog.com

<第3回の概要>

~ 後編 ~
3-5.実践!publicスキーマにみるPUBLICキーワード
 前回の残課題でもある、publicの取り扱いに迫ります。

3-6.実践!スキーマを介した権限と動作検証
 第2回の復習にもなりますが、データベース・スキーマという枠組みと
 権限も絡めた総ざらいを行います。

3-5.実践!publicスキーマにみるPUBLICキーワード

 PUBLICキーワードを使用する例を紹介してみたいと思います。

前編3-4では、スキーマを意識せずにテーブルを作成しました。

結果としては、復習にもなりますが、ユーザー名と同名のスキーマが存在しない限りは "public"スキーマにて取り扱いされますので(構築時デフォルト設定)、今、即席で作成したばかりのユーザーでの作業につき(たまたま、同名のスキーマが存在したら別ですが)、やはり"public"スキーマに作成された結果となっておりました。

<再掲>

adb=> \dt
            リレーションの一覧
 スキーマ |    名前    |    型    | 所有者
----------+------------+----------+--------
 public   | roletest_a | テーブル | user_a
 public   | roletest_x | テーブル | user_x
(2 行)

adb=>

ここで、

加えて、publicスキーマを使用不可もしくは削除することをお忘れなく。

第2回の残課題でした、publicスキーマの使用不可に挑みたいと思います。

方法としては、オブジェクトの作成ができなければ問題なしとして、publicスキーマに対するcreate権限のはく奪を以て実現としてみたいと思います。

▼権限確認

スキーマに対する権限を確認してみます。publicスキーマに作成可能な状況でしたが・・・
見てみましょう。

adb=> \dn
    スキーマ一覧
   名前   |  所有者
----------+----------
 postgres | postgres
 public   | postgres
 xwork    | postgres
(3 行)

adb=>
adb=> \dn+
                            スキーマ一覧
   名前   |  所有者  |      アクセス権      |          説明
----------+----------+----------------------+------------------------
 postgres | postgres |                      |
 public   | postgres | postgres=UC/postgres+| standard public schema
          |          | =UC/postgres         |
 xwork    | postgres |                      |
(3 行)

adb=>

第2回までは出てきませんでしたが、"+"を付与して、表示内容が拡大できる場合があります。 "\dn"→"\dn+"として、表示が充実しました。

アクセス権の読み方について、対スキーマバージョンですが、前編で見たオブジェクト権限の表示とほぼ変わりません。

スキーマに対して付与できる権限は2つある、ということでした。
スーパーユーザー"postgresql"に対して付与されている、"U"、"C"がそれぞれ何を表すか
もう分かりますね! ここで、左辺が空欄のものについて、PUBLICキーワード分を意味します。
publicスキーマに対する、PUBLICキーワードの・・・  ややこしい。

また、前編ではuser_x、user_aユーザーでpublicスキーマにテーブルをCREATE出来ていたわけですが、
user_x、user_aユーザーの権限表記が見当たりませんね。

adb=> \dt
            リレーションの一覧
 スキーマ |    名前    |    型    | 所有者
----------+------------+----------+--------
 public   | roletest_a | テーブル | user_a
 public   | roletest_x | テーブル | user_x
(2 行)

adb=>

確かに3-4実施直後のままでして、テーブルのCREATE済にてpublicスキーマに存在するのですがね。 一旦、先に進めます。

▼user_xユーザーより、publicスキーマに対するcreate権限をはく奪

作成出来たのですから、当然、権限が付与されており、これをはく奪してしまおう、の試みです。 user_xユーザーを対象に行ってみます。

adb=> \c - postgres
データベース "adb" にユーザ"postgres"として接続しました。
adb=#
adb=# revoke create on schema public from user_x;
REVOKE
adb=#
adb=# \dn+
                            スキーマ一覧
   名前   |  所有者  |      アクセス権      |          説明
----------+----------+----------------------+------------------------
 postgres | postgres |                      |
 public   | postgres | postgres=UC/postgres+| standard public schema
          |          | =UC/postgres         |
 xwork    | postgres |                      |
(3 行)

adb=#

見た目、もともとuser_x分の表示が無かったわけですが、何も変わりませんね。

▼テーブル作成

 手ごたえありませんでしたので、尚更検証してみたいものです。 適当なテーブルの作成を試みてみます。

adb=# \c - user_x

データベース "adb" にユーザ"user_x"として接続しました。
adb=>
adb=> create table public.publictest_x(
adb(> id integer,
adb(> value varchar(20)
adb(> );
CREATE TABLE
adb=>
adb=> \dt
             リレーションの一覧
 スキーマ |     名前     |    型    | 所有者
----------+--------------+----------+--------
 public   | publictest_x | テーブル | user_x
 public   | roletest_a   | テーブル | user_a
 public   | roletest_x   | テーブル | user_x
(3 行)

adb=>

出来ちゃった~ 何故? と、もうネタが出ちゃっているかもしれませんが、次に進みます。

▼PUBLICキーワードより、publicスキーマに対するcreate権限をはく奪

 ユーザー直で権限が無いのに作成可能ということでしたら、ロール関係を疑うことになります。 user_xは特にロールに加入していませんが・・・ いえ、PUBLICだけは強制加入ということでした。

adb=> \du
                                                      ロール一覧
 ロール名 |                                              属性                                              | メンバー
----------+------------------------------------------------------------------------------------------------+----------
 postgres | スーパーユーザ, ロールを作成できる, DBを作成できる, レプリケーション, 行単位セキュリティを無視 | {}
 user_a   | 継承なし                                                                                       | {user_y}
 user_b   | 継承なし                                                                                       | {user_y}
 user_i   | 継承なし                                                                                       | {user_a}
 user_x   | 継承なし                                                                                       | {}
 user_y   | 継承なし                                                                                       | {}

adb=>

確かに、user_xの"メンバー"欄は空欄ですが、PUBLICキーワードだけは別物、表示されないようですね。 さて、もはやPUBLICキーワードからのはく奪以外に疑いようがありません。 そういえば、スキーマ一覧にCが表示されていました。。 実施してみます。

adb=> \c - postgres
データベース "adb" にユーザ"postgres"として接続しました。
adb=#
adb=# revoke create on schema public from PUBLIC;
REVOKE
adb=#
adb=# \dn+
                            スキーマ一覧
   名前   |  所有者  |      アクセス権      |          説明
----------+----------+----------------------+------------------------
 postgres | postgres |                      |
 public   | postgres | postgres=UC/postgres+| standard public schema
          |          | =U/postgres          |                               ・・・★
 xwork    | postgres |                      |
(3 行)

adb=#

publicスキーマに対する権限表示より、Cが消えた!(★印箇所)

▼テーブル作成

 再度、実証いたします。

adb=# \c - user_x
データベース "adb" にユーザ"user_x"として接続しました。
adb=>
adb=> create table public.publictest_x_v2(
adb(> id integer,
adb(> value varchar(20)
adb(> );
ERROR:  permission denied for schema public
行 1: create table public.publictest_x_v2(
                   ^
adb=>

CREATEの阻止成功です。 結果的には出来たものの、何か心に引っかかるものがあります・・・

・・・・・
 振り返りますと、  スキーマとオブジェクトによる、権限の2段構えは、権限の仕組み・構造を捉えにくい形にしています。 特に、PUBLICキーワードに関しては、ロール一覧にも表示されず、忘れてしまいそうです。 全ユーザーが加入するロールということで、影響力は明らかに大きいわけですが、にもかかわらず、頭の中で認識を保つのは気が引けます。

 スキーマ一覧へは、左辺空欄で以て、U・Cの表示が出ましたが、publicスキーマに対する、PUBLICキーワードへのUSAGE、CREATE権限を有した状態がデフォルトでした。 “権限あり”がデフォルトというのも、うーん、危機感を覚えますね。この手の管理は、引き算ではなく、足し算で進めていきたいもののです。
・・・・・

 当方の業務では、publicスキーマを用いず、ユーザー名=スキーマ名にて運用を行っていることもあり、PUBLICより全権はく奪してPUBLICキーワードの存在を意識する必要が無い状態にして運用しています。

3-6.実践!スキーマを介した権限と動作検証

 最後に、スキーマを介した検証をしたいと思います。
 3-6では、ユーザーと同名のスキーマを設けるモデルとしたいと思います。複数ユーザーを作成。自他スキーマ(自=ユーザーと同名のスキーマのこと)に対して、代表アクションとしてCREATEとSELECTが可能か見ていきます。

 基本的には、各ユーザーが各専用のスキーマ・オブジェクトのみを自由に使用出来、逆に、他ユーザーからの介入(CREATE、自作したオブジェクトに対するSELECT)は不可能であるべき、とします。その上で、権限を付与可能であるべきユーザーによって許可されたユーザー・対象オブジェクトの関係上でのみ操作可能であるべき、とします。

 また、スーパーユーザーは使用すべきでない点を尊重したいと思います。
従って、"専用のユーザー"を別途作成。3-6検証専用のユーザー・データベース・スキーマの作成からシナリオを組みます。"専用のユーザー"とは、ユーザー・データベース・スキーマの作成が可能なユーザーをはじめに作成するということです。

 そして、OWNERの概念を含ませた検証にしたいと思います。データベースに対しては、"専用のユーザー"がOWNERとなりますが、スキーマに対して、"専用のユーザー"による設定の余地("専用のユーザー"、"スキーマ名と同名のユーザー" の2種)と動きの違いを観察します。

f:id:g071067:20201010112525p:plain

▼シナリオ

①環境作成用のユーザー作成
 スーパーユーザーにて環境作成用のユーザー(test_x)を作成。環境作成に必要な属性を付与します。

②環境作成
 ユーザー、データベース、スキーマを作成します。スキーマのオーナーについて、"専用のユーザー"、
"スキーマ名と同名のユーザー"の2種を試すため、ユーザーとスキーマを同名にて2通り作成します。
 ・データベース名=kengen
 ・test_aユーザー - test_aスキーマ(オーナー=test_x)
 ・test_bユーザー - test_bスキーマ(オーナー=test_b)

③テーブルのCREATE
 test_x含む3ユーザーにて、2スキーマへのテーブルCREATEを試みます。
 ・test_aユーザー、test_bユーザー:meiboテーブル
 ・test_xユーザー:kibanテーブル

④テーブルのSELECT
 ③で作成したオブジェクトへの参照を試みます。

⑤テーブルの共有
 ④を踏まえ、参照不可であったユーザーへの共有がどの程度可能か検証します。
 全ユーザーによる、全オブジェクトへのSELECT権限付与を試みます。

①環境作成用のユーザー作成

まずはじめに、環境作成用のtest_xユーザーを作成します。 これは、スーパーユーザーで実施することとなります。 データベース、ユーザーの作成を実施するユーザーにつき、「データベースの作成権限」属性、「ユーザーの作成権限」属性を付与します。今回は、OSコマンドで実施してみます。

-bash-4.2$ id
uid=26(postgres) gid=26(postgres) groups=26(postgres) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
-bash-4.2$
-bash-4.2$ createuser -d -r test_x
-bash-4.2$
-bash-4.2$ psql -c '\du'
                                                      ロール一覧
 ロール名 |                                              属性                                              | メンバー
----------+------------------------------------------------------------------------------------------------+----------
 postgres | スーパーユーザ, ロールを作成できる, DBを作成できる, レプリケーション, 行単位セキュリティを無視 | {}
 test_x   | ロールを作成できる, DBを作成できる                                                             | {}
 user_a   | 継承なし                                                                                       | {user_y}
 user_b   | 継承なし                                                                                       | {user_y}
 user_i   | 継承なし                                                                                       | {user_a}
 user_x   | 継承なし                                                                                       | {}
 user_y   | 継承なし                                                                                       | {}

-bash-4.2$
-bash-4.2$ psql -c '\du test*'
                        ロール一覧
 ロール名 |                属性                | メンバー
----------+------------------------------------+----------
 test_x   | ロールを作成できる, DBを作成できる | {}

-bash-4.2$

createuserコマンドのオプションにて、各属性の付与 -d(データベースの作成権限属性) -r(ユーザーの作成権限属性) を指定。 最後にユーザー名を指定しました。 その後、スーパーユーザーでデータベースにとりあえずの接続を行いませんでした。psqlの-cオプションにてコマンドを渡し、ユーザー一覧を表示させました。 これまでの実験結果が残っており、表示行が多くなってまいりましたので、正規表現にてあらためて絞りました。

②環境作成

 それでは、作成したtest_xユーザーによる操作のパートとなりますので、じっくりとログインして、作業開始しましょうか。

-bash-4.2$ psql -U test_x postgres
psql (9.6.3)
"help" でヘルプを表示します.

postgres=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 postgres         | test_x
(1 行)

postgres=>

psqlで、-Uオプションにてログインユーザーの指定を、最後にデータベース名を指定しました。作業用のデータベースが出来ていないため、仮でpostgresデータベースへ一旦接続しています。

それでは、kengenデータベースを作成します。

postgres=> create database kengen;
CREATE DATABASE
postgres=> \l
                                        データベース一覧
   名前    |  所有者  | エンコーディング | 照合順序 | Ctype(変換演算子) |      アクセス権
-----------+----------+------------------+----------+-------------------+-----------------------
 adb       | postgres | UTF8             | C        | C                 |
 kengen    | test_x   | UTF8             | C        | C                 |
 postgres  | postgres | UTF8             | C        | C                 |
 template0 | postgres | UTF8             | C        | C                 | =c/postgres          +
           |          |                  |          |                   | postgres=CTc/postgres
 template1 | postgres | UTF8             | C        | C                 | =c/postgres          +
           |          |                  |          |                   | postgres=CTc/postgres
(5 行)

postgres=>

今回も、第2回同様、単純に作成できています。
では、作成したばかりのデータベースに接続を移動しましょう。

postgres=> \c kengen
データベース "kengen" にユーザ"test_x"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_x
(1 行)

kengen=>

順調です。続いて、test_a、test_bユーザーの作成を行います。

kengen=> create role test_a with LOGIN PASSWORD 'password';
CREATE ROLE
kengen=> create role test_b with LOGIN PASSWORD 'password';
CREATE ROLE
kengen=>
kengen=> \du test_*
                        ロール一覧
 ロール名 |                属性                | メンバー
----------+------------------------------------+----------
 test_a   |                                    | {}
 test_b   |                                    | {}
 test_x   | ロールを作成できる, DBを作成できる | {}

kengen=>

作成できました。

データベース、ユーザーときましたら、次はスキーマです。名称はユーザー名と同じ。
オーナーだけ注意します。test_aスキーマ(オーナー=test_xユーザー)、test_bスキーマ(オーナー= test_bユーザー)を作成!!

kengen=> create schema test_a authorization test_x;
CREATE SCHEMA
kengen=>
kengen=> create schema authorization test_b;
ERROR:  must be member of role "test_b"
kengen=>

 スキーマ名を省略すると、所有者と同名がデフォルトとして採用されます。
ということで、オーナーとスキーマ名が同じtest_bスキーマの作成に関しては、あえて省略してみました。
 ですが、別な要因でtest_bスキーマの作成に失敗しています。
失敗の意味としましては、作成を試みたtest_xユーザーと、オーナーとなる予定のtest_bユーザーがロール関係に無く、またtest_xユーザーはスーパーユーザーではないため、関わりの無いロールをオーナーとしたスキーマの作成が権限上、不可能ということです。

 test_b本人によるスキーマ作成は、(kengenデータベースに対する)スキーマの作成権限を付与していないため不可能です。
また、test_xユーザーとtest_bユーザーをロール関係にするのは、余計な権限の譲渡につながり、そもそもユーザーを分けている意味が無いでしょう。題意に反します。
従って、この時点で当シナリオにおいては、"ユーザー"="スキーマのオーナー"とはなり得ません。
 その上で、不自然ですが、ここだけ。スーパーユーザーで強引に実現してしまいます。

kengen=> \c - postgres
データベース "kengen" にユーザ"postgres"として接続しました。
kengen=# select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | postgres
(1 行)

kengen=#
kengen=# create schema authorization test_b;
CREATE SCHEMA
kengen=#
kengen=> \dn+
                           スキーマ一覧
  名前  |  所有者  |      アクセス権      |          説明
--------+----------+----------------------+------------------------
 public | postgres | postgres=UC/postgres+| standard public schema
        |          | =UC/postgres         |
 test_a | test_x   |                      |
 test_b | test_b   |                      |
(3 行)

kengen=>

スーパーユーザーへ安易にスイッチ変更できているように見えるかもしれませんが、OS認証で通るためです。
強引にtest_bスキーマの所有者をtest_bユーザーに揃えました。

スキーマまで出来ますと、舞台は仕切りまで整いました。オブジェクト操作に移りましょう。

③テーブルのCREATE

はじめに、テーブルのCREATEです。

test_aユーザーにて、テーブルの作成を試みます。両スキーマに対して行います。

kengen=# \c - test_a
データベース "kengen" にユーザ"test_a"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_a
(1 行)

kengen=>
kengen=> create table test_a.meibo(id integer,namae varchar(20));
ERROR:  permission denied for schema test_a
行 1: create table test_a.meibo(id integer,namae varchar(20));
                   ^
kengen=> create table test_b.meibo(id integer,namae varchar(20));
ERROR:  permission denied for schema test_b
行 1: create table test_b.meibo(id integer,namae varchar(20));
                   ^
kengen=>

ぼろぼろに怒られました~ 全滅!!

 とはいえ、後者に関しては、他ユーザー用のスキーマですので、これでOKですね。
ですが、前者、自スキーマとして作成したものまで、作成できないとあっては・・・ 理由は何でしょう?

 そうです、スキーマに対するCREATE権限が無いのです。
もしくは、オーナーであれば問題ありませんが、オーナー(test_x)≠ユーザー(test_a)につき無条件での操作は不可能。
従って、権限を介しての手続きとなります。

 ということで、test_xユーザーよりCREATE権限付与の手続きを行ってもらいたいと思います。

kengen=> \c - test_x
データベース "kengen" にユーザ"test_x"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_x
(1 行)

kengen=>
kengen=> grant create on schema test_a to test_a;
GRANT
kengen=>
kengen=> \dn+
                           スキーマ一覧
  名前  |  所有者  |      アクセス権      |          説明
--------+----------+----------------------+------------------------
 public | postgres | postgres=UC/postgres+| standard public schema
        |          | =UC/postgres         |
 test_a | test_x   | test_x=UC/test_x    +|
        |          | test_a=C/test_x      |
 test_b | test_b   |                      |
(3 行)

kengen=>

それでは、再度CREATEにチャレンジします。

kengen=> \c - test_a
データベース "kengen" にユーザ"test_a"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_a
(1 行)

kengen=>
kengen=> create table test_a.meibo(id integer,namae varchar(20));
CREATE TABLE
kengen=> create table test_b.meibo(id integer,namae varchar(20));
ERROR:  permission denied for schema test_b
行 1: create table test_b.meibo(id integer,namae varchar(20));
                   ^
kengen=>
kengen=> \dt test_*.*
          リレーションの一覧
 スキーマ | 名前  |    型    | 所有者
----------+-------+----------+--------
 test_a   | meibo | テーブル | test_a
(1 行)

kengen=>

はい、できました~
テーブルの所有者については、CREATEを行ったtest_aユーザー(自身)となっています。

参照の動作について、後ほど検証を行いますが、ざっと適当にデータ挿入、参照してみます。
引き続き、test_aユーザー(のみ)です。

kengen=> insert into test_a.meibo values(1,'test_a write');
ERROR:  permission denied for schema test_a
行 1: insert into test_a.meibo values(1,'test_a write');
                  ^
kengen=>

また怒られた~
 先ほどと同じ概念で、今度はUSAGE権限が無いということです。
USAGEは、その名の通り、"使う"ことができません。CREATEだけ付与されている状況は、業務ではほぼ無いかもしれません。

 対応も先ほどと同じ。test_xユーザーより権限付与いただきましょう。

kengen=> \c - test_x
データベース "kengen" にユーザ"test_x"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_x
(1 行)

kengen=>
kengen=> grant usage on schema test_a to test_a;
GRANT
kengen=>
kengen=> \dn+
                           スキーマ一覧
  名前  |  所有者  |      アクセス権      |          説明
--------+----------+----------------------+------------------------
 public | postgres | postgres=UC/postgres+| standard public schema
        |          | =UC/postgres         |
 test_a | test_x   | test_x=UC/test_x    +|
        |          | test_a=UC/test_x     |
 test_b | test_b   |                      |
(3 行)

kengen=>

これで、アクセス権に、UとCが入りました!
それでは、再チャレンジします。

kengen=> \c - test_a
データベース "kengen" にユーザ"test_a"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_a
(1 行)

kengen=>
kengen=> insert into test_a.meibo values(1,'test_a write');
INSERT 0 1
kengen=> select * from test_a.meibo;
 id |    namae
----+--------------
  1 | test_a write
(1 行)

kengen=>

使えるようになりました。OKですね。

同様にCREATEおよび簡単な挿入・参照動作を、test_bユーザーでも行います。
振り返りですが、今度はスキーマのオーナー(test_b)=ユーザー(test_b)であるということです。

kengen=> \c - test_b
データベース "kengen" にユーザ"test_b"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_b
(1 行)

kengen=>
kengen=> create table test_a.meibo(id integer,namae varchar(20));
ERROR:  permission denied for schema test_a
行 1: create table test_a.meibo(id integer,namae varchar(20));
                   ^
kengen=> create table test_b.meibo(id integer,namae varchar(20));
CREATE TABLE
kengen=>
kengen=> insert into test_b.meibo values(1,'test_b write');
INSERT 0 1
kengen=> select * from test_b.meibo;
 id |    namae
----+--------------
  1 | test_b write
(1 行)

kengen=>
kengen=> \dt test_*.*
          リレーションの一覧
 スキーマ | 名前  |    型    | 所有者
----------+-------+----------+--------
 test_a   | meibo | テーブル | test_a
 test_b   | meibo | テーブル | test_b
(2 行)

kengen=>

すぱっと決まりました。オーナーにつき、全権があります。
また、他スキーマであるtest_aユーザー分に関しては、期待どおり作成不可であります。

test_xユーザーでも、再度同様を試します。

kengen=> \c - test_x
データベース "kengen" にユーザ"test_x"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_x
(1 行)

kengen=>
kengen=> create table test_a.kiban(id integer,namae varchar(20));
CREATE TABLE
kengen=> create table test_b.kiban(id integer,namae varchar(20));
ERROR:  permission denied for schema test_b
行 1: create table test_b.kiban(id integer,namae varchar(20));
                   ^
kengen=>
kengen=> insert into test_a.kiban values(1,'test_x write');
INSERT 0 1
kengen=> select * from test_a.kiban;
 id |    namae
----+--------------
  1 | test_x write
(1 行)

kengen=>
kengen=> \dt test_*.*
          リレーションの一覧
 スキーマ | 名前  |    型    | 所有者
----------+-------+----------+--------
 test_a   | kiban | テーブル | test_x
 test_a   | meibo | テーブル | test_a
 test_b   | meibo | テーブル | test_b
(3 行)

kengen=>

test_bユーザーのときと同じ、オーナーであれば・・・の結果です。
test_aのスキーマに関しては、スキーマのオーナーにあたりますので、CREATE・USAGEは既に許可されており、スパッと作業完了となります。

 CREATEについて、検証終了です。
 結果としては、スキーマを作成したユーザー(オーナー)によるCREATE権限の付与に依存しています(test_bユーザー分については、スーパーユーザーを用いて強引に操作しましたので、現実味はありません)。

 軽いテストがてら実施した参照動作・・・USAGEについても、自作のテーブルについてのみ先に見てしまいましたが、USAGEに関しても、CREATEと同じでした。
 ただ、USAGE(対スキーマ)=参照(SELECT 対オブジェクト)ではありませんが、似たところもあり
自作外の全テーブルに対する全ユーザーの参照の振る舞いを、次に確認したいと思います。

④テーブルのSELECT

一旦、現状で、ざっと参照をかけてみます。

test_aユーザーにて

kengen=> \c - test_a
データベース "kengen" にユーザ"test_a"として接続しました。
kengen=> select * from test_a.meibo;
 id |    namae
----+--------------
  1 | test_a write
(1 行)

kengen=> select * from test_a.kiban;
ERROR:  permission denied for relation kiban
kengen=> select * from test_b.meibo;
ERROR:  permission denied for schema test_b
行 1: select * from test_b.meibo;
                    ^
kengen=>

test_bユーザーにて

kengen=> \c - test_b
データベース "kengen" にユーザ"test_b"として接続しました。
kengen=> select * from test_a.meibo;
ERROR:  permission denied for schema test_a
行 1: select * from test_a.meibo;
                    ^
kengen=> select * from test_a.kiban;
ERROR:  permission denied for schema test_a
行 1: select * from test_a.kiban;
                    ^
kengen=> select * from test_b.meibo;
 id |    namae
----+--------------
  1 | test_b write
(1 行)

kengen=>

test_xユーザーにて

kengen=> \c - test_x
データベース "kengen" にユーザ"test_x"として接続しました。
kengen=> select * from test_a.meibo;
ERROR:  permission denied for relation meibo
kengen=> select * from test_a.kiban;
 id |    namae
----+--------------
  1 | test_x write
(1 行)

kengen=> select * from test_b.meibo;
ERROR:  permission denied for schema test_b
行 1: select * from test_b.meibo;
                    ^
kengen=>

各々自作のテーブルしか参照できない・・・ばっちりではないでしょうか。
基本的には、自作のテーブルに対してオーナーは自身であり、これに対する権限としては、オーナーが行使できる分のみ、という状態です。

⑤テーブルの共有

 さて、それでは逆に共有は可能なのかということで、権限の付与が可能か試したいと思います。
とあるテーブルに対し、他ユーザーにも公開し、情報共有したい~ の場合です。
また一方、誰が権限付与可能なのかを確認しなければ、前述の参照是非の確認のみでは検証不十分でしょう。権限付与によって、結果的に参照可能となってしまっては同じです。

 まず気になりますのが、test_xユーザーです。環境作成を担ったユーザーではありますが、保身のためにも、全てのデータが参照可能(権限付与によって、結果的に参照可能)で良いとは限らないはずです。
test_a、test_bユーザーのオブジェクトに対するgrantが可能なのか見てみます。

test_xユーザーにて

kengen=> \c - test_x
データベース "kengen" にユーザ"test_x"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_x
(1 行)

kengen=>
kengen=> grant select on test_a.meibo to test_b;
ERROR:  permission denied for relation meibo
kengen=> grant select on test_b.meibo to test_a;
ERROR:  permission denied for schema test_b
kengen=>

スキーマのオーナーであっても、オブジェクト権限の付与へは関与できない様子です。いいですね。
また、test_xユーザー自作のテーブル(test_a.kiban)に対しての操作は、自由あるいは自爆というものでしょう。割愛します。

続いて、test_aユーザーにて

kengen=> \c - test_a
データベース "kengen" にユーザ"test_a"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_a
(1 行)

kengen=>
kengen=> grant select on test_a.meibo to test_b;
GRANT
kengen=> grant select on test_b.meibo to test_a;
ERROR:  permission denied for schema test_b
kengen=>
kengen=> \z
                                アクセス権
 スキーマ | 名前  |    型    |      アクセス権       | 列の権限 | ポリシー
----------+-------+----------+-----------------------+----------+----------
 test_a   | kiban | テーブル |                       |          |
 test_a   | meibo | テーブル | test_a=arwdDxt/test_a+|          |
          |       |          | test_b=r/test_a       |          |
(2 行)

kengen=>

やはり、自作のものに限るようです。
test_bユーザーに対して、SELECT(r)が付与されました。

test_bユーザーでも、同様のことを行います。 結果は見えたも同然ですが。

kengen=> \c - test_b
データベース "kengen" にユーザ"test_b"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_b
(1 行)

kengen=>
kengen=> grant select on test_a.meibo to test_b;
ERROR:  permission denied for schema test_a
kengen=> grant select on test_b.meibo to test_a;
GRANT
kengen=>
kengen=> \z
                                アクセス権
 スキーマ | 名前  |    型    |      アクセス権       | 列の権限 | ポリシー
----------+-------+----------+-----------------------+----------+----------
 test_b   | meibo | テーブル | test_b=arwdDxt/test_b+|          |
          |       |          | test_a=r/test_b       |          |
(1 行)

kengen=>

権限の付与動作としては、思うとおりに出来た感がありますね。
・・・とは別に、実証確認しないと、なんだか恐ろしいので、、
再び、ざっと参照処理を通します。

test_aユーザーにて

kengen=> \c - test_a
データベース "kengen" にユーザ"test_a"として接続しました。
kengen=> select * from test_a.meibo;
 id |    namae
----+--------------
  1 | test_a write
(1 行)

kengen=> select * from test_a.kiban;
ERROR:  permission denied for relation kiban
kengen=> select * from test_b.meibo;
ERROR:  permission denied for schema test_b
行 1: select * from test_b.meibo;
                    ^
kengen=>

test_bユーザーにて

kengen=> \c - test_b
データベース "kengen" にユーザ"test_b"として接続しました。
kengen=> select * from test_a.meibo;
ERROR:  permission denied for schema test_a
行 1: select * from test_a.meibo;
                    ^
kengen=> select * from test_a.kiban;
ERROR:  permission denied for schema test_a
行 1: select * from test_a.kiban;
                    ^
kengen=> select * from test_b.meibo;
 id |    namae
----+--------------
  1 | test_b write
(1 行)

kengen=>

test_xユーザーにて

kengen=> \c - test_x
データベース "kengen" にユーザ"test_x"として接続しました。
kengen=> select * from test_a.meibo;
ERROR:  permission denied for relation meibo
kengen=> select * from test_a.kiban;
 id |    namae
----+--------------
  1 | test_x write
(1 行)

kengen=> select * from test_b.meibo;
ERROR:  permission denied for schema test_b
行 1: select * from test_b.meibo;
                    ^
kengen=>

 さっきと変わってな~い!! 自作のものしか見れませんね。
test_a、test_bユーザー間のみでの、テーブル見せ合いっこが出来ませんでした。

何か忘れているような・・・
スキーマに対するUSAGEを忘れていますね。他スキーマへの参照ですので、基本はUSAGE無し、かつ、スキーマオーナーであるはずも無いでしょう。付与が必要です。

 付与します。
(先ほどは、test_aスキーマに対するUSAGE権限をtest_aユーザーに付与。これをtest_xユーザーにて行いました)

test_aユーザーにて付与を試みます。

kengen=> \c - test_a
データベース "kengen" にユーザ"test_a"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_a
(1 行)

kengen=>
kengen=> grant usage on schema test_a to test_b;
WARNING:  no privileges were granted for "test_a"
GRANT
kengen=> grant usage on schema test_b to test_a;
ERROR:  permission denied for schema test_b
kengen=>
kengen=> \dn+
                           スキーマ一覧
  名前  |  所有者  |      アクセス権      |          説明
--------+----------+----------------------+------------------------
 public | postgres | postgres=UC/postgres+| standard public schema
        |          | =UC/postgres         |
 test_a | test_x   | test_x=UC/test_x    +|
        |          | test_a=UC/test_x     |
 test_b | test_b   |                      |
(3 行)

kengen=>

はい、test_aユーザーでは、そもそもスキーマのオーナーではありませんので付与できません。
まして、test_bスキーマ分など、出来るはずもなく期待値どおりです。

test_bユーザーにて

kengen=> \c - test_b
データベース "kengen" にユーザ"test_b"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_b
(1 行)

kengen=>
kengen=> grant usage on schema test_a to test_b;
ERROR:  permission denied for schema test_a
kengen=> grant usage on schema test_b to test_a;
GRANT
kengen=>
kengen=> \dn+
                           スキーマ一覧
  名前  |  所有者  |      アクセス権      |          説明
--------+----------+----------------------+------------------------
 public | postgres | postgres=UC/postgres+| standard public schema
        |          | =UC/postgres         |
 test_a | test_x   | test_x=UC/test_x    +|
        |          | test_a=UC/test_x     |
 test_b | test_b   | test_b=UC/test_b    +|
        |          | test_a=U/test_b      |
(3 行)

kengen=>

test_bユーザーに関しては、オーナーですので、付与可能です。
まあ、スーパーユーザーで強引にオーナーとしましたので、現実には起こりえない筋ですが。

test_xユーザーにて

kengen=> \c - test_x
データベース "kengen" にユーザ"test_x"として接続しました。
kengen=> select current_database(), current_user;
 current_database | current_user
------------------+--------------
 kengen           | test_x
(1 行)

kengen=>
kengen=> grant usage on schema test_a to test_b;
GRANT
kengen=> grant usage on schema test_b to test_a;
ERROR:  permission denied for schema test_b
kengen=>
kengen=> \dn+
                           スキーマ一覧
  名前  |  所有者  |      アクセス権      |          説明
--------+----------+----------------------+------------------------
 public | postgres | postgres=UC/postgres+| standard public schema
        |          | =UC/postgres         |
 test_a | test_x   | test_x=UC/test_x    +|
        |          | test_a=UC/test_x    +|
        |          | test_b=U/test_x      |
 test_b | test_b   | test_b=UC/test_b    +|
        |          | test_a=U/test_b      |
(3 行)

kengen=>

先ほど同様、オーナー分に関しては、付与可能です。

これで最後です。参照の実証確認をします。

test_aユーザーにて

kengen=> \c - test_a
データベース "kengen" にユーザ"test_a"として接続しました。
kengen=> select * from test_a.meibo;
 id |    namae
----+--------------
  1 | test_a write
(1 行)

kengen=> select * from test_a.kiban;
ERROR:  permission denied for relation kiban
kengen=> select * from test_b.meibo;
 id |    namae
----+--------------
  1 | test_b write
(1 行)

kengen=>

test_bユーザーにて

kengen=> \c - test_b
データベース "kengen" にユーザ"test_b"として接続しました。
kengen=> select * from test_a.meibo;
 id |    namae
----+--------------
  1 | test_a write
(1 行)

kengen=> select * from test_a.kiban;
ERROR:  permission denied for relation kiban
kengen=> select * from test_b.meibo;
 id |    namae
----+--------------
  1 | test_b write
(1 行)

kengen=>

test_xユーザーにて

kengen=> \c - test_x
データベース "kengen" にユーザ"test_x"として接続しました。
kengen=> select * from test_a.meibo;
ERROR:  permission denied for relation meibo
kengen=> select * from test_a.kiban;
 id |    namae
----+--------------
  1 | test_x write
(1 行)

kengen=> select * from test_b.meibo;
ERROR:  permission denied for schema test_b
行 1: select * from test_b.meibo;
                    ^
kengen=>

 はい。
 はずはじめに、test_aユーザーがtest_bユーザーのテーブルを、test_bユーザーがtest_aユーザーのテーブルを参照可能となりました。期待値通りです。
 次に、test_xユーザーについて、変わりなく、自作のテーブルのみ参照可能でした。こちらも期待値通りですね。

 テーブルオーナーによるSELECT権限の付与、および、スキーマオーナーによるUSAGE権限の付与が双方揃わなければ、他ユーザーに対するオブジェクト公開が不可能とのことで、それがスキーマのオーナーであっても、ユーザーの作成者であっても、テーブルのオーナーであっても、単独にて破られることは無いということです。



例えば、業務の担当割として
ここまでを、基盤・DBA担当が、ここからは、業務・アプリ担当が、などと役割の境界が
発生することがあるかと思います。

本題を振り返って、test_xユーザーを基盤・DBA担当、test_aユーザーを業務・アプリ担当、と重ねたとき
両担当からの設定を以て権限の是非をコントロールできるということになります。

権限管理を、業務・アプリ側に概ね任せつつも、スキーマ単位では基盤・DBAが介入して
共有を全く不可能にすることもできます。
また、基盤・DBA自らの権限のみで、業務データの参照が可能とならないため、保身にもなります。


 第3回を終了させていただきます。 権限等セキュリティ面が絡みますと、やはり気を抜くわけにはいきませんね。十分な検討とテストが必要です。 特に、public/PUBLICの概念はPostgreSQL独特のものでしたが、私見で恐縮ですが、便利の裏返しでややこしさが目立った感があります。ロール(ユーザー)に関しても、グループ/ユーザーの概念が同居ということで、慣れが必要なようです。

 今回までで、データベースクラスタからユーザー、テーブル等オブジェクトまで、作る系がおよそイメージ出来るようになったかと思います。 あ、表領域の概念が気になる方がいらっしゃるかもしれませんね。セキュリティという単語が出てしまいますと、監査なども気になり出し、キリがなく。。。

 作り物として、データベースクラスタにはじまり、ユーザー・テーブルまで作成したところで、そろそろ、PostgreSQLが業務システムに登場し出したキッカケの1つとも言える、レプリケーション機能の紹介・検証に迫りたいと思います。当機能の紹介を通じて、他の概念についても触れる機会が出来ますので、いつもどり? の寄り道続きとなりますが、各種拾いながら進んでいきたいと思います。

<第2回より抜粋、データベースの説明にて>

接続と申しましても、詳細は別途説明しなくてはなりませんが、 (中略) クライアント認証を通過したセッションが、さらにどのデータベースと関わるのかを 制御しているのは、実質、権限でしかありません。
折角、オブジェクトと権限(データベース内部といいますか)についてある程度の整理・検証まで行いましたので、対データベース・入口部分にも少し触れようと思います。

 おつかれさまでした。ありがとうございました。