RDS PostgreSQL刪除賬號(hào)失敗
問(wèn)題描述
在RDS PostgreSQL控制臺(tái)刪除賬號(hào)時(shí),出現(xiàn)錯(cuò)誤提示。其中:
報(bào)錯(cuò)信息:數(shù)據(jù)庫(kù)對(duì)象依賴該操作的賬號(hào),請(qǐng)先解除依賴后,再操作。
錯(cuò)誤碼:
AccountActionForbidden
。
問(wèn)題原因
在RDS PostgreSQL中,如果存在數(shù)據(jù)庫(kù)對(duì)象依賴于即將被刪除的賬號(hào),將導(dǎo)致刪除操作失敗。例如,存在user_to_be_dropped
賬號(hào),并使用該賬號(hào)創(chuàng)建了對(duì)象。示例SQL如下:
使用高權(quán)限賬號(hào),創(chuàng)建測(cè)試數(shù)據(jù)庫(kù)
testdb01
。CREATE DATABASE testdb01;
使用高權(quán)限賬號(hào),登錄
testdb01
,創(chuàng)建測(cè)試賬號(hào)user_to_be_dropped
,并賦予測(cè)試賬號(hào)對(duì)應(yīng)的權(quán)限。CREATE USER user_to_be_dropped WITH PASSWORD 'your_password' CREATEROLE CREATEDB; GRANT ALL ON SCHEMA public TO user_to_be_dropped; GRANT ALL ON DATABASE testdb01 TO user_to_be_dropped;
使用賬號(hào)
user_to_be_dropped
登錄testdb01
,創(chuàng)建對(duì)象和測(cè)試數(shù)據(jù)庫(kù)testdb02
。CREATE SCHEMA test_nsp; CREATE TABLE test_nsp.test_tbl(a1 int); CREATE TABLE test_tbl(a2 int); CREATE DATABASE testdb02;
使用賬號(hào)
user_to_be_dropped
登錄testdb02
,創(chuàng)建對(duì)象和新測(cè)試賬號(hào)user_to_be_dropped_2
,并給其授予高權(quán)限賬號(hào)(本文以testdbuser為例)的權(quán)限。CREATE SCHEMA testnsp; CREATE TABLE testnsp.tbl(a3 int); CREATE USER user_to_be_dropped_2 WITH PASSWORD 'your_password'; GRANT user_to_be_dropped_2 TO testdbuser;
刪除賬號(hào)user_to_be_dropped
時(shí),由于存在依賴對(duì)象,所以刪除操作會(huì)出現(xiàn)報(bào)錯(cuò)。
RDS PostgreSQL控制臺(tái):
SQL命令:
DROP USER user_to_be_dropped; ERROR: role "user_to_be_dropped" cannot be dropped because some objects depend on it DETAIL: privileges for schema public privileges for database testdb01 owner of schema test_nsp owner of table test_nsp.test_tbl owner of table test_tbl owner of database testdb02 privileges for membership of role testdbuser in role user_to_be_dropped_2 2 objects in database testdb02
解決方案
查找依賴目標(biāo)賬號(hào)的對(duì)象,并將其刪除。
查找依賴對(duì)象
系統(tǒng)表pg_shdepend
中記錄了單個(gè)數(shù)據(jù)庫(kù)內(nèi)部的對(duì)象對(duì)全局對(duì)象的依賴,可以用于查詢哪些對(duì)象依賴了目標(biāo)賬號(hào)。例如,查詢哪些對(duì)象依賴賬號(hào) user_to_be_dropped
。
使用高權(quán)限賬號(hào)登錄數(shù)據(jù)庫(kù)實(shí)例,查詢與賬號(hào)
user_to_be_dropped
相關(guān)聯(lián)的對(duì)象。WITH role as (SELECT oid FROM pg_roles WHERE rolname = 'user_to_be_dropped') SELECT db.datname AS database, pg_class.relname AS classname, shp.objid AS oid, CASE WHEN shp.deptype = 'o' THEN 'Object Owner' WHEN shp.deptype = 'a' THEN 'In Access Control List' WHEN shp.deptype = 'r' THEN 'Policy Object' ELSE 'CANNOT HAPPEN' END FROM pg_shdepend shp LEFT JOIN pg_database db ON shp.dbid = db.oid JOIN pg_class ON shp.classid = pg_class.oid WHERE shp.refclassid = 1260 AND shp.refobjid IN (SELECT oid FROM role);
查詢結(jié)果為:
database | classname | oid | case ----------+-----------------+-------+------------------------ testdb01 | pg_namespace | 2200 | In Access Control List | pg_database | 16399 | In Access Control List testdb01 | pg_namespace | 16402 | Object Owner testdb01 | pg_class | 16403 | Object Owner testdb01 | pg_class | 16406 | Object Owner | pg_database | 16409 | Object Owner testdb02 | pg_namespace | 16410 | Object Owner testdb02 | pg_class | 16411 | Object Owner | pg_auth_members | 16416 | In Access Control List
其中各個(gè)字段的含義如下。
字段
含義
database
指明依賴對(duì)象所在的庫(kù),為空時(shí)表示全局對(duì)象的依賴。
classname
指明系統(tǒng)表名稱。
oid
指明依賴對(duì)象的oid。
case
指明依賴類型,常見(jiàn)的類型包括:
Owner:被刪除賬號(hào)是該對(duì)象的所有者。
ACL(Access Control List):被刪除賬號(hào)在Access Control List中。
使用高權(quán)限賬號(hào)登錄到對(duì)應(yīng)數(shù)據(jù)庫(kù)中,在對(duì)應(yīng)的系統(tǒng)表中查詢上一步獲得的
oid
所對(duì)應(yīng)的對(duì)象名稱,例如。全局對(duì)象的依賴
database
字段為空,表示全局對(duì)象的依賴。oid=16399
,testdb01
的ACL中有user_to_be_dropped
的相關(guān)條目。SELECT datname, datdba::regrole, datacl FROM pg_database WHERE oid = 16399; datname | datdba | datacl ----------+------------+------------------------------------------------------------------------------ testdb01 | testdbuser | {=Tc/testdbuser,testdbuser=CTc/testdbuser,user_to_be_dropped=CTc/testdbuser} (1 row)
oid=16409
,testdb02
的所有者為user_to_be_dropped
。SELECT datname, datdba::regrole, datacl FROM pg_database WHERE oid = 16409; datname | datdba | datacl ----------+--------------------+-------- testdb02 | user_to_be_dropped | (1 row)
oid=16416
,pg_auth_members
中的角色從屬關(guān)系,記錄了授予user_to_be_dropped
賬號(hào)的相應(yīng)權(quán)限。SELECT oid, roleid::regrole, member::regrole, grantor::regrole FROM pg_auth_members WHERE oid = 16416; oid | roleid | member | grantor -------+----------------------+------------+-------------------- 16416 | user_to_be_dropped_2 | testdbuser | user_to_be_dropped (1 row)
單庫(kù)內(nèi)對(duì)象的依賴
database
字段不為空,表示該庫(kù)下存在依賴對(duì)象。oid=2200
,testdb01
下public schema
的ACL中有user_to_be_dropped
的相關(guān)條目。SELECT nspname, nspowner::regrole, nspacl FROM pg_namespace WHERE oid = 2200; nspname | nspowner | nspacl ---------+------------+--------------------------------------------------------------------------- public | testdbuser | {testdbuser=UC/testdbuser,=U/testdbuser,user_to_be_dropped=UC/testdbuser} (1 row)
oid=16403
,testdb01
下的表test_nsp.test_tbl
的所有者為user_to_be_dropped
。SELECT relname, relnamespace::regnamespace, relowner::regrole, relacl FROM pg_class WHERE oid = 16403; relname | relnamespace | relowner | relacl ----------+--------------+--------------------+-------- test_tbl | test_nsp | user_to_be_dropped | (1 row)
處理依賴對(duì)象
您可以根據(jù)實(shí)際需求:
如果是ACL類型的依賴,可以收回對(duì)應(yīng)的權(quán)限。
如果是Owner類型的依賴,可以將其所有權(quán)轉(zhuǎn)移給其他賬號(hào),也可以刪除對(duì)應(yīng)的依賴。
例如:
ACL類型的依賴
oid=2200
,收回testdb01
下public schema
的權(quán)限。SELECT nspname, nspowner::regrole, nspacl FROM pg_namespace WHERE oid = 2200; nspname | nspowner | nspacl ---------+------------+--------------------------------------------------------------------------- public | testdbuser | {testdbuser=UC/testdbuser,=U/testdbuser,user_to_be_dropped=UC/testdbuser} (1 row) REVOKE ALL ON SCHEMA public FROM user_to_be_dropped;
oid=16399
,收回testdb01
的權(quán)限。SELECT datname, datdba::regrole, datacl FROM pg_database WHERE oid = 16399; datname | datdba | datacl ----------+------------+------------------------------------------------------------------------------ testdb01 | testdbuser | {=Tc/testdbuser,testdbuser=CTc/testdbuser,user_to_be_dropped=CTc/testdbuser} (1 row) REVOKE ALL ON DATABASE testdb01 from user_to_be_dropped;
oid=16416
,對(duì)于包含角色從屬關(guān)系的情況,RDS PostgreSQL 16 及以上版本中,需要切換到user_to_be_dropped
賬號(hào),刪除user_to_be_dropped_2
的高權(quán)限賬號(hào)(本文以testdbuser為例)的權(quán)限。\c testdb01 user_to_be_dropped; You are now connected to database "testdb01" as user "user_to_be_dropped". REVOKE user_to_be_dropped_2 FROM testdbuser cascade;
Owner類型依賴所有權(quán)轉(zhuǎn)移給其他賬號(hào)。
使用高權(quán)限賬單登錄到對(duì)應(yīng)數(shù)據(jù)庫(kù)。
將對(duì)象的所有權(quán)轉(zhuǎn)移給其他賬號(hào)。
oid=16403
,將testdb01
下的表test_nsp.test_tbl
的所有者權(quán)限轉(zhuǎn)移給其他賬號(hào)(本文以testdbuser為例)。SELECT relname, relnamespace::regnamespace, relowner::regrole, relacl FROM pg_class WHERE oid = 16403; relname | relnamespace | relowner | relacl ----------+--------------+--------------------+-------- test_tbl | test_nsp | user_to_be_dropped | (1 row) ALTER TABLE test_nsp.test_tbl OWNER TO testdbuser;
刪除依賴對(duì)象。
刪除測(cè)試數(shù)據(jù)庫(kù)testdb02。
DROP DATABASE testdb02;
刪除
oid=16402
的對(duì)象。SELECT nspname, nspowner::regrole, nspacl FROM pg_namespace WHERE oid = 16402; nspname | nspowner | nspacl ----------+--------------------+-------- test_nsp | user_to_be_dropped | (1 row) DROP SCHEMA test_nsp cascade;
刪除
oid=16406
的對(duì)象。SELECT relname, relnamespace::regnamespace, relowner::regrole, relacl FROM pg_class WHERE oid = 16406; relname | relnamespace | relowner | relacl ----------+--------------+--------------------+-------- test_tbl | public | user_to_be_dropped | (1 row) DROP TABLE public.test_tbl;
使用高權(quán)限賬號(hào)登錄數(shù)據(jù)庫(kù)實(shí)例,查詢與賬號(hào) user_to_be_dropped相關(guān)聯(lián)的對(duì)象。
返回結(jié)果:
database | classname | oid | case
----------+-----------+-----+------
(0 rows)
刪除目標(biāo)賬號(hào)
在RDS PostgreSQL控制臺(tái)或通過(guò)SQL命令刪除目標(biāo)賬號(hào)。SQL示例如下。
DROP USER user_to_be_dropped;