PostgreSQL教程(二十四):服务器管理(六)之数据库角色

PostgreSQL使用角色的概念管理数据库访问权限一个角色可以被看成是一个数据库用户或者是一个数据库用户组,这取决于角色被怎样设置角色可以拥有数据库对象(例如,表和函数)并且能够把那些对象上的权限赋予给其他角色来控制谁能访问哪些对象。此外,还可以把一个角色中的成员资格授予给另一个角色,这样允许成员角色使用被赋予给另一个角色的权限。

角色的概念把“用户”和“组”的概念都包括在内。在PostgreSQL版本 8.1 之前,用户和组是完全不同的两种实体,但是现在只有角色。任意角色都可以扮演用户、组或者两者。

本章描述如何创建和管理角色。

一、数据库角色

数据库角色在概念上已经完全与操作系统用户独立开来。事实上可能维护一个对应关系会比较方便,但是这并非必需。数据库角色在一个数据库集簇安装范围内是全局的(而不是独立数据库内)。要创建一个角色,可使用CREATE ROLE SQL 命令:

CREATE ROLE name;

name遵循 SQL 标识符的规则或是未经装饰没有特殊字符,或是用双引号包围(实际上,你将总是给该命令要加上额外选项,例如LOGIN。更多细节可见下文)。要移除一个已有的角色,使用相似的DROP ROLE命令:

DROP ROLE name;

为了方便,createuserdropuser程序被提供作为这些 SQL 命令的包装器,它们可以从 shell 命令行调用:

createuser name
dropuser name

要决定现有角色的集合,检查pg_roles系统目录,例如:

SELECT rolname FROM pg_roles;

psql程序的\du元命令也可以用来列出现有角色。

为了引导数据库系统,一个刚刚被初始化好的系统总是包含一个预定义角色。这个角色总是一个“superuser”,并且默认情况下(除非在运行initdb时修改)它的名字和初始化数据库集簇的操作系统用户相同。习惯上,这个角色将被命名为postgres。为了创建更多角色,你首先必须以初始角色的身份连接。

每一个到数据库服务器的连接都是使用某个特定角色名建立的,并且这个角色决定发起连接的命令的初始访问权限。要使用一个特定数据库连接的角色名由客户端指示,该客户端以一种应用相关的风格发起连接请求。例如,psql程序使用-U命令行选项来指定要以哪个角色连接。很多应用假定该名字默认是当前操作系统用户(包括createuserpsql)。因此在角色和操作系统用户之间维护一个名字对应关系通常是很方便的。

一个给定客户端连接能够用来连接的数据库角色的集合由该客户端的认证设置决定,这些在教程二十三中有解释(因此,一个客户端不止限于以匹配其操作系统用户的角色连接,就像一个人的登录名不需要匹配她的真实名字一样)。因为角色身份决定一个已连接客户端可用的权限集合,在设置一个多用户环境时要小心地配置权限。

二、角色属性

一个数据库角色可以有一些属性,它们定义角色的权限并且与客户端认证系统交互。

login privilege

        只有具有LOGIN属性的角色才能被用于一个数据库连接的初始角色名称。一个带有LOGIN属性的角色可以被认为和一个“数据库用户”相同。要创建一个带有登录权限的角色,使用两者之一:

CREATE ROLE name LOGIN;
CREATE USER name;

CREATE USERCREATE ROLE等效,除了CREATE USER默认假定有LOGIN,而CREATE ROLE不这样认为)。

superuser status

一个数据库超级用户会绕开所有权限检查,除了登入的权利。这是一个危险的权限并且应该小心使用,最好用一个不是超级用户的角色来完成你的大部分工作。要创建一个新数据库超级用户,使用CREATE ROLE name SUPERUSER。你必须作为一个超级用户来完成这些。

database creation

一个角色必须被显式给予权限才能创建数据库(除了超级用户,因为它们会绕开所有权限检查)。要创建这样一个角色,使用CREATE ROLE name CREATEDB

role creation

一个角色必须被显式给予权限才能创建更多角色(除了超级用户,因为它们会绕开所有权限检查)。要创建这样一个角色,使用CREATE ROLE name CREATEROLE。一个带有CREATEROLE权限的角色也可以修改和删除其他角色,还可以授予或回收角色中的成员关系。然而,要创建、修改、删除或修改一个超级用户角色的成员关系,需要以超级用户的身份操作。CREATEROLE不足以完成这一切。

initiating replication

一个角色必须被显式给予权限才能发起流复制(除了超级用户,因为它们会绕开所有权限检查)。一个被用于流复制的角色必须也具有LOGIN权限。要创建这样一个角色,使用CREATE ROLE name REPLICATION LOGIN

password

只有当客户端认证方法要求用户在连接数据库时提供一个口令时,一个口令才有意义。passwordmd5认证方法使用口令。数据库口令与操作系统命令独立。在角色创建时指定一个口令:CREATE ROLE name PASSWORD 'string'

