PostgreSQL 15: 配置参数的 SET 和 ALTER SYSTEM 权限

John Doe 八月 1, 2025

你想要对配置参数的设置进行细粒度的权限管理吗?现在,PostgreSQL 可以做到这一点了。

非洲大草原上的一头大象

特性提交日志

允许授予 GUC 参数的 SET 和 ALTER SYSTEM 权限。

此补丁允许非超级用户在获得明确授权的情况下设置 “PGC_SUSET” 参数。也可以授予针对特定参数执行 ALTER SYSTEM SET/RESET 的权限。

此类权限是实例级别的,而非按数据库划分。它们在新的全局系统表 pg_parameter_acl 中进行跟踪。

授予和撤销这些新权限的操作与预期一致。需要注意的是,PGC_USERSET 类型的 GUC 参数不受 SET 权限的影响,理论上可以通过向 PUBLIC 角色授予可撤销的权限来处理这类参数,但实际并未采用这种方式,因为对于扩展定义的 GUC 参数而言,这种方式无法保证足够的稳健性。

讨论:https://postgr.es/m/3D691E20-C1D5-4B80-8BA5-6BEB63AF3029@enterprisedb.com

示例

通过本次提交的特性,你可以控制谁被允许设置特定参数。这为你提供了更多灵活性,尤其是在为客户托管 PostgreSQL 实例时。你可以将更多控制权委托给可信用户或角色,当然,当不再需要时,你也可以在之后撤销该权限。这样做的一个目标是减少需要超级用户权限的任务数量。下面,让我们通过一个简单的示例来看看如何使用它。

首先,我们创建一个新用户,并以该用户身份连接:

postgres=# create user u with login password 'u';
CREATE ROLE
postgres=# \c postgres u
You are now connected to database "postgres" as user "u".

该用户被允许设置哪些参数呢?在实例和数据库级别,什么都不能设置:

alter system set work_mem='12MB';
ERROR:  permission denied to set parameter "work_mem"

alter database postgres set work_mem='12MB';
ERROR:  must be owner of database postgres

当然,该用户可以为自己设置新的参数值,这可以是永久设置,也可以是在会话中设置:

alter user u set work_mem='12MB';

set work_mem='10MB';

这适用于 pg_settings 中 context 为 “user” 的所有参数:

select name,context from pg_settings where context = 'user' order by 1;
                name                 | context 
-------------------------------------+---------
 application_name                    | user
 array_nulls                         | user
 backend_flush_after                 | user
 backslash_quote                     | user
 bytea_output                        | user
 check_function_bodies               | user
 client_connection_check_interval    | user
 client_encoding                     | user
 client_min_messages                 | user
 commit_siblings                     | user
 constraint_exclusion                | user
 cpu_index_tuple_cost                | user
 cpu_operator_cost                   | user
 cpu_tuple_cost                      | user
 cursor_tuple_fraction               | user
 DateStyle                           | user
 debug_pretty_print                  | user
 debug_print_parse                   | user
...
 vacuum_cost_limit                   | user
 vacuum_cost_page_dirty              | user
 vacuum_cost_page_hit                | user
 vacuum_cost_page_miss               | user
 vacuum_failsafe_age                 | user
 vacuum_freeze_min_age               | user
 vacuum_freeze_table_age             | user
 vacuum_multixact_failsafe_age       | user
 vacuum_multixact_freeze_min_age     | user
 vacuum_multixact_freeze_table_age   | user
 wal_sender_timeout                  | user
 wal_skip_threshold                  | user
 work_mem                            | user
 xmlbinary                           | user
 xmloption                           | user
(136 rows)

对于所有其他参数,该操作不起作用:

select name,context from pg_settings where context != 'user' order by 1;
                  name                  |      context
----------------------------------------+-------------------
 allow_in_place_tablespaces             | superuser
 allow_system_table_mods                | superuser
 archive_cleanup_command                | sighup
 archive_command                        | sighup
 archive_library                        | sighup
 archive_mode                           | postmaster
 archive_timeout                        | sighup
 authentication_timeout                 | sighup
...
 wal_sync_method                        | sighup
 wal_writer_delay                       | sighup
 wal_writer_flush_after                 | sighup
 zero_damaged_pages                     | superuser
(202 rows)

SET track_counts='on';
ERROR:  permission denied to set parameter "track_counts"

上面的情况已经成为历史。从 PostgreSQL 新版本开始,你可以向用户或角色授予设置特定参数的权限:

postgres=# SELECT current_user;
 current_user
--------------
 postgres
(1 row)
postgres=# GRANT SET ON PARAMETER track_counts TO u;
GRANT
postgres=# \c postgres u
You are now connected to database "postgres" as user "u".
postgres=> SET track_counts = 'on';
SET

这在实例级别也适用:

postgres=# GRANT ALTER SYSTEM ON PARAMETER shared_buffers TO u;
GRANT
postgres=# \c postgres u
You are now connected to database "postgres" as user "u".
postgres=> ALTER SYSTEM SET shared_buffers = '129MB';
ALTER SYSTEM

本次提交的特性新增了一个系统表,它可以列出所有参数的授权:

postgres=> \c postgres
You are now connected to database "postgres" as user "u".
postgres=> select * from pg_parameter_acl;
  oid  |    parname     |               paracl                
-------+----------------+-------------------------------------
 16392 | track_counts   | {postgres=sA/postgres,u=s/postgres}
 16393 | wal_level      | {postgres=sA/postgres,u=s/postgres}
 16394 | shared_buffers | {postgres=sA/postgres,u=A/postgres}
(3 rows)

非常不错的体验,感谢所有参与的社区人员。

参考

提交日志:https://git.postgresql.org/pg/commitdiff/a0ffa885e478f5eeacc4e250e35ce25a4740c487