用户权限体系

与PostgreSQL兼容的权限体系

ProtonBase 实现和 PostgreSQL 兼容的完整权限体系来保证细粒度的权限控制,让用户可以对各种数据库对象进行权限的管理。

用户、角色

Protonbase 数据库中的用户、角色在概念上与标准 Postgres 的用户、角色概念基本相同。按作用域可划分为 Global User & Local User/Local Role, 示例如下图:

如上图所示,在Protonbase云平台中,GlobalUser是全局可见的,可以在任何Database中引用GlobalUser,对比LocalUser & LocalRole则只能在Database内可见。不同于以往的数据库产品,由于User & Role信息是记录在每个Database内部,所以Database间没有共享的User & Role信息。

Global User, Local User, Local Role的详细区别如下表(User/Role差异表):

类型属性功能权限
passwordsuperusercreatedbcreateroleinheritconnect
parentofmemberof
Global User
Local User
Local Role

属性: 参考章节 角色属性

功能: 参考章节 角色管理

权限: 参考章节 权限列表

为简化后续描述,如无特殊说明GlobalUser, LocalUser, LocalRole均使用 角色 代指。

角色属性

数据库角色可以具有多个属性,定义其特权并与客户端做身份验证交互。详细的属性描述如下:

PASSWORD (密码)

具有密码属性的角色一般为用户类型,当该用户持有当前Database的CONNECT权限后,则可以登录数据库。

注意GlobalUser的password存储在平台服务里,并不能通过SQL方式管理GlobalUser的密码。

SUPERUSER | NOSUPERUSER(超级用户)

数据库超级用户属性绕过所有权限检查,除了登录权限。这是一个危险的特权,不应该随意使用;最好将大部分工作作为一个不是超级用户的角色来完成。 要创建一个新的数据库超级用户,使用CREATE ROLE name SUPERUSER。您必须以已经是超级用户的角色来执行此操作。

CREATEDB | NOCREATEDB (数据库创建)

角色必须明确获得权限才能创建数据库(超级用户除外,因为他们可以绕过所有权限检查)。 要创建这样的角色,请使用CREATE ROLE name CREATEDB

CREATEROLE | NOCREATEROLE (角色创建)

角色必须明确获得权限才能创建更多的角色(除了超级用户,因为他们可以绕过所有权限检查)。 要创建这样的角色,请使用CREATE ROLE name CREATEROLE。 拥有CREATEROLE特权的角色也可以修改和删除其他角色,以及授予或撤销其成员资格。 修改角色包括大多数可以使用ALTER ROLE进行的更改,例如更改密码。 还包括可以使用COMMENTSECURITY LABEL命令进行的对角色的修改。

然而,CREATEROLE并不包含创建SUPERUSER角色的能力, 也不包含对已经存在的SUPERUSER角色的任何控制权。

因为CREATEROLE权限允许用户授予或撤销即使在尚未具有任何访问权限的角色中的成员身份,一个CREATEROLE用户可以获得对系统中每个预定义角色(参考章节预定义角色)的访问权限,包括高度特权角色。

角色管理

数据库中角色具备继承能力,可通过将授权的方式将角色的能力(权限集合,继承关系)授与其它角色,对应的反向操作为撤销授权。

如表《User/Role差异表》中所示,不可以将GlobalUser授权给其它人。

角色的授权限制如下图所示:

限制1: GlobalUser只可以为叶子节点,不可以是父节点

限制2: 授权成功后产生了环(自己是自己的祖先节点)

角色管理操作权限检查

角色管理操作时需要做权限检查, 检查当前角色是否具有执行操作的权限,检查的逻辑如下表:

操作权限检查
create user/role
drop user/role
alter user/role
grant role
revoke role

创建User、Role

可通过命令CREATE ROLE创建一个角色,创建命令如下:

CREATE ROLE name [ [ WITH ] option [ ... ] ]
 
这里 option 可以是:
 
      SUPERUSER  | NOSUPERUSER
    | CREATEDB   | NOCREATEDB
    | CREATEROLE | NOCREATEROLE

示例:

创建一个SUPERUSER属性的ROLE

CREATE ROLE role1 WITH SUPERUSER;

创建一个复合属性的ROLE

CREATE ROLE role1 WITH SUPERUSER CREATEDB CREATEROLE;

创建一个LocalUser