在创建后可以用ALTER ROLE修改一个角色属性。CREATE ROLEALTER ROLE命令的细节可见参考页。

提示:

一个好习惯是创建一个具有CREATEDBCREATEROLE权限的角色,而不是创建一个超级用户,并且然后用这个角色来完成对数据库和角色的例行管理。这种方法避免了在非必要时作为超级用户操作任务的风险。

对于前面章节描述的运行时配置设置,一个角色也可以有角色相关的默认值。例如,如果出于某些原因你希望在每次连接时禁用索引扫描(提示:不是好主意),你可以使用:

ALTER ROLE myname SET enable_indexscan TO off;

这将保存设置(但是不会立刻设置它)。在这个角色的后续连接中,它就表现得像在会话开始之前执行过SET enable_indexscan TO off。你也可以在会话期间改变该设置,它将只是作为默认值。要移除一个角色相关的默认设置,使用ALTER ROLE rolename RESET varname。注意附加到没有LOGIN权限的角色的角色相关默认值相当无用,因为它们从不会被调用。

三、角色成员关系

把用户分组在一起来便于管理权限常常很方便:那样,权限可以被授予一整个组或从一整个组回收。在PostgreSQL中通过创建一个表示组的角色来实现,并且然后将在该组角色中的成员关系授予给单独的用户角色

要建立一个组角色,首先创建该角色:

CREATE ROLE name;

通常被用作一个组的角色不需要有LOGIN属性,不过如果你希望你也可以设置它。

一旦组角色存在,你可以使用GRANTREVOKE命令增加和移除成员:

GRANT group_role TO role1, ... ;
REVOKE group_role FROM role1, ... ;

你也可以为其他组角色授予成员关系(因为组角色和非组角色之间其实没有任何区别)。数据库将不会让你设置环状的成员关系。另外,不允许把一个角色中的成员关系授予给PUBLIC

组角色的成员可以以两种方式使用角色的权限。第一,一个组的每一个成员可以显式地做SET ROLE来临时“成为”组角色。在这种状态中,数据库会话可以访问组角色而不是原始登录角色的权限,并且任何被创建的数据库对象被认为属于组角色而不是登录角色。第二,有INHERIT属性的成员角色自动地具有它们所属角色的权限,包括任何组角色继承得到的权限。作为一个例子,假设我们已经有:

CREATE ROLE joe LOGIN INHERIT;
CREATE ROLE admin NOINHERIT;
CREATE ROLE wheel NOINHERIT;
GRANT admin TO joe;
GRANT wheel TO admin;

在作为角色joe连接后,一个数据库会话将立即拥有直接授予给joe的权限,外加任何授予给admin的权限,因为joe“继承了” admin的权限。然而,授予给wheel的权限不可用,因为即使joewheel的一个间接成员,但是该成员关系是通过带NOINHERIT属性的admin得到的。在:

SET ROLE admin;

之后,该会话将只拥有授予给admin的权限,但是没有授予给joe的权限。在执行:

SET ROLE wheel;

之后,该会话将只拥有授予给wheel的权限,但是没有授予给joeadmin的权限。初始的权限状态可以使用下面命令之一恢复:

SET ROLE joe;
SET ROLE NONE;
RESET ROLE;

注意:
 

SET ROLE命令总是允许选择原始登录角色的直接或间接组角色。因此,在上面的例子中,在成为wheel之前不必先成为admin

注意:
在 SQL 标准中,用户和角色之间的区别很清楚,并且用户不会自动继承权限而角色会继承。这种行为在PostgreSQL中也可以实现:为要用作 SQL 角色的角色给予INHERIT属性,而为要用作 SQL 用户的角色给予NOINHERIT属性。不过,为了向后兼容 8.1 以前的发布(在其中用户总是拥有它们所在组的权限),PostgreSQL默认给所有的角色INHERIT属性。

角色属性LOGINSUPERUSERCREATEDBCREATEROLE可以被认为是一种特殊权限,但是它们从来不会像数据库对象上的普通权限那样被继承。要使用这些属性,你必须实际SET ROLE到一个有这些属性之一的特定角色。继续上述例子,我们可以选择授予CREATEDBCREATEROLEadmin角色。然后一个以joe角色连接的会话将不会立即有这些权限,只有在执行了SET ROLE admin之后才会拥有。

要销毁一个组角色,使用DROP ROLE

DROP ROLE name;

任何在该组角色中的成员关系会被自动撤销(但是成员角色不会受到影响)。

四、删除角色

由于角色可以拥有数据库对象并且能持有访问其他对象的特权,删除一个角色 常常并非一次DROP ROLE就能解决。任何被该用户所拥有 的对象必须首先被删除或者转移给其他拥有者,并且任何已被授予给该角色的 权限必须被收回。

对象的拥有关系可以使用ALTER命令一次转移出去,例如:

ALTER TABLE bobs_table OWNER TO alice;

