web-dev-qa-db-ja.com

postgres:どうすればインデックスの作成を許可できますが、同じユーザーによるテーブルの変更やテーブルの削除はできませんか?

(ほとんど)読み取り専用のワークロードになるPostgresサーバーをセットアップしています。

私は自分でテーブルをドロップしたり、テーブルを変更したりせずに、自分や同僚が適切にインデックスを作成/ドロップできるようにしたいと思います。

付与/取り消しのドキュメントとロールのドキュメントのページを読むのに時間を費やしましたが、テーブル所有者のロールには両方の権限があるようです。

私が見つけたものの1つは、おそらくcreate create tablespace でインデックスを作成できることですが、機能しませんでした(他のテーブルスペースは作成していません)。

具体的には、私は試しました:

mydb=# grant create on tablespace pg_default to bob;
GRANT

...次にbobに切り替えました:

mydb=> create index on foo(a);
ERROR:  must be owner of relation foo

私もボブを所有者にしようとしましたが、ボブはテーブルを削除する権利を取得しました。その特権を取り消す方法はないようです。だから私は両方またはどちらにもこだわっています。

何か案は?

8
orm

SQLレベルではできません。これらのタスクはすべてテーブルの所有権によって管理されているためです。

テーブルスペースのCREATE必須ですが、テーブルにインデックスを作成してそのテーブルスペースにインデックスを格納するには十分ではありません。インデックスを配置するテーブルスペースにCREATE権限がない場合、そのインデックスを_CREATE INDEX_することはできません。ただし、その権利を持つだけでは十分ではありません。それ以外の場合、任意のテーブルスペースに何かを作成する権限があれば、誰でも任意のテーブルにインデックスを作成できますが、それは望ましくありません。インデックスはパフォーマンスコストがかかり、作成中に重いロックを取得します。おそらく最も重要なことに、式インデックスは悪意のある関数または演算子を介してテーブルに関するデータをリークする可能性があります。したがって、インデックスを作成するテーブルをまたはで所有している必要があります。

テーブルに対する個別のINDEX権限のサポートをPostgreSQLに追加できますが、追加されておらず、送信された場合に受け入れられない可能性があります。今のところ、あなたはテーブルを所有しなければならないことにこだわっています。

実行中の操作と現在のユーザーIDをチェックする_ProcessUtility_hook_をインストールし、必要に応じてそれらを拒否または許可するC拡張を作成できます。 _ProcessUtility_hook_の使用例は_contrib/sepgsql_で、外部ではBDRプロジェクトのソースコードの_bdr_commandfilter.c_ファイルで確認できます。拡張機能をコンパイルしてファイルシステムにインストールし、それを_shared_preload_libraries_に追加してインストールする必要があるため、サーバーへの完全なファイルシステムレベルのアクセス権、通常はルートアクセス権が必要です。

より実用的なアプローチは、_SECURITY DEFINER_関数をラッパーとして使用することです。テーブルの所有者として実行し、インデックス化するテーブル、インデックス化する列などを引数として受け入れるPL/PgSQL関数を記述します。format(...)を使用して_CREATE INDEX_式を作成します。 EXECUTEに渡します。実行notを使用すると、ユーザーは任意のSQL式を引数として渡すことができます。または、基本的に、SQLインジェクションを介してフルアクセスを許可します。複数の列が必要ですか? _colname text[]_を引数として受け入れ、_quote_ident_をそれぞれ受け入れる必要があります。等々。この方法の詳細については、「動的SQL plpgsql」を検索してください。

7
Craig Ringer

Plpgsql event triggers は現在のバージョンではかなり制限されていますが、DROP TABLEのみを許可しないという特定の結果を得ることができます。

このことを考慮:

CREATE OR REPLACE FUNCTION no_drop() RETURNS event_trigger AS $$
BEGIN
    IF (tg_tag = 'DROP TABLE') THEN
      RAISE exception 'DROP TABLE is not allowed';
    END IF;
END;
$$ LANGUAGE plpgsql;

CREATE EVENT TRIGGER nodrop_trigger ON sql_drop
   EXECUTE PROCEDURE no_drop();

ユーザーpostgres(スーパーユーザー)として:

 test =#create table foo(bar int); 
 CREATE TABLE 
 test =#drop table foo; 
エラー:DROP TABLEは許可されていません

一方、CREATE INDEXは機能します。

 test =#foo(bar);にインデックスidxを作成; 
インデックスを作成
3
Daniel Vérité