使用适用于 PostgreSQL 的 Amazon RDS 委派扩展支持 - Amazon Relational Database Service

使用适用于 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 版本

为用户开启委派扩展支持

必须执行以下操作才能为用户启用委派扩展支持:

  1. 向用户授予 rds_extension 角色:以 rds_superuser 身份连接到数据库并执行以下命令:

    Postgres => grant rds_extension to user_name;
  2. 设置可供委派用户管理的扩展列表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 动态参数后,无需重启数据库。

  3. 允许委派用户访问在扩展创建过程中创建的对象:某些扩展创建的对象要求先授予其它权限,然后具有 rds_extension 角色的用户才能访问它们。rds_superuser 必须向委派用户授予对这些对象的访问权限。其中一个选项是使用事件触发器自动向委派用户授予权限。有关更多信息,请参阅关闭对委派扩展的支持中的事件触发器示例。

在适用于 PostgreSQL 的 RDS 委派扩展支持中使用的配置

配置名称 描述 默认值 注意 谁可以修改或授予权限

rds.allowed_delegated_extensions

此参数限制 rds_extension 角色可以在数据库中管理的扩展。它必须是 rds.allowed_extensions 的子集。

空字符串

  • 默认情况下,此参数为空字符串,这意味着没有向具有 rds_extension 的用户委派任何扩展。

  • 如果用户有添加受支持的扩展的权限,则可以添加此扩展。为此,请将 rds.allowed_delegated_extensions 参数设置为一串以逗号分隔的扩展名称。通过向该参数添加扩展列表,可以显式确定具有 rds_extension 角色的用户可以安装的扩展。

  • 如果设置为 *,则表示 rds_allowed_extensions 中列出的所有扩展都将委派给具有 rds_extension 角色的用户。

要了解有关设置此参数的更多信息,请参阅为用户开启委派扩展支持

rds_superuser

rds.allowed_extensions

此参数可让客户限制可以在 RDS 数据库实例中安装的扩展。有关更多信息,请参阅限制 PostgreSQL 扩展的安装

"*"

默认情况下,此参数设置为“*”,这意味着具有必要权限的用户能够创建 RDS for PostgreSQL 和 Aurora PostgreSQL 支持的所有扩展。

空表示无法在 RDS 数据库实例中安装任何扩展。

管理员

rds-delegated_extension_allow_drop_cascade

此参数控制拥有 rds_extension 的用户使用级联选项删除扩展的能力。

off

默认情况下,将 rds-delegated_extension_allow_drop_cascade 设置为 off。这意味着不允许拥有 rds_extension 的用户使用级联选项删除扩展。

要授予该能力,rds.delegated_extension_allow_drop_cascade 参数应设置为 on

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_fdwpg_cronpg_tlepgactivepglogicalpostgis_rasterpostgis_tiger_geocoderpostgis_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_fdwdblink 提供在同一实例或远程实例上跨数据库进行查询的功能。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