PostgreSQL 権限に関するこのシリーズの最初の 2 つの記事では、次のことを確認しました。役割の作成方法、データベース オブジェクトに対する権限を付与する方法、およびその方法オブジェクトの所有権これは、データベース内のアクセスと制御を管理する上で重要な側面です。
どのロールが既存のオブジェクトにアクセスまたは変更できるかを管理する場合、所有権は究極の権限です。 PostgreSQL の権限は最小特権の原則に基づいて機能するため、オブジェクト (テーブル、トリガー、関数、プロシージャなど) の所有者は次のことを行う必要があります。許す
他の役割に対する特権。
これを手動で行う方法について説明しました。許す
ただし、オブジェクトが作成されるたびにコマンドを実行すると、管理に時間がかかり、詳細を見落としやすくなります。
代わりに、PostgreSQL は、データベース オブジェクトの作成時にオブジェクト所有者に代わって付与されるデフォルトの権限を設定するメソッドを提供します。デフォルトの権限を使用すると、ロールは事前にデータベースを準備して、一貫したアクセス権限が適用されるようにしながら、時間の経過とともに管理の負担を軽減できます。
しかし、適切なレベルの制御とアクセスを提供する一連のロールとデフォルト権限を作成するにはどうすればよいでしょうか?もう少し深く掘り下げてみましょう。
デフォルトの権限を使用した移行の管理
デフォルトの権限はロール (ユーザーまたはユーザーのグループを表すことができる) ごとに設定されることを思い出してください。つまり、各ロールは、特定の種類のオブジェクトが作成されるたびに、他のロールにどの権限を付与するかを指定する必要があります。以下のイメージ図では、内部に多数のオブジェクトがあり、それぞれが異なるロールによって所有されているデータベースを考えてみましょう。
多くのロールがオブジェクトの作成と所有を許可するデータベースでは、少なくとも 2 つの問題が発生します。
まず、多くの役割には作成
各スキーマの権限。以前の記事で説明したように、オブジェクト作成者はデフォルトで所有者でもあり、オブジェクトに対してスーパーユーザーのような権限を持ちます。ただし、それ以上に、スキーマ内にオブジェクトを作成する権限があると、潜在的なセキュリティ問題が発生します。作成
PostgreSQL 15 では、権限が public ロールから削除されました。
第 2 に、多くの異なるロールがスキーマ内にオブジェクトを作成する正当な理由がある場合でも、他のロールが必要なアクセス権を確実に持つことができるように、それぞれのロールがデフォルトの権限のセットを作成して維持する必要があります。現在、PostgreSQL でデフォルトの権限を簡単に視覚化するのは難しいため、管理するのは大変です。
代わりに、すべてのデータベース オブジェクトを所有する 1 つのグループ ロールを示す、この 2 番目の図を検討してください。このシナリオでは、グループ ロールはログインできないため、ある程度のセキュリティが提供されます。デフォルトの権限セットは 1 つだけデータベース オブジェクトとデータへのアクセスを効果的かつ効率的に管理するには、時間をかけて維持する必要があります。
PostgreSQL データベース内でこの種のセキュリティを設定する方法を見てみましょう。
高レベルのグループ役割の作成
PostgreSQL では、最初の記事で説明したように、ロールに他のロールのメンバーシップを付与し、その権限を継承することができます。したがって、データベース内のさまざまなロールにどのような種類の権限を付与する必要があるか、またそれらをより上位のロールのセットに抽象化する方法を考えることが課題となります。
ロールはインスタンス レベルで作成されることに注意してください。したがって、「」を作成すると、読み取り専用'
ロールを使用すると、読み取り専用アクセスの管理に使用できます ('選択する'
) 各データベースにあります。 DML アクセスからのさまざまな種類の権限でも同じことができます (‘入れる'
、「消去'
、「アップデート'
) DDL 操作に至るまで (‘作成'
)。
サンプル「テンプレート」は、すべてのデータベース インスタンスにこれら 3 つのグループ ロールを作成することから始めることができます。ニーズはさらに複雑になる可能性があるため、必要に応じて追加および調整してください。
- 次のスクリプトは、このスタックオーバーフローの回答テンプレートとして使用します。私は昨年この本を偶然見つけて、PostgreSQL データベース権限を設定するための簡単なプロセスの概要をうまく説明していると思いました。 (最高のデータベース DevOps ツールについても言及しているのは間違いありません! 😊)
PostgreSQL インスタンス グループのロール
次の 2 つのスクリプトを実行する必要があります一度各データベース インスタンスで適切なロールを作成し、各データベース内で権限を付与します。
1 2 3 4 5 6 7 8 9 10 11 | /* * このスクリプトは PostgreSQL インスタンスごとに 1 回実行する必要があります * すべてのデータベースで使用できる、または使用できるグループ ロールを作成します。 * ddl/dml/read_only アクセスの場合 * * 状況によっては、さらにグループの役割を作成する必要がある場合があります。 * 権限の粒度が向上します。 */ 作成 役割 ddl_grp と NOLOGIN; 作成 役割 dml_grp と NOLOGIN; 作成 役割 読み取り専用グループ と NOLOGIN; |
これらの役割を作成しても、まだ実質的な成果は何もありません。代わりに、これらのロールは、データベースとスキーマ オブジェクトを作成するときに他の権限を管理するメカニズムになります。これらのロールではデータベースに直接接続できませんが、(「ログインなし」
)、これらのロールは引き続きオブジェクトを所有し、デフォルトの権限を作成できます。
次に、必要に応じて、これらのグループ ロールのメンバーシップを他のロールに付与できます。以下の例では、3 種類のユーザー ロールがあります。
- オブジェクト管理者: これらの役割は、データベース内にオブジェクトを作成することを許可されます。オブジェクトの作成は DDL アクションであるため、ロールに名前を付けました
「ddl_grp」
- データ管理者: これらのロールは、DML ステートメントを使用してデータと関連オブジェクトを変更することが許可されているため、ロールに「」という名前を付けました。
dml_grp'
- 読み取り専用: これらのロールは、特定のスキーマまたはテーブルからデータを選択することができます。私たちはその役割に「
読み取り専用_grp'
ユーザー役割の例 (例:「dev_admin1」
、「フライウェイ」
、「開発1'
、「レポート_ユーザー'
、など) は、グループ ロールのメンバーシップを付与する前に存在している必要があります。重要なのは、「メンバーシップが付与されたロールはすべて、ddl_grp'
ロールは、データベース内のオブジェクトを作成または変更するスクリプトを「ddl_grp'
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* * ここで、必要に応じて各ロールへのアクセスを許可します。 * 職務権限。繰り返しますが、これらは入手方法の単なるアイデアです *始めました。より多くの「グループ」役割が必要になる可能性があります * * これらは、アクセス権が付与される役割の例です。良い * 「ddl_grp」に含める必要があるロールの例は、 * Flyway などの DevOps ツールが実行するために使用されるロール * 移行スクリプト。これにより、すべてのオブジェクトが確実に所有されるようになります。 * そのグループによって、すべてのユーザーがアクセス権を取得します。 */ 許す ddl_grp に dev_admin1、 フライウェイ; 許す dml_grp に 開発1、 開発2; 許す 読み取り専用グループ に レポート_usr1、 レポート_usr2; |
すべてのロールが配置され、メンバーシップが更新されたので、特権が本当に重要な個々のデータベースに目を向けることができます。
個々のデータベース権限
データベース ロールを作成したので、個々のデータベース権限に注目することができます。この場合、選択肢は 2 つあります。
クラスター内に新しいデータベースが作成されるたびに、このスクリプトを実行できます。または、スーパーユーザーの役割を使用して、テンプレート データベース (通常は「テンプレート1'
) PostgreSQL インスタンス上で。テンプレート データベースに適用される設定は、そのテンプレートから作成される新しいデータベースごとにこれらの権限を自動的に設定します。
以下のスクリプトは 1 つのスクリプトとして適用できますが、各セクションの目的とデータベースへの適用方法を説明するために分割しました。
PUBLIC からすべての権限を取り消します
新しいデータベースに対して最初に行うべきことは、デフォルトでデータベースに付与されているすべての権限を取り消すことです。公共
役割。最初の記事で、これが推奨される理由について説明しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* * 各データベースで、このスクリプトをスーパーユーザーとして実行するか、 * CREATEROLE およびその他の GRANT 権限を持つユーザー。 * Amazon RDS のような DBaaS サービスでは、これはユーザーである可能性があります * 管理のためにあなたに割り当てられました */ -- PostgreSQL のすべての最新バージョンが対象。この意志 -- 具体的に指定されるまでデータベースへの接続を禁止します。 -- CONNECT で付与 取り消す 全て の上 データベース 私のデータベース から 公共; -- 誰もが公共の場でオブジェクトを作成できないようにします -- 権限が付与されるまでスキーマ。 PG15+ のデフォルト 取り消す 作成 の上 スキーマ 公共 から 公共; |
ここで 1 つのニュアンスに注目してください。 「」を削除しています全て'
からの特権'公共'
データベースのスキーマ レベルではなく、データベース レベルで。スキーマからすべての権限も削除した場合、追加の権限をリセットしない限り、通常の PostgreSQL コマンドは多くのユーザーに対して機能しなくなります。
取り消し中'全て'
以下に示すように、データベース レベルでは、他の場所で適用される特定の許可なしにユーザーがデータベースに接続できないようにします。
基本的な権限を付与する
すべてのロールには、データベースに接続し、(通常は) 一時テーブルにアクセスする機能が必要です。ただし、次のような追加の権限がなければ、使用法
と選択する
、これらの役割は実際にはできませんするデータベースにはまだ何もありません。
通常、すべてのロールはこれらの権限を公共
ロールですが、各データベースとパブリック スキーマにアクセスするロールをより詳細に制御できるようにするために、上記の権限を取り消しただけです。
1 2 3 | -- すべてのロールへの接続とアクセスを許可します。 許す 接続、 一時的 の上 データベース mysuperdb に ddl_grp、 dml_grp、 読み取り専用グループ; |
各グループの役割に使用法およびその他の権限を付与します。
ここからは良い点に移ります。データベースごとに、どのロールがデータベース オブジェクトを使用できるかを決定できます。('使用法'
) とスキーマごとにできること。以下に示すように、この例では、パブリック スキーマに対する権限を付与する方法のみを示します。アプリケーションに他のスキーマがある場合 (おそらく存在します!)、各スキーマに適切なアクセス許可を付与する必要があります。
まず、私たちの「ddl_grp」
(およびすべてのメンバー) は、スキーマおよび任意のシーケンス内のオブジェクトを使用および作成できます。などの既存のオブジェクトがある場合テーブル
、順序
、タイプ
、ドメイン
などを実行する必要があります。許す
デフォルトの権限は新しく作成されたオブジェクトにのみ影響するため、毎回ステートメントを使用して既存の権限を適切に設定します。以下の例では、既存のシーケンスとテーブルに権限を付与する方法を示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* * 以下では、「myapp」というアプリケーション スキーマでの使用を許可します。 * アプリケーションに異なるスキーマがある場合は、次のことが必要になります。 * これを適切に更新します。 * * 複数のスキーマ名はカンマで区切ることができます */ -- これにより、グループ内の誰でも使用および作成できるようになります。 -- スキーマ内の新しいオブジェクト。このグループが所有するため -- オブジェクトは後で変更できます。 許す 使用法、 作成 の上 スキーマ マイアプリ に ddl_grp; -- 既存のテーブルとシーケンスの権限を変更します。 許す 全て の上 全て テーブル の スキーマ マイアプリ に ddl_grp; 許す 全て の上 全て シーケンス の スキーマ マイアプリ に ddl_grp; |
次に、スキーマ内のオブジェクトの使用を許可されるグループ ロールに進み、データとシーケンス値を選択します。前と同様、データベースに複数のスキーマがある場合は、各スキーマのオブジェクト タイプごとにロールの使用を許可する必要があります。
1 2 3 4 5 6 7 8 9 10 11 | -- これにより、他のすべての「グループ」ロールが接続できるようになります。 -- myapp スキーマにアクセスし、オブジェクトがある場合はオブジェクトにアクセスします。 -- そうする権限が与えられています。 許す 使用法 の上 スキーマ マイアプリ に dml_grp、 読み取り専用グループ; -- 既存のテーブルとシーケンスの権限を変更します。 許す 選択する の上 全て テーブル の スキーマ マイアプリ に dml_grp、 読み取り専用グループ; 許す 使用法、 選択する の上 全て シーケンス の スキーマ マイアプリ に dml_grp、 読み取り専用グループ; |
最後に、スキーマ オブジェクトの作成に使用されるユーザーとして、データベース内の他のロールのデフォルト権限を設定します。次の例では 2 つの点に注目してください。
- テーブルとシーケンスに対してのみデフォルトの権限を設定します。オブジェクトの作成時にユーザーが必要とする他の権限を考慮し、スクリプトに追加する必要があります。
- の
「ddl_grp」
ロールにはデフォルトの権限が割り当てられておらず、そのメンバーであるロールにもデフォルトの権限が割り当てられていません。これは、グループがオブジェクトの所有者となり、他のメンバーの役割が自動的に所有権を継承するためです。それ以上は何も必要ありません。
通常、デフォルトの権限はステートメントを実行するロールに適用されます。したがって、スクリプトでは、将来オブジェクトを作成する所有者にロールを一時的に設定する必要があります。これには、このスクリプトを実行するロールが他のロールのメンバーである必要があります。
あるいは、長期的にはもう少し明確になりますが、デフォルトの権限を別のロールに設定することもできます。デフォルトの権限を変更する
現在のロールがそのメンバーである限り、ステートメントは使用されません。
以下の両方の例で、SQL を実行しているロールは、他のグループ ロールのメンバーである必要があります。 2 番目の形式はもう少し冗長で、どの権限が誰に適用されているかをステートメント レベルで追跡しやすくなります。
オプション 1: 権限を割り当てる前に SET ROLE を実行する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* * 最後に、移行スクリプトを実行するユーザーとして (そして * DDL グループのメンバーの場合は、デフォルトのアクセス権限を設定します。 */ 設定 役割 ddl_grp; 変更 デフォルト 特権 の スキーマ マイアプリ 許す 選択する、 入れる、 アップデート、 消去 の上 テーブル に dml_grp; 変更 デフォルト 特権 の スキーマ マイアプリ 許す 選択する の上 テーブル に 読み取り専用グループ; 変更 デフォルト 特権 の スキーマ マイアプリ 許す 使用法、 選択する の上 シーケンス に dml_grp、 読み取り専用グループ; 変更 デフォルト 特権 の スキーマ マイアプリ 許す アップデート の上 シーケンス に dml_grp; |
オプション 2: 別のロールに権限を割り当てる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /* * 最後に、グループ ロールのメンバーシップを持つユーザーとして、 * デフォルトのアクセス権限を設定する移行スクリプトを実行します。 */ 変更 デフォルト 特権 ために 役割 ddl_grp の スキーマ マイアプリ 許す 選択する、 入れる、 アップデート、 消去 の上 テーブル に dml_grp; 変更 デフォルト 特権 ために 役割 ddl_grp の スキーマ マイアプリ 許す 選択する の上 テーブル に 読み取り専用グループ; 変更 デフォルト 特権 ために 役割 ddl_grp の スキーマ マイアプリ 許す 使用法、 選択する の上 シーケンス に dml_grp、 読み取り専用グループ; 変更 デフォルト 特権 ために 役割 ddl_grp の スキーマ マイアプリ 許す アップデート の上 シーケンス に dml_grp; |
権限が正しく設定されていることを確認してください
最後のステップは、デフォルトの権限が設定されていて、そのジョブを実行する準備ができていることを確認することです。作業の結果を確認する最も簡単な方法は、「psql」の「\ddp」コマンドを使用することです。
これは、「ddl_grp」
role は、パブリック スキーマ内のすべてのテーブルとシーケンスに対するデフォルトの権限を設定します。
明らかに、実際のアプリケーションとロールの設定は、このサンプル テンプレートよりも複雑になる可能性があります。ただし、この原則は、管理する必要があるロールとオブジェクトの種類の数に関係なく適用されます。これを出発点として使用してください。
移行時に統合する
すべての準備が整ったので、運用データベース (たとえば) でこれを実際にどのように使用するかを見てみましょう。
移行パイプラインでは、上記の「フライウェイ」として示されているパイプライン ロールを使用するように移行スクリプトの接続文字列を設定します。理想的には、このロールのパスワードはボールトに保存され、パイプライン スクリプトの一部として取得され、通常のユーザーがこのロールとして認証できないようにする必要があります。
移行スクリプトの先頭では、まずロールを「ddl_grp」
ロールにより、作成 DDL によってオブジェクトがそのグループに所有されるようになります。とデフォルトの権限が起動し、正しく適用されます。簡単な例は次のようになります。
1 2 3 4 5 6 7 8 9 10 11 | /* * 最初にセッションロールを高レベルに設定します * 所有権グループの役割 */ 設定 役割 ddl_grp; -- オブジェクトを作成します 作成 テーブル テスト( 列1 文章 ヌル、 列2 整数 ヌル ); |
移行が適用されたら、権限が正しく適用されたことをすぐに確認できます。'\dp'
コマンドイン'\psql'
。
成功!この時点から、「ddl_grp」
はテーブルとシーケンス (またはデフォルトの権限を設定したその他のオブジェクト) の作成に使用され、他のロールには定義したアクセス権が与えられ、全体的な管理の負担が軽減されます。
結論
PostgreSQL の権限は、考えたり管理したりするのが複雑になる場合があります。ロールとロール間のメンバーシップに特権を付与する方法を理解すると、この負担をすぐに軽減できます。ただし、デフォルトの権限を効果的に設定する方法を学ぶことから、データベース管理の真の力が始まります。