使用适用于 PostgreSQL 的 Amazon RDS 委派扩展支持
使用适用于 PostgreSQL 的 Amazon RDS 委派扩展支持,您可以将扩展管理委派给其它用户,而且不必让该用户成为 rds_superuser
。通过这种委派扩展支持,将创建一个名为 rds_extension
的新角色,您必须将其分配给用户才能管理其它扩展。此角色可以创建、更新和删除扩展。
可以通过在 rds.allowed_extensions
参数中列出扩展,指定可以在 RDS 数据库实例上安装哪些扩展。有关更多信息,请参阅将 PostgreSQL 扩展与 Amazon RDS for PostgreSQL 结合使用。
您可以通过 rds.allowed_delegated_extensions
参数来限制具有 rds_extension
角色的用户可以管理的可用扩展列表。
委派扩展支持在以下版本中可用:
-
所有更高版本
-
16.4 及更高的 16 版本
-
15.8 及更高的 15 版本
-
14.13 及更高的 14 版本
-
13.16 及更高的 13 版本
-
12.20 及更高的 12 版本
主题
为用户开启委派扩展支持
必须执行以下操作才能为用户启用委派扩展支持:
-
向用户授予
rds_extension
角色:以rds_superuser
身份连接到数据库并执行以下命令:Postgres => grant rds_extension to
user_name
; -
设置可供委派用户管理的扩展列表:
rds.allowed_delegated_extensions
允许您使用rds.allowed_extensions
在数据库集群参数中指定可用扩展的子集。您可以在以下级别之一执行此操作:-
在集群或实例参数组中,通过 AWS Management Console或 API。有关更多信息,请参阅 Amazon RDS 的参数组。
-
在数据库级别使用以下命令:
alter database
database_name
set rds.allowed_delegated_extensions = 'extension_name_1
,extension_name_2
,...extension_name_n
'; -
在用户级别使用以下命令:
alter user
user_name
set rds.allowed_delegated_extensions = 'extension_name_1
,extension_name_2
,...extension_name_n
';
注意
更改
rds.allowed_delegated_extensions
动态参数后,无需重启数据库。 -
-
允许委派用户访问在扩展创建过程中创建的对象:某些扩展创建的对象要求先授予其它权限,然后具有
rds_extension
角色的用户才能访问它们。rds_superuser
必须向委派用户授予对这些对象的访问权限。其中一个选项是使用事件触发器自动向委派用户授予权限。有关更多信息,请参阅关闭对委派扩展的支持中的事件触发器示例。
在适用于 PostgreSQL 的 RDS 委派扩展支持中使用的配置
配置名称 | 描述 | 默认值 | 注意 | 谁可以修改或授予权限 |
---|---|---|---|---|
|
此参数限制 rds_extension 角色可以在数据库中管理的扩展。它必须是 rds.allowed_extensions 的子集。 |
空字符串 |
要了解有关设置此参数的更多信息,请参阅为用户开启委派扩展支持。 |
rds_superuser |
|
此参数可让客户限制可以在 RDS 数据库实例中安装的扩展。有关更多信息,请参阅限制 PostgreSQL 扩展的安装。 |
"*" |
默认情况下,此参数设置为“*”,这意味着具有必要权限的用户能够创建 RDS for PostgreSQL 和 Aurora PostgreSQL 支持的所有扩展。 空表示无法在 RDS 数据库实例中安装任何扩展。 |
管理员 |
|
此参数控制拥有 |
off |
默认情况下,将 要授予该能力, |
rds_superuser |
关闭对委派扩展的支持
部分关闭
委派用户无法创建新的扩展,但仍然可以更新现有的扩展。
-
在数据库集群参数组中将
rds.allowed_delegated_extensions
重置为默认值。 -
在数据库级别使用以下命令:
alter database
database_name
reset rds.allowed_delegated_extensions; -
在用户级别使用以下命令:
alter user
user_name
reset rds.allowed_delegated_extensions;
完全关闭
撤销用户的 rds_extension
角色会将该用户恢复为标准权限。用户无法再创建、更新或删除扩展。
postgres => revoke rds_extension from
user_name
;
事件触发器示例
如果您希望允许具有 rds_extension
的委派用户使用扩展,而此类扩展要求对通过扩展创建过程所创建的对象设置权限,则可以自定义以下事件触发器示例,并仅添加您希望委派用户有权访问其全部功能的扩展。此事件触发器可以在 template1(默认模板)上创建,因此所有从 template1 创建的数据库都将具有该事件触发器。当委派用户安装扩展时,此触发器将自动授予对扩展创建的对象的所有权。
CREATE OR REPLACE FUNCTION create_ext() RETURNS event_trigger AS $$ DECLARE schemaname TEXT; databaseowner TEXT; r RECORD; BEGIN IF tg_tag = 'CREATE EXTENSION' and current_user != 'rds_superuser' THEN RAISE NOTICE 'SECURITY INVOKER'; RAISE NOTICE 'user: %', current_user; FOR r IN SELECT * FROM pg_event_trigger_ddl_commands() LOOP CONTINUE WHEN r.command_tag != 'CREATE EXTENSION' OR r.object_type != 'extension'; schemaname = ( SELECT n.nspname FROM pg_catalog.pg_extension AS e INNER JOIN pg_catalog.pg_namespace AS n ON e.extnamespace = n.oid WHERE e.oid = r.objid ); databaseowner = ( SELECT pg_catalog.pg_get_userbyid(d.datdba) FROM pg_catalog.pg_database d WHERE d.datname = current_database() ); RAISE NOTICE 'Record for event trigger %, objid: %,tag: %, current_user: %, schema: %, database_owenr: %', r.object_identity, r.objid, tg_tag, current_user, schemaname, databaseowner; IF r.object_identity = 'address_standardizer_data_us' THEN EXECUTE format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.us_gaz TO %I WITH GRANT OPTION;', schemaname, databaseowner); EXECUTE format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.us_lex TO %I WITH GRANT OPTION;', schemaname, databaseowner); EXECUTE format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.us_rules TO %I WITH GRANT OPTION;', schemaname, databaseowner); ELSIF r.object_identity = 'dict_int' THEN EXECUTE format('ALTER TEXT SEARCH DICTIONARY %I.intdict OWNER TO %I;', schemaname, databaseowner); ELSIF r.object_identity = 'pg_partman' THEN EXECUTE format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.part_config TO %I WITH GRANT OPTION;', schemaname, databaseowner); EXECUTE format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.part_config_sub TO %I WITH GRANT OPTION;', schemaname, databaseowner); EXECUTE format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.custom_time_partitions TO %I WITH GRANT OPTION;', schemaname, databaseowner); ELSIF r.object_identity = 'postgis_topology' THEN EXECUTE format('GRANT SELECT, UPDATE, INSERT, DELETE ON ALL TABLES IN SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner); EXECUTE format('GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner); EXECUTE format('GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner); EXECUTE format('GRANT USAGE ON SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner); END IF; END LOOP; END IF; END; $$ LANGUAGE plpgsql SECURITY DEFINER; CREATE EVENT TRIGGER log_create_ext ON ddl_command_end EXECUTE PROCEDURE create_ext();
使用 Amazon RDS 委派扩展支持的优势
通过使用适用于 PostgreSQL 的 Amazon RDS 委派扩展支持,您可以安全地将扩展管理委派给没有 rds_superuser
角色的用户。该功能具有以下优势:
-
您可以轻松地将扩展管理委派给您选择的用户。
-
这不需要
rds_superuser
角色。 -
支持为同一个数据库集群中的不同数据库提供不同的扩展集。
适用于 PostgreSQL 的 Amazon RDS 委派扩展支持的限制
-
在扩展创建过程中创建的对象可能需要额外的权限才能使扩展正常运行。
-
默认情况下,委派扩展用户无法管理某些扩展,包括以下各项:
log_fdw
、pg_cron
、pg_tle
、pgactive
、pglogical
、postgis_raster
、postgis_tiger_geocoder
、postgis_topology
。
某些扩展所需的权限
要创建、使用或更新以下扩展,委派用户应具有对以下函数、表和架构的必要权限。
需要所有权或权限的扩展 | 函数 | 表 | 架构 | 文本搜索词典 | 注释 |
---|---|---|---|---|---|
address_standardizer_data_us |
none |
us_gaz、us_lex、us_lex、I.us_rules |
none |
none |
none |
amcheck |
bt_index_check、bt_index_parent_check |
none |
none |
none |
none |
dict_int |
none |
none |
none |
intdict |
none |
pg_partman |
none |
custom_time_partitions、part_config、part_config_sub |
none |
none |
none |
pg_stat_statements |
none |
none |
none |
none |
none |
PostGIS |
st_tileenvelope |
spatial_ref_sys |
none |
none |
none |
postgis_raster |
none |
none |
none |
none |
none |
postgis_topology |
none |
topology、layer |
topology |
none |
委派用户必须是数据库所有者 |
log_fdw |
create_foreign_table_for_log_file |
none |
none |
none |
none |
rds_tools |
role_password_encryption_type |
none |
none |
none |
none |
postgis_tiger_geocoder |
none |
geocode_settings_default、geocode_settings |
tiger |
none |
none |
pg_freespacemap |
pg_freespace |
none |
none |
none |
none |
pg_visibility |
pg_visibility |
none |
none |
none |
none |
安全考虑因素
请记住,具有 rds_extension
角色的用户将能够管理他们拥有连接权限的所有数据库上的扩展。如果打算让委派用户管理单个数据库上的扩展,那么一个好的做法是撤销每个数据库上的公有权限,然后向委派用户显式授予对该特定数据库的连接权限。
有几个扩展可以允许用户访问多个数据库中的信息。在向 rds.allowed_delegated_extensions
添加这些扩展之前,请确保您授予 rds_extension
的用户具有跨数据库功能。例如,postgres_fdw
和 dblink
提供在同一实例或远程实例上跨数据库进行查询的功能。log_fdw
读取 postgres 引擎日志文件,这些文件适用于实例中的所有数据库,可能包含来自多个数据库的慢速查询或错误消息。pg_cron
允许在数据库实例上运行计划的后台任务,并且可以将任务配置为在不同的数据库中运行。
已禁用删除扩展级联
具有 rds_extension
角色的用户使用级联选项删除扩展的能力由 rds.delegated_extension_allow_drop_cascade
参数控制。默认情况下,将 rds-delegated_extension_allow_drop_cascade
设置为 off
。这意味着不允许具有 rds_extension
角色的用户使用级联选项删除扩展,如以下查询所示。
DROP EXTENSION CASCADE;
因为这将自动删除依赖于扩展的对象,进而删除依赖于这些对象的所有对象。尝试使用级联选项将会导致错误。
要授予该能力,rds.delegated_extension_allow_drop_cascade
参数应设置为 on
。
更改 rds.delegated_extension_allow_drop_cascade
动态参数不需要重启数据库。您可以在以下级别之一执行此操作:
-
在集群或实例参数组中,通过 AWS Management Console或 API。
-
在数据库级别使用以下命令:
alter database
database_name
set rds.delegated_extension_allow_drop_cascade = 'on'; -
在用户级别使用以下命令:
alter role tenant_user set rds.delegated_extension_allow_drop_cascade = 'on';
可以使用委派扩展支持添加的扩展示例
-
rds_tools
extension_test_db=> create extension rds_tools; CREATE EXTENSION extension_test_db=> SELECT * from rds_tools.role_password_encryption_type() where rolname = 'pg_read_server_files'; ERROR: permission denied for function role_password_encryption_type
-
amcheck
extension_test_db=> CREATE TABLE amcheck_test (id int); CREATE TABLE extension_test_db=> INSERT INTO amcheck_test VALUES (generate_series(1,100000)); INSERT 0 100000 extension_test_db=> CREATE INDEX amcheck_test_btree_idx ON amcheck_test USING btree (id); CREATE INDEX extension_test_db=> create extension amcheck; CREATE EXTENSION extension_test_db=> SELECT bt_index_check('amcheck_test_btree_idx'::regclass); ERROR: permission denied for function bt_index_check extension_test_db=> SELECT bt_index_parent_check('amcheck_test_btree_idx'::regclass); ERROR: permission denied for function bt_index_parent_check
-
pg_freespacemap
extension_test_db=> create extension pg_freespacemap; CREATE EXTENSION extension_test_db=> SELECT * FROM pg_freespace('pg_authid'); ERROR: permission denied for function pg_freespace extension_test_db=> SELECT * FROM pg_freespace('pg_authid',0); ERROR: permission denied for function pg_freespace
-
pg_visibility
extension_test_db=> create extension pg_visibility; CREATE EXTENSION extension_test_db=> select * from pg_visibility('pg_database'::regclass); ERROR: permission denied for function pg_visibility
-
postgres_fdw
extension_test_db=> create extension postgres_fdw; CREATE EXTENSION extension_test_db=> create server myserver foreign data wrapper postgres_fdw options (host 'foo', dbname 'foodb', port '5432'); ERROR: permission denied for foreign-data wrapper postgres_fdw