本文介紹如何對RDS PostgreSQL實例中的賬號權限進行精細化管理。
配置原則
創建角色(Role)作為權限集合,對權限管理的細分操作集中在Role上。Role沒有登錄權限。在Role的基礎上創建user賬號來作為登錄賬號使用。使用user = role + login權限
的賬號權限管理模型,當Role的權限變化時,user賬號權限會自動跟隨Role變化。
權限管理設計模型
該模型簡單有效,推薦絕大多數客戶使用。
1個RDS PostgreSQL高權限賬號,具有所有權限,由少量資深DBA掌握。
項目或者團隊維度,1個資源owner賬號,2個基本Role:{project}_role_readwrite、{project}_role_readonly。
說明如果有更多細分需求,可以根據需要新建Role。
在Role的基礎上創建業務賬號:
業務賬號user = role + login權限
。1個項目或團隊可以有多個Schema。權限分配盡量以Schema或Role為單位。
業務表請勿放到
schema public
中。因為PostgreSQL默認所有用戶對schema public
都有CREATE和USAGE權限。
權限規劃示例
本示例以項目維度進行權限管理示例,同樣也適用于團隊維度。
DBA擁有RDS PostgreSQL實例的高權限賬號,名稱是dbsuperuser。
業務項目名稱是rdspg,新建schema名稱是rdspg、rdspg_1。
項目中新增的資源owner賬號和Role規劃如下:
user/Role | schema中表權限 | schema中存儲過程權限 |
rdspg_owner (user),是唯一的項目資源owner賬號 |
|
|
rdspg_role_readwrite (role) |
| DQL(SELECT,調用存儲過程) ,若存儲過程有DDL操作,會拋出權限相關錯誤。 |
rdspg_role_readonly (role) | DQL(SELECT) | DQL(SELECT,調用存儲過程),若存儲過程有DDL或者DML操作,會拋出權限相關錯誤。 |
新增業務賬號時,根據不同需求,采用如下管理模式創建:
rdspg_readwrite = rdspg_role_readwrite + login權限
rdspg_readonly = rdspg_role_readonly + login權限
配置步驟
創建項目資源owner賬號rdspg_owner和項目Role。
DBA使用dbsuperuser高權限賬號執行如下操作。
--- rdspg_owner 是項目管理賬號,此處密碼僅為示例,請注意修改。 CREATE USER rdspg_owner WITH LOGIN PASSWORD 'asdfy181BASDfadasdbfas'; CREATE ROLE rdspg_role_readwrite; CREATE ROLE rdspg_role_readonly; --- 設置: 對于rdspg_owner 創建的表,rdspg_role_readwrite 有 DQL(SELECT)、DML(UPDATE、INSERT、DELETE)權限。 ALTER DEFAULT PRIVILEGES FOR ROLE rdspg_owner GRANT ALL ON TABLES TO rdspg_role_readwrite; --- 設置: 對于rdspg_owner 創建的SEQUENCES,rdspg_role_readwrite 有 DQL(SELECT)、DML(UPDATE、INSERT、DELETE)權限。 ALTER DEFAULT PRIVILEGES FOR ROLE rdspg_owner GRANT ALL ON SEQUENCES TO rdspg_role_readwrite; --- 設置: 對于 rdspg_owner 創建的表, rdspg_role_readonly 只有 DQL(SELECT)權限。 ALTER DEFAULT PRIVILEGES FOR ROLE rdspg_owner GRANT SELECT ON TABLES TO rdspg_role_readonly;
創建rdspg_readwrite、rdspg_readonly業務賬號。
DBA使用dbsuperuser高權限賬號執行如下操作。
--- rdspg_readwrite只有 DQL(SELECT)、DML(UPDATE、INSERT、DELETE)權限。 CREATE USER rdspg_readwrite WITH LOGIN PASSWORD 'dfandfnapSDhf23hbEfabf'; GRANT rdspg_role_readwrite TO rdspg_readwrite; --- rdspg_readonly只有 DQL(SELECT)權限。 CREATE USER rdspg_readonly WITH LOGIN PASSWORD 'F89h912badSHfadsd01zlk'; GRANT rdspg_role_readonly TO rdspg_readonly;
創建schema rdspg,并授權給項目Role。
DBA使用dbsuperuser高權限賬號執行如下操作。
--- schema rdspg的owner是 rdspg_owner賬號 CREATE SCHEMA rdspg AUTHORIZATION rdspg_owner; --- 授權ROLE相關SCHEMA訪問權限。 GRANT USAGE ON SCHEMA rdspg TO rdspg_role_readwrite; GRANT USAGE ON SCHEMA rdspg TO rdspg_role_readonly;
說明rdspg_readwrite和rdspg_readonly自動繼承了相關Role的權限變更,不需要再額外操作。
應用場景示例
場景1:使用rdspg_owner賬號:對schema rdspg中的表進行DDL(CREATE、DROP、ALTER)操作
CREATE TABLE rdspg.test(id bigserial primary key, name text);
CREATE INDEX idx_test_name on rdspg.test(name);
場景2:使用 rdspg_readwrite/rdspg_readonly 賬號進行業務開發
業務開發遵循最小權限原則,盡量使用rdspg_readonly賬號,需要DML操作的地方才使用rdspg_readwrite賬號。這樣也方便在業務層做讀寫分離。
業務層做讀寫分離,避免了自動讀寫分離中間件proxy帶來的額外成本和性能損耗。
即使目前還沒有使用只讀實例,也建議區分 readonly客戶端、readwrite客戶端,為使用只讀實例做準備。readonly客戶端建議使用readonly賬號,最小權限原則,規避權限誤用。
readonly客戶端,使用readonly賬號,設置JDBC URL:
只讀實例1地址,只讀實例2地址,讀寫實例地址
。readwrite客戶端,使用readwrite賬號,設置JDBC URL:
讀寫實例地址
。
使用rdspg_readwrite賬號,對schema rdspg中的表進行DQL(SELECT)、DML(UPDATE、INSERT、DELETE)操作:
INSERT INTO rdspg.test (name) VALUES('name0'),('name1'); SELECT id,name FROM rdspg.test LIMIT 1; --- rdspg_readwrite沒有 DDL(CREATE、DROP、ALTER)權限 CREATE TABLE rdspg.test2(id int); ERROR: permission denied for schema rdspg LINE 1: create table rdspg.test2(id int); DROP TABLE rdspg.test; ERROR: must be owner of table test ALTER TABLE rdspg.test ADD id2 int; ERROR: must be owner of table test CREATE INDEX idx_test_name on rdspg.test(name); ERROR: must be owner of table test
使用rdspg_readonly賬號,對schema rdspg中的表進行DQL(SELECT)操作:
INSERT INTO rdspg.test (name) VALUES('name0'),('name1'); ERROR: permission denied for table test SELECT id,name FROM rdspg.test LIMIT 1; id | name ----+------- 1 | name0 (1 row)
場景3:不同項目交叉授權
如果有另外1個項目employee,需求為賬號employee_readwrite增加rdspg項目的表只讀權限。DBA使用dbsuperuser高權限賬號做如下操作:
--- 給賬號 employee_readwrite 加上 rdspg_role_readonly 權限集合。
GRANT rdspg_role_readonly TO employee_readwrite;
場景4:項目新增 schema rdspg_2,并授權給項目Role
rdspg_readwrite、rdspg_readonly、employee_readwrite賬號自動繼承了相關Role的權限變更,不需要再額外操作。DBA使用dbsuperuser 高權限賬號做如下操作:
CREATE SCHEMA rdspg_1 AUTHORIZATION rdspg_owner;
--- 授權ROLE相關SCHEMA訪問權限。
--- CREATE 使得 rdspg_role_admin 對schema rdspg_1中的表有 DDL(CREATE、DROP、ALTER)權限。
GRANT USAGE ON SCHEMA rdspg_1 TO rdspg_role_readwrite;
GRANT USAGE ON SCHEMA rdspg_1 TO rdspg_role_readonly;
賬號權限查詢
通過本文介紹的賬號權限管理模型創建的賬號,可以通過如下方式查詢具體權限信息。
使用PostgreSQL客戶端命令行終端連接RDS PostgreSQL數據庫,具體請參見連接PostgreSQL實例。然后使用
\du
命令查看:從上述查詢結果示例中可以看出:employee_readwrite賬號的Member of列中,內容為
rdspg_role_readonly,employee_role_readwrite
,因此,此賬號對employee項目表具有DQL和DML權限,對rdspg項目表具有DQL權限。使用SQL查詢:
SELECT r.rolname, r.rolsuper, r.rolinherit, r.rolcreaterole, r.rolcreatedb, r.rolcanlogin, r.rolconnlimit, r.rolvaliduntil, ARRAY(SELECT b.rolname FROM pg_catalog.pg_auth_members m JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid) WHERE m.member = r.oid) as memberof , r.rolreplication , r.rolbypassrls FROM pg_catalog.pg_roles r WHERE r.rolname !~ '^pg_' ORDER BY 1;