ApsaraDB RDS for PostgreSQL は、データベース権限を管理するためにロールベースアクセス制御 (RBAC) モデルを使用します。このトピックでは、プロジェクトまたはチームレベルのアクセス管理に適した、所有者、読み書きロール、読み取り専用ロールという3層の権限モデルの設定について説明します。
仕組み
PostgreSQL では、ロールとユーザーは同じオブジェクトタイプです。その違いは機能にあります。
ロールは権限を保持しますが、ログインできません。
ユーザーは、
WITH LOGIN属性を持つロールです。その実効権限は、自身のログイン権限と、付与されたすべてのロールの権限の合計です。
ロールの権限を更新すると、そのロールに割り当てられたすべてのユーザーは自動的に変更を継承します。再付与は不要です。
すべての RDS インスタンスには、dbsuperuser という名前の特権アカウントが含まれています。このアカウントはインスタンスに対する完全な権限を持ち、データベース管理者のみを対象としています。
権限モデル
プロジェクトまたはチームに推奨される3層モデルでは、次のエンティティを使用します。
| エンティティ | タイプ | テーブルに対する権限 | ストアドプロシージャに対する権限 |
|---|---|---|---|
rdspg_owner | 所有者 (完全な DDL を持つユーザー) | DDL (CREATE、DROP、ALTER) + DQL (SELECT) + DML (UPDATE、INSERT、DELETE) | DDL (CREATE、DROP、ALTER) + DQL (SELECT) + ストアドプロシージャの呼び出し |
rdspg_role_readwrite | ロール | DQL (SELECT) + DML (UPDATE、INSERT、DELETE) | DQL (SELECT) + ストアドプロシージャの呼び出し。ストアドプロシージャ内の DDL 操作は権限エラーを返します。 |
rdspg_role_readonly | ロール | DQL (SELECT) のみ | DQL (SELECT) + ストアドプロシージャの呼び出し。ストアドプロシージャ内の DDL 操作は権限エラーを返します。 |
アプリケーションユーザーは、ロール割り当てを通じて権限を継承します。
rdspg_readwrite—rdspg_role_readwrite権限 + ログインを継承rdspg_readonly—rdspg_role_readonly権限 + ログインを継承
よりきめ細かい制御を行うには、要件に基づいて追加のロールを作成します。
テーブルをpublicスキーマに配置しないでください。デフォルトでは、すべてのユーザーがpublicスキーマに対する CREATE 権限と USAGE 権限を持っています。
前提条件
開始する前に、以下があることを確認してください。
ApsaraDB RDS for PostgreSQL インスタンス
dbsuperuser特権アカウントへのアクセスコマンドラインツールを介したインスタンスへの接続 (「ApsaraDB RDS for PostgreSQL インスタンスへの接続」をご参照ください)
プロジェクトの権限設定
次の例では、rdspg という名前のプロジェクトに、rdspg と rdspg_1 の2つのスキーマを持つ権限を設定します。すべてのコマンドを dbsuperuser として実行します。
ステップ 1: 所有者とロールの作成
-- Create the owner. Replace the password with a strong password.
CREATE USER rdspg_owner WITH LOGIN PASSWORD 'asdfy181BASDfadasdbfas';
-- Create the read-write and read-only roles (no login).
CREATE ROLE rdspg_role_readwrite;
CREATE ROLE rdspg_role_readonly;
-- Grant DQL + DML permissions on tables created by rdspg_owner to rdspg_role_readwrite.
ALTER DEFAULT PRIVILEGES FOR ROLE rdspg_owner GRANT ALL ON TABLES TO rdspg_role_readwrite;
-- Grant DQL + DML permissions on sequences created by rdspg_owner to rdspg_role_readwrite.
ALTER DEFAULT PRIVILEGES FOR ROLE rdspg_owner GRANT ALL ON SEQUENCES TO rdspg_role_readwrite;
-- Grant DQL-only permission on tables created by rdspg_owner to rdspg_role_readonly.
ALTER DEFAULT PRIVILEGES FOR ROLE rdspg_owner GRANT SELECT ON TABLES TO rdspg_role_readonly;ALTER DEFAULT PRIVILEGES は、rdspg_owner が将来作成するすべてのオブジェクトに適用されます。既存のオブジェクトには、個別の GRANT が必要です。
ステップ 2: アプリケーションユーザーの作成
-- Read-write user: inherits DQL + DML permissions from rdspg_role_readwrite.
CREATE USER rdspg_readwrite WITH LOGIN PASSWORD 'dfandfnapSDhf23hbEfabf';
GRANT rdspg_role_readwrite TO rdspg_readwrite;
-- Read-only user: inherits DQL-only permission from rdspg_role_readonly.
CREATE USER rdspg_readonly WITH LOGIN PASSWORD 'F89h912badSHfadsd01zlk';
GRANT rdspg_role_readonly TO rdspg_readonly;ステップ 3: スキーマの作成とアクセス権の付与
-- Set rdspg_owner as the owner of the rdspg schema.
CREATE SCHEMA rdspg AUTHORIZATION rdspg_owner;
-- Grant schema access to both roles.
GRANT USAGE ON SCHEMA rdspg TO rdspg_role_readwrite;
GRANT USAGE ON SCHEMA rdspg TO rdspg_role_readonly;rdspg_readwriteとrdspg_readonlyは、それぞれのロールを通じてスキーマアクセスを継承します。これらのユーザーへの直接の付与は不要です。
最小権限の原則の適用
アプリケーション接続のデフォルトユーザーとして rdspg_readonly を使用します。書き込み操作が必要な場合にのみ、rdspg_readwrite に切り替えます。このアプローチにより、プロキシミドルウェアのオーバーヘッドなしで、アプリケーション層での読み書き分離が可能になります。
読み取り専用 RDS インスタンスがご利用の RDS インスタンスにアタッチされていない場合は、一方のクライアントに読み取り権限を付与し、もう一方のクライアントに読み取りおよび書き込み権限を付与することを推奨します。Java Database Connectivity (JDBC) 接続を次のように設定します。
| クライアント | ユーザー | JDBC URL |
|---|---|---|
| 読み取り専用クライアント | rdspg_readonly | the endpoint of read-only RDS instance 1,the endpoint of read-only RDS instance 2,the endpoint of your RDS instance |
| 読み書きクライアント | rdspg_readwrite | the endpoint of your RDS instance |
権限モデルの拡張
スキーマの追加
同じプロジェクトに2番目のスキーマ (rdspg_1) を追加するには:
CREATE SCHEMA rdspg_1 AUTHORIZATION rdspg_owner;
-- Grant the access permission on the rdspg_2 schema to roles.
-- Grant the permissions to perform DDL CREATE, DROP, and ALTER operations on tables in the rdspg_1 schema.
GRANT USAGE ON SCHEMA rdspg_1 TO rdspg_role_readwrite;
GRANT USAGE ON SCHEMA rdspg_1 TO rdspg_role_readonly;これらのロールに割り当てられたすべてのユーザーは、新しいスキーマアクセスを自動的に継承します。
プロジェクト間のアクセス権の付与
employee_readwrite ( employee プロジェクトのユーザー) に rdspg プロジェクトへの読み取りアクセス権を付与するには:
-- Grant rdspg_role_readonly permissions to employee_readwrite.
GRANT rdspg_role_readonly TO employee_readwrite;権限の検証
\du の使用
インスタンスに接続し、\du を実行してロールとロールメンバーシップを一覧表示します。
postgres=> \du
List of roles
Role name | Attributes | Member of
------------------------+---------------+----------------------------------------------
rdspg_owner | ... | {}
rdspg_role_readwrite | Cannot login | {}
rdspg_role_readonly | Cannot login | {}
rdspg_readwrite | ... | {rdspg_role_readwrite}
rdspg_readonly | ... | {rdspg_role_readonly}
employee_readwrite | ... | {rdspg_role_readonly,employee_role_readwrite}employee_readwrite の [所属] 列には rdspg_role_readonly と employee_role_readwrite の両方が表示され、クロスプロジェクトの読み取りアクセスがアクティブであることを確認できます。