命令CREATE USER是命令CREATE ROLE 的别称,区别在于可选的Option中增加了PASSWORD属性用于指定User的密码,示例如下:

CREATE USER localuser WITH PASSWORD 'warebase';

创建一个GlobalUser

使用命令CREATE USER创建GlobalUser, 区别于创建LocalUser,创建时不能为GlobalUser指定PASSWORD属性,示例如下:

CREATE USER "document@protonbase.io" WITH SUPERUSER;

删除User、Role

DROP ROLE|USER命令可用于删除一个数据库角色。

DROP USER [ IF EXISTS ] name [, ...]

修改User、Role属性

ALTER ROLE|USER命令可用于修改一个角色的属性。

ALTER ROLE myname WITH NOSUPERUSER;

角色组

角色组用于表达一组具有相同特征的用户、角色集合,在同一个用户组的用户、角色可继承使用角色组的权限。LocalUser/LocalRole 均具有用户组的能力,注意 GlobalUser 只能是角色组的成员。

授权

命令GRANT role_group TO role1, ... [WITH admin OPTION];可以把角色加入到某个角色组中,示例如下:

GRANT group_role TO other_role [WITH admin OPTION];

WITH admin OPTION: 授予角色other_role对角色group_role的授权、取消授权的能力。

取消授权

命令REVOKE role_group from role1;可以把角色role1从role_group中移除

默认角色组 PUBLIC

PUBLIC 是一个默认的权限组,代表当前Database中的所有角色,不可以通过GRANT、REVOKE命令管理PUBLIC角色组中的成员。

预定义角色

数据库中默认提供了一组预定义角色,它们提供对特定的、通常需要的、需要特权的功能和信息的访问。 管理员(包括具有CREATEROLE 权限的角色)可以把这些角色GRANT给其环境中的用户或者其他角色,让这些用户能够访问指定的功能和信息。

下表中描述了预定义的角色。 注意由于额外功能的增加,每一种角色相关的权限可能会在未来被改变。 管理员应该关注发行注记中提到的这方面的变化。

角色允许的访问
pg_read_all_data读所有数据(表,视图,序列), 如同在那些对象上有 SELECT 权限,在所有模式上有USAGE权限,即使没有显式拥有它。
pg_write_all_data写全部数据(表,视图,序列), 如果在那些对象上有INSERTUPDATEDELETE权限,以及在全部模式上有USAGE权限,即使没有显式拥有它。
pg_read_all_stats读取所有的pg_stat_*视图并且使用与扩展相关的各种统计信息,甚至是那些通常只对超级用户可见的信息。
pg_monitor读取/执行各种不同的监控视图和函数。 这角色是pg_read_all_settingspg_read_all_stats的成员。
pg_database_owner无成员构成,隐式的,当前数据库的所有者。
pg_checkpoint允许执行CHECKPOINT命令。

pg_database_owner: 该角色为逻辑角色,表示为当前database的owner, 不可以显式的对它进行授权或撤销授权操作操作。

权限

一旦一个对象被创建,它会被分配一个所有者。所有者通常是执行创建语句的角色。对于大部分类型的对象,初始状态下只有所有者(或者超级用户)能够对该对象做任何事情。为了允许其他角色使用它,必须分配权限

有多种不同的权限:SELECTINSERTUPDATEDELETETRUNCATEREFERENCESTRIGGERCREATECONNECTTEMPORARYEXECUTE以及USAGE。可以应用于一个特定对象的权限随着对象的类型(表、函数等)而不同。 有关这些权限含义的更多详细信息请参阅下文。后续的章节将介绍如何使用这些权限。

修改或销毁一个对象的权利是作为该对象的所有者所固有的,不能授予或撤销其本身。

对象权限设计

一个对象可以通过该对象类型相应的ALTER命令来重新分配所有者,例如

ALTER TABLE table_name OWNER TO new_owner;

与角色管理一致,具有SUPERUSER属性的角色总是可以做到这点,普通角色只有同时是对象的当前所有者(或者是拥有角色的一个成员)以及新拥有角色的一个成员时才能做同样的事。

要分配权限,可以使用GRANT命令。例如,如果joe是一个已有角色,而accounts是一个已有表,更新该表的权限可以按如下方式授权:

GRANT UPDATE ON accounts TO joe [WITH grant OPTION];

WITH grant OPTION: joe可以继续grant UPDATE权限给其它用户