此外,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,它将发出 消息标识哪些对象需要被重新授予或者删除。

五、默认角色

PostgreSQL提供了一组默认角色,它们提供对特定的、通常需要的、需要特权的功能和信息的访问。管理员可以把这些角色GRANT给其环境中的用户或者其他角色,让这些用户能够访问指定的功能和信息。

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

表 5.1. 默认角色

角色 允许的访问
pg_read_all_settings 读取所有配置变量,甚至是那些通常只对超级用户可见的变量。
pg_read_all_stats 读取所有的pg_stat_*视图并且使用与扩展相关的各种统计信息,甚至是那些通常只对超级用户可见的信息。
pg_stat_scan_tables 执行可能会在表上取得ACCESS SHARE锁的监控函数(可能会持锁很长时间)。
pg_signal_backend 向其他后端发送信号(例如:取消查询、中止)。
pg_read_server_files 允许使用COPY以及其他文件访问函数从服务器上该数据库可访问的任意位置读取文件。
pg_write_server_files 允许使用COPY以及其他文件访问函数在服务器上该数据库可访问的任意位置中写入文件。
pg_execute_server_program 允许用运行该数据库的用户执行数据库服务器上的程序来配合COPY和其他允许执行服务器端程序的函数。
pg_monitor 读取/执行各种监控视图和函数。这个角色是pg_read_all_settingspg_read_all_stats以及pg_stat_scan_tables的成员。

pg_read_server_filespg_write_server_files以及pg_execute_server_program角色的目的是允许管理员有一些可信但不是超级用户的角色来访问文件以及以运行数据库的用户在数据库服务器上运行程序。由于这些角色能够防伪服务器文件系统上的任何文件,因此在直接访问文件时它们会绕过任何数据库级别的权限检查并且它们可以被用来得到超级用户级别的访问,因此在把这些角色授予给用户时应当非常小心。

pg_monitorpg_read_all_settingspg_read_all_statspg_stat_scan_tables角色的目的是允许管理员能为监控数据库服务器的目的很容易地配置角色。它们授予一组常用的特权,这些特权允许角色读取各种有用的配置设置、统计信息以及通常仅限于超级用户的其他系统信息。

在授予这些角色时应当非常小心,以确保它们只被用在需要的地方,并且要理解这些角色会授予对特权信息的访问。

管理员可以用GRANT命令把对这些角色的访问授予给用户:

GRANT pg_signal_backend TO admin_user;

六、函数和触发器安全性

函数、触发器以及行级安全性策略允许用户在后端服务器中插入代码,其他用户不会注意到这些代码的执行。因此,这些机制允许用户相对容易地为其他人设置“特洛伊木马”。最强的保护是严格控制哪些人能定义对象。如果做不到,则编写查询时应该只引用具有可信任拥有者的对象。可以从search_path中去除public方案以及任何其他允许不可信用户创建对象的方案。

在后端服务器进程中运行的函数带有数据库服务器守护进程的操作系统权限。如果用于函数的编程语言允许非检查的内存访问,它就可能改变服务器的内部数据结构。因此,在很多其他事情中,这些函数可能绕开任何系统访问控制。允许这种访问的函数语言被认为是“不可信的”,并且PostgreSQL只允许超级用户创建用这些语言编写的函数。

最近更新

  1. TCP协议是安全的吗?

    2024-03-15 04:22:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-15 04:22:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-15 04:22:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-15 04:22:03       18 阅读

热门阅读

  1. 【点云】激光点云建图评测

    2024-03-15 04:22:03       19 阅读
  2. OpenAI GPT-4.5 Turbo 泄露,六月或将发布

    2024-03-15 04:22:03       21 阅读
  3. 4. git 添加版本标签

    2024-03-15 04:22:03       21 阅读
  4. Oracle控制文件control file(1)控制文件概述

    2024-03-15 04:22:03       22 阅读
  5. 电子信息工程实践案例分析报告

    2024-03-15 04:22:03       20 阅读
  6. PHP伪协议详解

    2024-03-15 04:22:03       22 阅读
  7. LeetCode(力扣)算法题_2864_最大二进制奇数

    2024-03-15 04:22:03       19 阅读
  8. 2.Linux文件IO基础

    2024-03-15 04:22:03       20 阅读
  9. 查看Linux服务器配置

    2024-03-15 04:22:03       22 阅读
  10. leetcode:反转链表II 和k个一组反转链表的C++实现

    2024-03-15 04:22:03       22 阅读
  11. 网络学习DAY3--TCP并发

    2024-03-15 04:22:03       20 阅读
  12. LeetCode2864. Maximum Odd Binary Number

    2024-03-15 04:22:03       25 阅读
  13. 动态规划 Leetcode 494 目标和

    2024-03-15 04:22:03       20 阅读
  14. 缓存穿透和缓存击穿有什么区别?

    2024-03-15 04:22:03       22 阅读