PostgreSQL 数据库权限、角色总结
- 1、权限
- (1)权限的初始状态
- (2)grant 和 revoke
- (3)权限类型
- (4)适用对象的类型
- (5)默认情况
- 2、角色
- (1)数据库角色
- (2)角色属性
- 角色属性的运用
- (3)角色成员
- (4)drop 角色
- (5)预定义角色
- (6)函数安全
- 3、grant 和 revoke
1、权限
主要的资料来源
(1)权限的初始状态
对象的所有者(或超级用户)可以对该对象执行任何操作。
ALTER TABLE table_name OWNER TO new_owner;
"owner to" 一个新的所有者。
(2)grant 和 revoke
使用 grant 和 revoke 进行授权和撤权
grant 权限类型 on 适用对象 to 用户(组);
revoke 权限类型 on 适用对象 from 用户(组);
在 SQL 标准中,用户和角色为不同的概念;在 PostgreSQL 中,用户和角色统一为一种实体,即用户和角色是“相同的”,用户是具有连接登录权限的角色。
(3)权限类型
权限类型包括:SELECT、INSERT、UPDATE、DELETE、TRUNCATE、REFERENCES、TRIGGER、CREATE、CONNECT、TEMPORARY、EXECUTE、USAGE、SET、ALTER SYSTEM。
详情如下:
SELECT
- 允许从表、视图、具体化视图或其他类似表的对象的任何列或特定列执行 SELECT 操作。
- 还允许使用 COPY TO。
- UPDATE、DELETE 或 MERGE 也需要此权限。
- 对于 SEQUENCE,此权限还允许使用 currval 函数。
- 对于 LARGE OBJECT,此权限允许读取对象。
INSERT
- 允许将新行 INSERT 到表、视图等中。可以在特定列上授予,在这种情况下,只能在 INSERT 命令中使用这些列(其他列将获得默认值)。
- 还允许使用 COPY FROM。
UPDATE
- 允许对表、视图等的任何列或特定列执行 UPDATE。
- 对于 SEQUENCE,此权限允许使用 nextval 和 setval 函数。
- 对于 LARGE OBJECT,此权限允许写入或截断对象。
DELETE
允许从表、视图等中 DELETE 行。
TRUNCATE
允许对表进行 TRUNCATE。
REFERENCES
允许创建引用表的外键约束或表的特定列。
TRIGGER
允许在表、视图等上创建触发器。
CREATE
- 对于数据库,允许在数据库中创建新的 SCHEMA 和发布,并允许在数据库中安装 Trusted Extensions。
- 对于 SCHEMA,允许在 SCHEMA 中创建新对象。要重命名现有对象,您必须拥有该对象,并拥有此权限。
- 对于表空间,允许在表空间内创建表、索引和临时文件,并允许创建
将表空间作为其默认表空间的数据库。
请注意,撤销此权限,不会更改现有对象的存在或位置(即不会删除对象)。
CONNECT
允许被授权者连接到数据库。在连接启动时检查此权限(除了检查 pg_hba.conf 施加的任何限制外)。
TEMPORARY
允许在使用数据库时创建临时表。
EXECUTE
允许调用函数或过程,包括使用在函数上实现的任何运算符。这是唯一适用于函数和过程的权限类型。
USAGE
- 对于过程语言(LANGUAGE),允许使用该语言创建函数。这是唯一适用于过程语言的权限类型。
- 对于 SCHEMA,允许访问 SCHEMA 中包含的对象(假设还满足对象自己的权限要求)。从本质上讲,这允许被授权者在 schema 中 “查找” 对象。如果没有此权限,仍然可以查看对象名称,例如,通过查询 system catalog。此外,撤销此权限后,现有会话可能具有以前执行过此 “查找” 的语句,因此这不是阻止对象访问的完全安全方法。
- 对于SEQUENCE,允许使用 currval 和 nextval 函数。
- 对于 DOMAIN 和 TYPE,允许在创建表、函数和其他架构对象时使用 DOMAIN 和 TYPE。此权限并不控制该类型的所有 “用法”,例如,查询中出现的 type 的值。它仅阻止创建依赖于 TYPE 的对象。此权限的主要目的是控制哪些用户可以创建对 TYPE 的依赖关系,这可能会阻止所有者以后更改类型。
- 对于 FOREIGN DATA WRAPPER,允许使用外部数据包装器创建新服务器。
- 对于 FOREIGN SERVER,允许使用服务器创建外部表。被授权者还可以创建、更改或删除与该服务器关联的用户映射。
SET
允许在当前会话中将服务器配置参数设置为新值。
ALTER SYSTEM
允许使用 ALTER SYSTEM 命令将服务器配置参数配置为新值。
另,需要特别控制的权限,包括:是否为超级用户(SUPERUSER/NOSUPERUSER)、是否可以创建新角色(CREATEROLE/NOCREATEROLE)、是否可以启动流复制(REPLICATION/NOREPLICATION)、是否可以绕过行级安全性(BYPASSRLS/NOBYPASSRLS)、角色连接最大数量(CONNECTION LIMIT)。但这一般是在创建角色时,通过角色属性进行设置。
(4)适用对象的类型
权限及其适用的对象的类型:
| 权限类型 | 缩写 | 适用对象的类型 |
|---|---|---|
| SELECT | r (“read”) | LARGE OBJECT, SEQUENCE, TABLE (and table-like objects), table column |
| INSERT | a (“append”) | TABLE, table column |
| UPDATE | w (“write”) | LARGE OBJECT, SEQUENCE, TABLE, table column |
| DELETE | d | TABLE |
| TRUNCATE | D | TABLE |
| REFERENCES | x | TABLE, table column |
| TRIGGER | t | TABLE |
| CREATE | C | DATABASE, SCHEMA, TABLESPACE |
| CONNECT | c | DATABASE |
| TEMPORARY | T | DATABASE |
| EXECUTE | X | FUNCTION, PROCEDURE |
| USAGE | U | DOMAIN, FOREIGN DATA WRAPPER, FOREIGN SERVER, LANGUAGE, SCHEMA, SEQUENCE, TYPE |
| SET | s | PARAMETER |
| ALTER SYSTEM | A | PARAMETER |
对象及其可以授予的权限:
| 对象的类型 | 权限 | 默认公开权限 | psql Command |
|---|---|---|---|
| DATABASE | CTc | Tc | \l |
| DOMAIN | U | U | \dD+ |
| FUNCTION or PROCEDURE | X | X | \df+ |
| FOREIGN DATA WRAPPER | U | none | \dew+ |
| FOREIGN SERVER | U | none | \des+ |
| LANGUAGE | U | U | \dL+ |
| LARGE OBJECT | rw | none | \dl+ |
| PARAMETER | sA | none | \dconfig+ |
| SCHEMA | UC | none | \dn+ |
| SEQUENCE | rwU | none | \dp |
| TABLE (and table-like objects) | arwdDxt | none | \dp |
| Table column | arwx | none | \dp |
| TABLESPACE | C | none | \db+ |
| TYPE | U | U | \dT+ |
(5)默认情况
默认情况下,PostgreSQL 在创建对象时,不会将某些类型的对象的权限授予 PUBLIC:
FOREIGN DATA WRAPPER、FOREIGN SERVER、LARGE OBJECT、PARAMETER、SCHEMA、SEQUENCE、TABLE 、Table column 及 TABLESPACE。
默认情况下,PostgreSQL 在创建对象时,会将某些类型的对象的权限授予 PUBLIC:
DATABASE 【CONNECT 和 TEMPORARY(创建临时表)权限】,FUNCTION or PROCEDURE【EXECUTE 权限】,DOMAIN、LANGUAGE、TYPE【USAGE 权限】。
当然,对象所有者可以 REVOKE 这些默认权限,并显式授予权限。
为了获得最大的安全性,请在创建对象的同一事务中发出 REVOKE;然后,其他用户就不能使用该对象。
此外,还可以使用 ALTER DEFAULT PRIVILEGES 命令覆盖这些默认权限设置。
2、角色
主要的资料来源
(1)数据库角色
数据库角色在数据库集群安装中是全局的(而不是按单个数据库)。
新初始化的系统始终包含一个预定义的角色。此角色始终是“超级用户”,通常,此角色将命名为 postgres。
与数据库服务器的每个连接,都是使用某个特定角色的名称建立的,在该连接中,该角色确定初始访问权限。
特殊的 “角色” 名称 PUBLIC 可用于向系统上的每个角色授予权限。它自动地、隐式地包含了数据库中的每个用户。
任何特定角色都将具有:直接授予它的权限、授予它当前所属的组角色的权限,以及授予 PUBLIC 的权限。
(2)角色属性
LOGIN/NOLOGIN:
LOGIN:具有此属性的角色可以用于数据库连接,即可以视为登录用户。
NOLOGIN:没有此属性的角色不能用于数据库连接,默认值。
SUPERUSER/NOSUPERUSER:
SUPERUSER:超级用户拥有数据库的所有权限,包括创建数据库、创建角色、修改系统配置等。
NOSUPERUSER:非超级用户,其权限受到一定限制,默认值。
CREATEDB/NOCREATEDB:
CREATEDB:具有此属性的角色可以创建数据库。
NOCREATEDB:没有此属性的角色不能创建数据库,默认值。
CREATEROLE/NOCREATEROLE:
CREATEROLE:具有此属性的角色可以创建、修改和删除其他角色,以及给其他角色赋予或撤销权限。应将具有“创建角色”权限的用户,视为超级用户。
NOCREATEROLE:没有此属性的角色不能执行上述操作,默认值。
INHERIT/NOINHERIT:
INHERIT:具有此属性的角色会自动继承其所属组角色的权限,默认值。需要注意的是,角色属性 对应的权限并不被继承,例如,CREATEDB、CREATEROLE;即通过 create role 和 alter role 设置的角色属性,不被继承。但在 PostgreSQL 的早期版本中,会继承所有权限。被继承的,是诸如对表等对象的操作权限。另,需要注意的是,在 SQL 标准中,只有角色有继承属性,并且继承所有权限,而用户没有所谓的继承。
NOINHERIT:没有此属性的角色不会继承其所属组角色的权限,除非显式地执行SET ROLE命令来临时“成为”组角色。
REPLICATION/NOREPLICATION:
REPLICATION:具有此属性的角色可以启动流复制。
NOREPLICATION:没有此属性的角色不能启动流复制,默认值。
BYPASSRLS/NOBYPASSRLS:
BYPASSRLS:具有此属性的角色可以绕过行级安全性(Row-Level Security, RLS)检查【另,超级用用和所有者始终绕过 RLS 检查】。
NOBYPASSRLS:没有此属性的角色不能绕过RLS检查,默认值。
CONNECTION LIMIT:
此属性用于限制角色可以同时建立的连接数,但超级用户不受限。
PASSWORD:
用于设置角色的密码。如果设置了密码,则角色在连接数据库时需要提供该密码。
VALID UNTIL:
此属性用于设置角色的密码有效期。它仅定义密码的过期时间,而不是角色本身的过期时间。特别是,使用非基于密码的身份验证方法登录时,不会强制执行过期时间。
角色属性的运用
--CREATE:
CREATE ROLE name [ [ WITH ] option [ ... ] ];
/*
option 可以是一个或多个角色属性、参数:
SUPERUSER | NOSUPERUSER
| CREATEDB | NOCREATEDB
| CREATEROLE | NOCREATEROLE
| INHERIT | NOINHERIT
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT connlimit
| [ ENCRYPTED ] PASSWORD 'password' | PASSWORD NULL
| VALID UNTIL 'timestamp'
| IN ROLE role_name [, ...]
| IN GROUP role_name [, ...]
| ROLE role_name [, ...]
| ADMIN role_name [, ...]
| USER role_name [, ...]
| SYSID uid
其中,SYSID 仅用于向后兼容,将被忽略。
*/
--ALTER:
ALTER ROLE role_specification [ WITH ] option [ ... ];
/*
option 可以是一个或多个角色属性:
SUPERUSER | NOSUPERUSER
| CREATEDB | NOCREATEDB
| CREATEROLE | NOCREATEROLE
| INHERIT | NOINHERIT
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT connlimit
| [ ENCRYPTED ] PASSWORD 'password' | PASSWORD NULL
| VALID UNTIL 'timestamp'
*/
注意事项:
-
使用 ALTER ROLE 更改角色的属性,
使用 DROP ROLE 删除角色。
CREATE ROLE 指定的所有属性都可以由 ALTER ROLE 命令进行修改。- ALTER ROLE 语句是 PostgreSQL 扩展,在SQL标准中,并没有直接名为 ALTER ROLE 的子句。很多现代的数据库管理系统提供了相同的功能。
-
首选使用 GRANT 和 REVOKE 进行用户组的成员管理。
在 CREATE ROLE 时,可以立即指定 新建角色 属于哪个组或其包含哪些现有角色。- IN ROLE 或 IN GROUP:指定 新建角色 属于哪个组;
- ROLE 或 USER:指定 新建角色 包含哪些现有角色;
- ADMIN:同 ROLE【指定 新建角色 包含哪些现有角色】,但同时使 列出的现有角色具有以下权限:添加成员到该组。
(3)角色成员
将用户分组,以简化权限管理。
-
作为组的角色一般不具有 LOGIN 属性,但可以根据需要,设置该属性。
-
将作为组的角色视为一组权限,授予不同的角色,或从角色上撤销:
GRANT group_role TO role1, ... ;
REVOKE group_role FROM role1, ... ;
组角色和非组角色之间实际上没有任何区别。
授权不允许形成循环。
不允许向 PUBLIC 授予角色的成员资格,即不要向 public 组添加成员。它自动包含数据库中的每个用户。
成员角色通过两种方式使用组角色的权限:
- 成员角色都可以显式地执行 SET ROLE 来临时“成为”组角色。在此状态下,数据库会话可以访问组角色而不是原始登录角色的权限,并且创建的任何数据库对象都被视为由组角色而不是成员角色拥有。
- 其次,具有 INHERIT 属性的成员角色会自动使用其所属角色的权限,包括继承的任何权限。
举例说明:
--创建具有INHERIT属性的角色joe:
CREATE ROLE joe LOGIN INHERIT;
--创建具有NOINHERIT属性的角色admin:
CREATE ROLE admin NOINHERIT;
--创建具有NOINHERIT属性的角色wheel:
CREATE ROLE wheel NOINHERIT;
--将joe作为成员,添加进admin组:
GRANT admin TO joe;
--将admin作为成员,添加进wheel组:
GRANT wheel TO admin;
一个 session 以 joe 身份连接登录数据库,则立即具有授予 joe 的权限 和 授予 admin 的权限 。因为 joe 具有属性 INHERIT,能继承其所在组 admin 的任何权限。
即便 joe 也是 wheel 的成员(间接地),但该 session 并不具有授予 wheel 的权限。因为 admin 具有属性 NOINHERIT,并未继承任何来自 wheel 的权限。
SET ROLE admin;
执行 SET ROLE admin;之后,数据库将该 session 视为以 admin 连接,则仅具有授予 admin 的权限。
SET ROLE wheel;
执行 SET ROLE wheel;之后,数据库将该 session 视为以 wheel 连接,则仅具有授予 wheel 的权限。
要想恢复到原始状态,执行以下任一语句即可:
SET ROLE joe;
SET ROLE NONE;
RESET ROLE;
注意事项一:
在 SQL 标准中,角色与用户有明显的区别,角色自动继承其所属组的权限,而用户不会。
在 PostgreSQL 要想达到同样效果,可以通过:
- 将角色的属性设置为 INHERIT,使角色像 SQL标准中的角色一样,能自动继承其所属组的权限;
- 将角色的属性设置为 NOINHERIT,使角色像 SQL标准中的用户一样,不能自动继承其所属组的权限。
注意事项二:
诸如 LOGIN, SUPERUSER, CREATEDB 和 CREATEROLE 等这些角色属性,视为不能被继承的权限。在上述的例子中,假定已经给 admin 设置了属性 CREATEDB 和 CREATEROLE ,以 joe 身份连接登录数据库的 session 并不能立即具有创建数据库和创建角色的权限,需要执行 SET ROLE admin;之后才可以。
(4)drop 角色
删除一个角色,首先必须删除干净所有者是该角色的对象,或将这些对象改为其他角色所有;并且必须撤销授予该角色的任何权限。
可以使用 ALTER 命令来修改对象的所有者,例如,ALTER TABLE table_name OWNER TO new_owner;
也可以使用 REASSIGN OWNED 命令,将对象的所有权重新分配给其他角色。由于 REASSIGN OWNED 无法跨库执行,因此必须在每个数据库中运行它。如果是跨数据库共享对象,第一个 REASSIGN OWNED 命令执行时,就更改了它们的所有权,例如数据库或表空间。
使用 DROP OWNED 命令,删除剩余的对象。同样,此命令无法跨库执行,因此必须在每个数据库中运行它。此外,DROP OWNED 不会删除整个数据库或表空间,因此,如果角色拥有任何尚未转让给新所有者的数据库或表空间,则必须手动执行删除数据库或表空间。
DROP OWNED 还负责删除相应的权限。由于 REASSIGN OWNED 不涉及此类对象,因此通常需要同时运行 REASSIGN OWNED 和 DROP OWNED(按此顺序)以完全删除要删除的角色的依赖项。
简而言之,删除已用于拥有对象的角色的最通用方法是:
REASSIGN OWNED BY doomed_role TO successor_role;
DROP OWNED BY doomed_role;
-- 每个数据库中,重复上述命令
DROP ROLE doomed_role;
如果没有处理干净,就尝试 DROP ROLE,它将发出消息,指出哪些对象需要重新分配或删除。
(5)预定义角色
PostgreSQL 提供了一组预定义的角色。
| 角色 | 被允许的访问 |
|---|---|
| pg_read_all_data | 读取所有数据(表、视图、序列):具有 SELECT 权限,对所有 schema 具有 USAGE 权限;即使没有显式声明拥有这些权限。此角色没有设置角色属性 BYPASSRLS。如果正在使用 RLS,则管理员可能希望在此角色被授予的角色上设置 BYPASSRLS。 |
| pg_write_all_data | 写入所有数据(表、视图、序列):具有 INSERT、UPDATE 和 DELETE 权限以及对所有 schema 具有 USAGE 权限;即使没有显式声明拥有这些权限。此角色没有设置角色属性 BYPASSRLS。如果正在使用 RLS,则管理员可能希望在此角色被授予的角色上设置 BYPASSRLS。 |
| pg_read_all_settings | 读取所有配置变量,甚至包括通常仅对超级用户可见的变量。 |
| pg_read_all_stats | 读取所有 pg_stat_* 视图并使用各种与统计相关的扩展,甚至是通常仅对超级用户可见的扩展。 |
| pg_stat_scan_tables | 执行监控功能,这些功能可能会持续很长时间,并且可能对表执行 ACCESS SHARE 锁。 |
| pg_monitor | 读取各种监控视图/执行各种监控功能。此角色是 pg_read_all_settings、pg_read_all_stats 和 pg_stat_scan_tables 的成员。 |
| pg_database_owner | 没有。成员由当前数据库所有者组成。 |
| pg_signal_backend | 向另一个后端发出信号以取消查询或终止其会话。 |
| pg_read_server_files | 使用 COPY 或其他文件访问功能时,允许读取文件【即那些在服务器上数据库可以访问的文件】。 |
| pg_write_server_files | 使用 COPY 或其他文件访问功能时,允许写入文件【即那些在服务器上数据库可以访问的文件】。 |
| pg_execute_server_program | 使用 COPY 或调用函数(函数将执行服务端程序)时,允许在数据库服务器上执行程序【以运行数据库的用户的身份来执行程序】。 |
| pg_checkpoint | 允许执行 CHECKPOINT 命令。 |
pg_monitor、pg_read_all_settings、pg_read_all_stats 和 pg_stat_scan_tables 角色旨在允许管理员轻松配置角色以监视数据库服务器。它们授予一组通用权限,允许角色读取通常仅限于超级用户的各种有用的配置设置、统计信息和其他系统信息。
pg_database_owner 角色具有一个隐式的、依赖于情境的成员,即当前数据库的所有者。与任何角色一样,它可以拥有对象或接收访问权限的授予。因此,一旦 pg_database_owner 在模板数据库中拥有权限,从该模板实例化的数据库的所有者都将行使这些权限。pg_database_owner 不能是任何角色的成员,并且不能具有非隐式成员。最初,此角色拥有(模板数据库) public 模式(schema),因此每个(从该模板实例化的)数据库所有者都管理 public 模式的本地使用。
pg_signal_backend 角色旨在允许管理员启用受信任但非超级用户的角色,以向其他后端发送信号。目前,此角色允许发送信号以取消另一个后端上的查询或终止其会话。但是,被授予此角色的用户无法向超级用户拥有的后端发送信号。
pg_read_server_files、pg_write_server_files 和 pg_execute_server_program 角色旨在允许管理员拥有受信任但非超级用户的角色,这些角色能够以运行数据库的用户身份访问文件,并在数据库服务器上运行程序。由于这些角色能够访问服务器文件系统上的任何文件,因此它们在直接访问文件时会绕过所有数据库级权限检查,并且可用于获得超级用户级访问权限,因此在向用户授予这些角色时应非常小心。
预定义角色的使用例子:
GRANT pg_signal_backend TO admin_user;
(6)函数安全
-
PostgreSQL 仅允许超级用户创建以
不可信语言编写的函数。
函数在后端服务器进程内运行,具有数据库服务器守护程序的操作系统权限。如果用于该函数的编程语言允许未经检查的内存访问,则可以更改服务器的内部数据结构。因此,此类函数可以绕过任何系统访问控制。允许进行此类访问的函数语言,被视为“不可信”语言。 -
严格控制谁可以定义对象。
函数、触发器和行级安全策略允许用户将代码插入到后端服务器中,其他用户可能会无意中执行这些代码。因此,最强大的保护措施是严格控制谁可以定义对象。 -
仅对
受信任所有者拥有的对象进行查询。
从 search_path 中删除相关 schema——这些 schema 允许不受信任的用户创建对象。
3、grant 和 revoke
(1)grant
GRANT 命令有两个基本变体:一个用于角色的权限管理,另一个用于角色的成员管理。
grant A on B to C [ WITH GRANT OPTION ] [ GRANTED BY role_specification ];
GRANT D TO E [ WITH { ADMIN | INHERIT | SET } { OPTION | TRUE | FALSE } ] [ GRANTED BY role_specification ]
注:
- 方括号 [] 代表可选内容;
- 如果指定了 GRANTED BY,则指定的授权者必须是当前用户。此子句当前以此形式存在,仅用于 SQL 兼容性。
即 role_specification 可以是: [ GROUP ] role_name | PUBLIC | CURRENT_ROLE | CURRENT_USER | SESSION_USER