ALL取代特定权限会把与对象类型相关的所有权限全部授权。

一个特殊的名为PUBLIC的“角色”可以用来向系统中的每一个角色授予一个权限(参考1.2.4.3 默认角色组PUBLIC)

要撤销以前授予的特权,请使用恰当命名的REVOKE命令:

REVOKE ALL ON accounts FROM PUBLIC;

一般情况下,只有对象拥有者(或者超级用户)可以授予或撤销一个对象上的权限。但是可以在授予权限时使用“with grant option”来允许接收人将权限转授给其他人。如果后来授予选项被撤销,则所有从接收人那里获得的权限(直接或者通过授权链获得)都将被撤销。

对象的所有者可以选择撤销自己的普通特权,例如,令表对于自己和其他人只读。 但是所有者总是被视为拥有所有的授予选项,所以他们总是可以重新授予自己的特权。

权限列表

有效的权限如下:

权限说明
SELECT允许 SELECT 从任何列、或特定的列、表、视图、物化视图、或其他类似表格的对象。 也允许使用COPY TO。 还需要这个权限来引用UPDATEDELETE中现有的列值。 对于序列,这个权限还允许使用currval 函数。对于大对象,此权限允许读取对象。
INSERT允许将新行的INSERT加入表、视图等等。 可以在特定列上授予,在这种情况下INSERT命令中只有那些列可以被分配(其他列将因此而收到默认值)。 还允许使用COPY FROM
UPDATE允许 UPDATE 更新任何列、或指定列、表、视图等等。 (实际上,任何有效的UPDATE命令也需要SELECT权限,因为它必须引用表列来确定要更新的行,和/或计算列的新值。) SELECT ... FOR UPDATESELECT ... FOR SHARE除了SELECT权限外,还需要至少一列上的这个权限。 对于序列,这个权限允许使用 nextvalsetval 函数。对于大对象,此权限允许写入或截断对象。
DELETE允许 DELETE 从表、视图等等中删除行. (实际上,任何有效的DELETE命令也需要SELECT权限,因为它必须引用表列来确定要删除的行。)
TRUNCATE允许在表上TRUNCATE
REFERENCES允许创建引用表或表的特定列的外键约束。
CREATE对于Database对象,允许在数据库中创建新的模式和发布,并允许在数据库中安装受信任的扩展。对于Schema对象,允许在表空间中创建表、索引和临时文件,并允许创建将表空间作为默认表空间的数据库。注意,取消该特权不会改变现有对象的存在或位置。
CONNECT允许受让者连接到数据库。
TEMPORARY允许在使用数据库时创建临时表。
USAGE对于Schema对象,允许操作引用表空间下的Table, Sequence等对象

在创建对象时,Protonbase数据库默认将某些类型对象的权限授予PUBLIC。 默认情况下,在表、表列、序列、或表空间上,不向PUBLIC授予权限。 对于其他类型的对象,授予 PUBLIC的默认权限如下所示: 针对数据库的CONNECTTEMPORARY(创建临时表)权限; 当然,对象所有者可以REVOKE默认权限和特别授予的权限。 (为了最大程度的安全性,在创建对象的同一事务中发出REVOKE;那么就没有其他用户能够使用该对象的窗口。) 此外,可以使用ALTER DEFAULT PRIVILEGES命令取代这些默认权限设置。

ACL (Access Control List)

下表显示了ACL(访问控制列表)值中用于这些权限类型的单字母缩写。 你将在下面列出的 psql 命令的输出中,或者在查看系统目录的 ACL 列时看到这些字母。

权限缩写适用对象类型
ADMINMSchema, Table, Sequence
SELECTr (“读”)SEQUENCE, TABLE (and table-like objects), table column
INSERTa (“增补”)TABLE, table column
UPDATEw (“写”)SEQUENCE, TABLE, table column
DELETEdTABLE
TRUNCATEDTABLE
REFERENCESxTABLE, table column
CREATECDATABASE, SCHEMA
CONNECTcDATABASE
TEMPORARYTDATABASE
USAGEUSCHEMA, SEQUENCE

ACL 规则

数据库中每一个对象都记录了对应的ACL条目,用于做权限检查,标准的ACL定义格式如下:

acl_item: Grantee=Privilege[*][Privilege[*]].../Grantor

Grantee: 被授予人,空代表为系统保留角色