SQL の使用
すべてのロールおよびそれらのメンバーシップを対象とした完全な監査を行うには:
SELECT r.rolname, r.rolsuper, r.rolinherit,
r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,
r.rolconnlimit, r.rolvaliduntil,
ARRAY(SELECT b.rolname
FROM pg_catalog.pg_auth_members m
JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)
WHERE m.member = r.oid) as memberof
, r.rolreplication
, r.rolbypassrls
FROM pg_catalog.pg_roles r
WHERE r.rolname !~ '^pg_'
ORDER BY 1;権限の例
rdspg_owner による DDL 操作
rdspg_owner は、所有する任意のスキーマで完全な DDL 権限を保持します。
CREATE TABLE rdspg.test(id bigserial primary key, name text);
CREATE INDEX idx_test_name on rdspg.test(name);rdspg_readwrite による DML および DQL
rdspg_readwrite はデータの読み書きはできますが、スキーマを変更することはできません。
INSERT INTO rdspg.test (name) VALUES('name0'),('name1');
SELECT id,name FROM rdspg.test LIMIT 1;
-- DDL is blocked:
CREATE TABLE rdspg.test2(id int);
ERROR: permission denied for schema rdspg
DROP TABLE rdspg.test;
ERROR: must be owner of table test
ALTER TABLE rdspg.test ADD id2 int;
ERROR: must be owner of table test
CREATE INDEX idx_test_name on rdspg.test(name);
ERROR: must be owner of table testrdspg_readonly による DQL のみ
rdspg_readonly はデータをクエリできますが、変更することはできません。
INSERT INTO rdspg.test (name) VALUES('name0'),('name1');
ERROR: permission denied for table test
SELECT id,name FROM rdspg.test LIMIT 1;
id | name
----+-------
1 | name0
(1 row)