PostgreSQL 16即将发布第三个beta版本(计划日期8月10号),全部功能特性基本尘埃落定,本文与大家探讨新版本在权限管理方面的变化。
一、三个新增预置角色让普通用户后台管理更便捷
新版本增加的三个预置角色分别是:
- pg_maintain:允许执行一些表级维护操作而不需要具有DDL或DML的权限,可执行的维护操作命令包括:vacuum、analyze、reindex、refresh materialized view、cluster、lock table命令。
- pg_create_subscription:允许执行create subscription命令而不需要具有超级用户权限。
- pg_use_reserved_connections:允许用户使用reserved_connections参数设置的连接数来执行一些后台运维及管理操作而无须担心数据库连接被应用程序占满而无法工作。
注意:pg_maintain在beta3版本被回退。
二、初始用户权限优化
在PostgreSQL 16里,使用initdb工具初始化数据库时生成的初始用户不允许移除超级用户权限,示例如下:
postgres=# alter user postgres nosuperuser;
ERROR: permission denied to alter role
DETAIL: The bootstrap user must have the SUPERUSER attribute.
上面的代码对默认的postgres初始用户删除超级用户权限,该操作在PostgreSQL 16里会提示错误。初始用户仍然是许多重要系统对象的宿主,即便它没有超级用户权限也可以通过修改pg_catalog模式下的系统表来获得超级用户权限,之前的版本允许移除超级用户权限并不符合安全预期。
三、成员角色权限更安全
PostgreSQL 16对grant命令的语法进行了扩展,新增了with inherit和with set选项。
当对新建用户赋权系统预置角色时,可使用with inherit true选项,参考命令如下:
postgres=# grant pg_read_all_settings to a with inherit true;
GRANT ROLE
postgres=# \c - a
You are now connected to database "postgres" as user "a".
postgres=> show data_directory;
data_directory
-----------------
/opt/pgdata1600
(1 row)
使用with inherit true选项赋予成员角色后,不需要显式切换到成员角色即可进行相关的操作。
而自定义角色需要设置成员角色时,为了安全起见需要显式切换角色,此时可以设置with set true选项。
另外在PostgreSQL 16里使用带createrole属性创建新用户时,有如下变化:
- 自动成为新建用户的成员
- 拥有新建用户的管理权限
- 没有新建用户的继承权限
- 没有新建用户的角色切换权限
下面进行代码演示:
postgres=# create role admin login createrole;
CREATE ROLE
postgres=# \c - admin
You are now connected to database "postgres" as user "admin".
postgres=> create role user1 login;
CREATE ROLE
postgres=> \du admin
List of roles
Role name | Attributes | Member of
-----------+-------------+-----------
admin | Create role | {user1}
postgres=> alter user user1 connection limit 10;
ALTER ROLE
上面第一行代码被创建的admin用户带有createrole属性,第四行代码可以看到admin用户自动变为user1的成员。
第五行代码可以看到admin用户可以对创建的user1用户设置连接限制进行权限管理,并且只能对自己创建的角色或者被赋予admin选项的角色进行管理。
使用createrole属性创建的用户管理其他用户的能力将受到一定程度的限制,示例如下:
postgres=> \c - postgres
You are now connected to database "postgres" as user "postgres".
postgres=# create role admin2 LOGIN CREATEROLE;
CREATE ROLE
postgres=# \c - admin2
You are now connected to database "postgres" as user "admin2".
postgres=> alter user user1 connection limit -1;
ERROR: permission denied to alter role
DETAIL: Only roles with the CREATEROLE attribute and the ADMIN option on role "user1" may alter this role.
从上面的代码可以观察,同样拥有createrole属性的admin2用户并不能对admin创建的用户user1进行权限管理。
我们还可以从pg_auth_members系统表可以查看到如下变化:
postgres=> SELECT roleid::regrole,member::regrole,grantor::regrole, *
FROM pg_auth_members
WHERE roleid::regrole::text !~ '^pg_' \gx
-[ RECORD 1 ]--+---------
roleid | user1
member | admin
grantor | postgres
oid | 49336
roleid | 49335
member | 49334
grantor | 10
admin_option | t
inherit_option | f
set_option | f
从上面的数据记录观察pg_auth_members系统表新增了两个字段:
- inherit_option:字段的值为f表示admin用户没有继承user1用户的权限
- set_option字段的值为f表示admin用户没有切换到user1用户的权限。
上面的实验可以看到创建新用户后,默认只具有用户的管理权限而不能直接继承用户的权限以及不能直接切换用户。
PostgreSQL 16为了保持向下的兼容性,同时也新增了一个createrole_self_grant参数,它的参数值可以配置为inherit、set或者两者的组合,并使用逗号分割。
下面是createrole_self_grant参数使用的示例:
postgres=# \c - admin
You are now connected to database "postgres" as user "admin".
postgres=> set createrole_self_grant to 'set';
SET
postgres=> create user user2;
CREATE ROLE
postgres=> set role user2;
SET
postgres=> select roleid::regrole,member::regrole,grantor::regrole, *
from pg_auth_members
where roleid::regrole::text = 'user2'
and grantor::regrole::text = 'admin' \gx
-[ RECORD 1 ]--+------
roleid | user2
member | admin
grantor | admin
oid | 49358
roleid | 49356
member | 49334
grantor | 49334
admin_option | f
inherit_option | f
set_option | t
由于createrole_self_grant参数的值设置为set选项,使用admin用户创建的用户user2可以被admin用户使用set命令进行切换,同时pg_auth_members系统表的set_option字段值也变为了t。
总结
从以上几个方面可以看到PostgreSQL 16对普通用户的日常管理、成员角色权限以及初始用户权限做了不少的优化提升。
最后也欢迎大家关注本人即将出版的新书:<<快速掌握PostgreSQL版本新特性>>,书稿简介可以参考我写的这篇文章:PostgreSQL版本新特性顺利完稿
对本书感兴趣的朋友,可以加我微信入群,后续一起学习讨论。