Privilege:权限简写,参考《表2.3》中缩写列,当权限后跟着字符'*'代表被授予人可继续将该权限授予他人。

Grantor: 权限授予人, 空代表权限授予人是系统保留角色

完整的ACL是一个列表,定义如下:

acl: {acl_item[,acl_item]...}

示例如下:

{=rx/,public=rx/, joe=r*x*/owner, nick=rx/owner,owner=rxcd/owner}

上述例子中,对象的owner将该对象的rx权限分别授予了nick, 以及joe,同时角色joe具备继续授权该权限的能力。注意例子中 owner=rxcd/owner表示的是owner作为对象的创建者持有默认的所有权限,以及授权给他人的权限。

授权

GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
    [, ...] | ALL [ PRIVILEGES ] }
    ON { [ TABLE ] table_name [, ...]
         | ALL TABLES IN SCHEMA schema_name [, ...] }
    TO role_specification [, ...] [ WITH GRANT OPTION ]
 
GRANT { { USAGE | SELECT | UPDATE }
    [, ...] | ALL [ PRIVILEGES ] }
    ON { SEQUENCE sequence_name [, ...]
         | ALL SEQUENCES IN SCHEMA schema_name [, ...] }
    TO role_specification [, ...] [ WITH GRANT OPTION ]
 
GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
    ON DATABASE database_name [, ...]
    TO role_specification [, ...] [ WITH GRANT OPTION ]
 
GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
    ON SCHEMA schema_name [, ...]
    TO role_specification [, ...] [ WITH GRANT OPTION ]
    [ GRANTED BY role_specification ]
    
GRANT role_name [, ...] TO role_specification [, ...]
    [ WITH { ADMIN | } { OPTION | TRUE | FALSE } ]

取消授权

REVOKE [ GRANT OPTION FOR ]
    { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
    [, ...] | ALL [ PRIVILEGES ] }
    ON { [ TABLE ] table_name [, ...]
         | ALL TABLES IN SCHEMA schema_name [, ...] }
    FROM role_specification [, ...]
 
REVOKE [ GRANT OPTION FOR ]
    { { USAGE | SELECT | UPDATE }
    [, ...] | ALL [ PRIVILEGES ] }
    ON { SEQUENCE sequence_name [, ...]
         | ALL SEQUENCES IN SCHEMA schema_name [, ...] }
    FROM role_specification [, ...]
 
REVOKE [ GRANT OPTION FOR ]
    { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
    ON DATABASE database_name [, ...]
    FROM role_specification [, ...]
 
REVOKE [ GRANT OPTION FOR ]
    { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
    ON SCHEMA schema_name [, ...]
    FROM role_specification [, ...]
 
REVOKE [ { ADMIN } OPTION FOR ]
    role_name [, ...] FROM role_specification [, ...]

Table行级权限

CREATE POLICY — 为一个表定义一条新的行级安全性策略

CREATE POLICY name ON table_name
    [ AS { PERMISSIVE | RESTRICTIVE } ]
    [ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ]
    [ TO { role_name | PUBLIC | CURRENT_ROLE | CURRENT_USER | SESSION_USER } [, ...] ]
    [ USING ( using_expression ) ]
    [ WITH CHECK ( check_expression ) ]

CREATE POLICY为一个表定义一条行级安全性策略。注意为了应用已被创建的策略,在表上必须启用行级安全 性(使用ALTER TABLE ... ENABLE ROW LEVEL SECURITY)。

一条策略授予权限以选择、插入、更新或者删除匹配相关策略表达式的行。 现有的表行会按照USING中指定的表达式进行检查, 而将要通过INSERTUPDATE创建 的新行会按照WITH CHECK中指定的表达式进行检查。 当USING表达式对于一个给定行返回真时,该行对用户 可见,而返回假或空时该行不可见。当一个WITH CHECK 表达式对一行返回真时,该行会被插入或更新,而如果返回假或空时会发生 一个错误。

对于INSERTUPDATEMERGE语句, WITH CHECK表达式在 BEFORE触发器触发后执行, 并在进行任何实际数据修改之前执行。因此,BEFORE ROW触发器可能 修改要插入的数据,从而影响安全策略检查的结果。 WITH CHECK表达式在其他约束之前执行。

策略名称是针对每个表的。因此,一个策略名称可以被用于很多个不同的表 并且对于不同的表呈现适合于该表的定义。

更多内容参考行级安全策略