ユーザーasd
をDBから削除します。だから、私は2つのDB:foo
とbar
を持っています。ユーザーは両方に依存関係があるようです。 DBはrootユーザーpostgres
から作成されていますが、内部のallテーブルとシーケンスはユーザーfoo_migration
とbar_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
ユーザーは「全能」な管理者ユーザーではありませんか?
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;
最初に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}")