web-dev-qa-db-ja.com

PgSQL AWS RDSで権限を取り消したりユーザーを削除したりすることはできません

ユーザーasdをDBから削除します。だから、私は2つのDB:foobarを持っています。ユーザーは両方に依存関係があるようです。 DBはrootユーザーpostgresから作成されていますが、内部のallテーブルとシーケンスはユーザーfoo_migrationbar_migrationによってそれぞれ作成されています。

まず、postgresユーザーとしてfoo DBにログインします。ユーザーを削除しようとすると、次のようになります。

ERROR: role "asd" cannot be dropped because some objects depend on itには、複数のシーケンス、テーブル、bar DB、およびpostgres DB内のいくつかのオブジェクトからの特権に関する詳細が含まれています。

そこで、私は1つずつ(postgres DBにfooユーザーとしてログインしたまま)クリアを試みます。最初にREASSIGN OWNED BY asd TO foo_migration;を試します。これはERROR: permission deniedを返します。これは、postgresユーザーとしてログインしているため、奇妙です。とにかく、私はしてみます

REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM asd;
REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM asd;

そして、ユーザーが権限を持つすべてのシーケンスとテーブルのWARNING: no privileges could be revokedの束を取得します。また、DROP OWNED BY asd;で終わるERROR: permission deniedも試します。

これはすべて失敗したため、postgres DBにpostgresユーザーとしてログインし、同じ手順を実行します。 REVOKEコマンドは警告なしで正常に実行されますが、実際にアクセス許可が変更/影響を受けることはありません。 REASSIGNおよびDROP OWNED BYは、引き続きERROR: permission deniedになります。

エラーメッセージはむき出しです。一緒に提供されるヒントや詳細はありません。

asdユーザーのパスワードを持っていないので、それを使用してログインしたり、アクションを実行したりできません。

これにどのように取り組むかについてのアイデアはありますか?所有権を示すいくつかのテーブルを調べてそこから移動する必要がありますか? postgresユーザーは「全能」な管理者ユーザーではありませんか?

1
Milkncookiez

Postgres RDSで同様の問題が発生していました。 これ は、あるユーザーから別のユーザーにオブジェクトを再割り当てしてからユーザーを削除するために使用した回避策でした。あなたにとってそれは次のようになります:

-- logged in as the rds_superuser role you defined when you created your RDS instance
CREATE ROLE change_owner LOGIN;
GRANT asd TO change_owner;
GRANT foo_migration TO change_owner;

-- log out of current user and log in as `change_owner`
REASSIGN OWNED BY asd TO foo_migration;

-- log out of current user and log in as rds_superuser role
DROP USER asd;
1
rjh336

最初にREVOKING everythingをスクリプトを使用して解決しました。
私はそれをpython(sqlalchemy)で記述し、postgresqlを明示的に維持しました;別の言語に移行するのに十分明確であるはずです。

all_schemas = db_conn.execute(
    "SELECT schema_name FROM information_schema.schemata "
    "WHERE schema_name != 'information_schema' "
    "AND schema_name != 'pg_toast' "
    "AND schema_name != 'pg_catalog';"
).fetchall()
for schem in all_schemas:
    if any([s in schem[0] for s in ["pg_temp_", "pg_toast_temp_"]]):
        continue  # skip over these.  This is kinda what '\dn' does in psql.
    db_conn.execute(f"REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA {schem[0]} FROM {user}")
    db_conn.execute(f"REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA {schem[0]} FROM {user}")
    db_conn.execute(f"REVOKE ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA {schem[0]} FROM {user}")
    db_conn.execute(f"REVOKE USAGE ON SCHEMA {schem[0]} FROM {user}")

# this is response from \d
all_resources = db_conn.execute("""
SELECT n.nspname as "Schema",
  c.relname as "Name",
  CASE c.relkind 
  WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' 
  WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' WHEN 'f' THEN 'foreign table' 
  END as "Type",
  pg_catalog.pg_get_userbyid(c.relowner) as "Owner"
FROM pg_catalog.pg_class c
     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','v','m','S','f','')
      AND n.nspname <> 'pg_catalog'
      AND n.nspname <> 'information_schema'
      AND n.nspname !~ '^pg_toast'
  AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 1,2;
""").fetchall()
for resource in all_resources:
    resource_name = resource[1]
    db_conn.execute(f"REVOKE ALL ON {resource_name} FROM {user}")

all_databases = db_conn.execute(
    "SELECT datname FROM pg_database "
    "WHERE NOT datacl ~ 'rdsadmin=CTc/rdsadmin';"
).fetchall()
for db_tup in all_databases:
    db_conn.execute(f"REVOKE ALL PRIVILEGES ON DATABASE {db_tup[0]} FROM {user}")

# And finally (good god this shouldn't be this hard)
db_conn.execute(f"DROP USER IF EXISTS {user}")
0
Roman