web-dev-qa-db-ja.com

postgresは、テーブルとそれらのテーブルの列を選択できる制限付きユーザーを作成します

PostgreSQLデータベースの作成を自動化し、データベースユーザーの作成も自動化するアプリがあります。このデータベースユーザーは、クライアントに渡されて使用されるため、セキュリティ上の目的で制限付きアクセスが許可されます。 使用しているバージョンはPostgres 9.6です

CREATE USER %USERSETUP% WITH
    LOGIN PASSWORD '%USERSETUPPASS%'
    NOSUPERUSER
    NOCREATEDB
    NOCREATEROLE
    INHERIT
    NOREPLICATION
    CONNECTION LIMIT -1;

ALTER DEFAULT PRIVILEGES IN SCHEMA %SCHEMA% GRANT INSERT, SELECT, UPDATE, DELETE, REFERENCES ON TABLES TO %USERSETUP%;

さて、私のテストは作成されたデータベースにも行き、クエリスクリプトを使用してテーブル名を取得し、各テーブル内の列名を取得します(おまけとして、列のデータ型も取得

これらの権限のため、ユーザーはinformation_schemaを使用できません。また、SYSTEM CATALOGでクエリスクリプトのみをリクエストしています

テーブル名に使用するスクリプトは機能します。

SELECT tablename FROM pg_catalog.pg_tables where schemaname = '{schema}'

そして、これはテーブル名をリストとして返します:

ビジネス、場所、人、顧客など...

ただし、次の2つのスクリプトを実行して列名を取得すると、このユーザーがinformation_schemaを照会しようとしているかのように、0が返されます。私はそれが特権のためだと思います:

SELECT c.oid,
  n.nspname,
  c.relname
FROM pg_catalog.pg_class c
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname ~ 'schemaaryzdhyqoi'
  AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 2, 3;

また

SELECT c.oid,
  n.nspname,
  c.relname, t.*
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
CROSS JOIN LATERAL (
  SELECT a.attname,
    pg_catalog.format_type(a.atttypid, a.atttypmod),
    (
      SELECT substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid) for 128)
      FROM pg_catalog.pg_attrdef d
      WHERE d.adrelid = a.attrelid
        AND d.adnum = a.attnum
        AND a.atthasdef
    ),
    a.attnotnull, a.attnum,
    (
      SELECT c.collname
      FROM
        pg_catalog.pg_collation c,
        pg_catalog.pg_type t
      WHERE c.oid = a.attcollation
        AND t.oid = a.atttypid
        AND a.attcollation <> t.typcollation
    ) AS attcollation
  FROM pg_catalog.pg_attribute a
  WHERE a.attrelid = c.oid
    AND a.attnum > 0
    AND NOT a.attisdropped
) AS t
WHERE n.nspname ~ '^(schemaaryzdhyqoi)$'  -- YOUR SCHEMA HERE
AND pg_catalog.pg_table_is_visible(c.oid);

質問は次のとおりです:スキーマ内の各テーブル内の列の名前(およびおそらくデータ型)だけにアクセスできるように、制限付きユーザーにアクセス許可を追加するにはどうすればよいですか

2
as.beaulieu

列レベルの権限を非常に具体的(かつ狭義)に設定して、権限のないユーザーがデータにアクセスできるようにすることができます。あなたの場合、それは2つのカタログです:pg_attributeおよびpg_type

aliceというユーザーがいます。このユーザーは、あなたのユーザーと同様に制限されています。

alice@test=> > SELECT * FROM pg_class LIMIT 1;
ERROR:  permission denied for relation pg_class

次のGRANTステートメントを発行します。

GRANT SELECT (oid, typname) ON pg_type TO alice;
GRANT SELECT (attrelid, attname, atttypid, attnum) ON TABLE pg_attribute TO alice;

これらの後、aliceは以下を実行できます。例えば:

SELECT attname, typname 
  FROM pg_attribute JOIN pg_type t ON t.oid = atttypid
 WHERE attrelid = 't2'::regclass AND attnum > 0;

 attname │ typname 
─────────┼─────────
 key     │ jsonb
 value   │ jsonb

必要に応じて特権を簡単に拡張できます。

2
dezso