分享到

简介

PostgreSQL 使用各种机制在数据库集群中实现身份验证授权和对象所有权。其中核心概念是角色。

PostgreSQL 角色是将用户和组的概念组合成一个单一、灵活的实体。它们是用户在数据库系统中采用的角色,是身份验证系统接受或拒绝连接的实体,也是所有范围的权限管理规则的主题。

本指南将介绍什么是角色以及如何在 PostgreSQL 数据库集群中管理角色。更具体地说,本指南将介绍与角色属性相关的角色管理。要更广泛地了解角色如何融入更大的图景,请查看身份验证和授权指南简介。要了解如何更改特定数据库对象上的角色权限,请查看我们关于角色授权的指南。

什么是角色?

在 PostgreSQL 中,角色是特定能力、权限和“拥有”实体的分组。PostgreSQL 使用角色来表示“用户”和“组”这两个概念,而不是使用不同的概念。“角色”可以对应于现实世界中的个人,也可以作为具有某些访问权限的组运作,其他角色可以成为该组的成员。

角色是 PostgreSQL 中确定身份验证和授权策略应用于谁的锚点。任何不普遍适用的策略都需要身份概念来定义限制谁和允许谁。在 PostgreSQL 中,此身份由角色表示。

PostgreSQL 的身份验证系统有许多不同的组件,每个组件都与角色相关联。为了用于初始连接到数据库集群,角色必须首先设置 LOGIN 属性。身份验证规则本身在名为 pg_hba.conf 的基于主机的配置文件中定义。每个规则定义了可能作用于单个角色的身份验证方法。对于配置为密码身份验证的角色,必须设置密码属性,以便系统可以验证提供的用户密码。

在授权方面,角色是在数据库集群级别定义的,在 PostgreSQL 中,这意味着它们在数据库之间共享。由于角色跨越数据库,因此授权系统控制每个角色对每个数据库实体的访问级别。由于角色可以代表人群组,因此访问配置方式非常灵活。

角色对于 PostgreSQL 中对象所有权的概念也至关重要。例如,每个数据库和表都恰好有一个角色配置为所有者。除了 superusers 之外,所有者角色是唯一可以修改或删除实际对象的角色。

总而言之,角色是大多数实际数据库操作的核心。它们的灵活性使它们既可以充当用户标识符,又可以充当用户类。数据库集群中的每个操作都会根据角色的权限进行检查,并且每次连接到数据库集群的成功与否都取决于角色身份验证。重要的是要很好地掌握角色管理,因为它在如此多的核心操作中都非常重要。

角色属性

角色属性是角色本身的标志,它决定了角色在数据库集群级别上的一些核心权限。这些属性可以在角色最初创建时设置,也可以随时由具有适当属性的角色(在本例中为 SUPERUSERCREATEROLE)更改。

可以应用于角色的属性包括

  • LOGIN:允许用户使用此角色初始连接到数据库集群。CREATE USER 命令自动添加此属性,而 CREATE ROLE 命令则不添加。
  • SUPERUSER:允许角色绕过所有权限检查,除了登录权限。只有其他 SUPERUSER 角色才能创建具有此属性的角色。
  • CREATEDB:允许角色创建新数据库。
  • CREATEROLE:允许角色创建、更改和删除其他角色。此属性还允许角色分配或更改角色成员身份。例外情况是,没有 SUPERUSER 属性的角色无法更改 SUPERUSER 角色。
  • REPLICATION:允许角色启动流复制。具有此属性的角色还必须具有 LOGIN 属性。
  • PASSWORD:为角色分配一个密码,该密码将与 passwordmd5 身份验证机制一起使用。此属性在属性关键字后直接将带引号的密码作为参数。
  • INHERIT:确定角色是否继承其所属角色的权限。如果没有 INHERIT,成员必须使用 SET ROLE 才能更改为其他角色,以便访问这些独占权限。默认情况下,为新角色设置此属性。

您可以通过查看 PostgreSQL 关于角色属性CREATE ROLE 命令的文档来了解有关角色属性的更多信息。

什么是 superuser 角色?

如上文简要提及,名为 superuser 的特殊权限允许对数据库集群进行无限制的管理访问。这类似于 Linux 和类 Unix 操作系统中的 root 帐户,但在数据库级别。

每个数据库集群中必须始终至少有一个具有 superuser 权限的角色。初始 superuser 帐户在安装过程中创建。初始 superuser 帐户的名称可能因安装过程而异,但最常见的是,此帐户称为 postgres

不建议使用具有 superuser 权限的帐户进行日常工作,这既是因为它可能导致破坏性操作,也是为了最大限度地减少泄露具有广泛访问权限的帐户的机会。相反,在大多数情况下,用户应使用专用于他们正在处理的特定功能或数据对象的帐户,仅在需要更强大的访问权限时才使用 superuser 帐户。

检查现有角色属性

现在您已经大致了解了角色属性是什么以及它们允许的权限类型,您应该学习如何查找应用于整个 PostgreSQL 中角色的属性。本节将向您展示一些命令,以帮助您查找通常在角色上以及专门在您自己的当前角色上设置的属性。

列出所有数据库角色及其属性

有几种不同的方法可以检查应用于整个系统的角色的属性。

如果您正在使用 psql 命令行客户端,则可以利用一些有用的元命令,这些元命令允许您在没有查询的情况下获取角色属性信息。

\du 元命令显示所有角色及其属性

\du
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}

在本例中,postgres 角色是默认角色,为此数据库集群配置了 superuser 权限。

列出角色的等效 SQL(通过在启动 psql 时传递 -E--echo-hidden 标志可发现)是

SELECT r.rolname, r.rolsuper, r.rolinherit,
r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,
r.rolconnlimit, r.rolvaliduntil,
ARRAY(SELECT b.rolname
FROM pg_catalog.pg_auth_members m
JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)
WHERE m.member = r.oid) as memberof
, r.rolreplication
, r.rolbypassrls
FROM pg_catalog.pg_roles r
WHERE r.rolname !~ '^pg_'
ORDER BY 1;

下面是一个类似的查询,它提供角色属性信息(没有角色成员资格组件)。我们在此处使用 psql 元命令 \x on 垂直输出结果,以便更好地阅读

-- turn on vertical display
\x on
SELECT * FROM pg_roles WHERE rolname !~ '^pg_';
-- turn off vertical display
\x off
-[ RECORD 1 ]--+---------
rolname | postgres
rolsuper | t
rolinherit | t
rolcreaterole | t
rolcreatedb | t
rolcanlogin | t
rolreplication | t
rolconnlimit | -1
rolpassword | ********
rolvaliduntil |
rolbypassrls | t
rolconfig |
oid | 10

如果您只对查看哪些角色具有 superuser 属性感兴趣,您可以显式请求列表

SELECT rolname FROM pg_roles WHERE rolsuper;
rolname
----------
postgres
(1 row)

或者,您可以列出所有用户及其 superuser 状态,以获得更完整的画面

SELECT usename,usesuper FROM pg_user;
usename | usesuper
----------+----------
postgres | t
user1 | f
(2 rows)

可以使用 PostgreSQL 的“角色”范例而不是其(有时含糊不清的)“用户”覆盖来检索相同的信息,而是使用以下稍长的查询

SELECT rolname,rolsuper FROM pg_roles WHERE rolname !~ '^pg_';
rolname | rolsuper
----------+----------
postgres | t
user1 | f
(2 rows)

列出您自己的属性

如果您想查找当前正在使用的角色的属性,可以轻松过滤输出。

使用 psql 元命令时,可以使用 USER 变量,该变量将被替换为当前连接的角色。psql 使用冒号 (:) 来插值变量

\du :USER
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}

要获取显示所有可能的角色属性值的列表,可以使用将角色名称与CURRENT_ROLE PostgreSQL 函数返回的值进行比较的查询。同样,我们使用垂直输出以提高可读性

-- First, turn on vertical output
\x on
SELECT * FROM pg_roles WHERE rolename = CURRENT_ROLE;
-- Change back to normal output
\x off
-[ RECORD 1 ]--+---------
rolname | postgres
rolsuper | t
rolinherit | t
rolcreaterole | t
rolcreatedb | t
rolcanlogin | t
rolreplication | t
rolconnlimit | -1
rolpassword | ********
rolvaliduntil |
rolbypassrls | t
rolconfig |
oid | 10

要仅检查您当前的角色是否具有 superuser 权限,可以键入

SHOW is_superuser;
is_superuser
--------------
on
(1 row)

检查您是否具有角色管理权限

要创建、更改或删除角色,您必须具有 superuserCREATEROLE 权限。

要检查系统中哪些角色具有角色管理权限,请键入

SELECT rolname as "Users who can manage roles" FROM pg_roles WHERE rolsuper OR rolcreaterole;
Users who can manage roles
----------------------------
postgres
(1 rows)

如果您只想知道您当前的角色是否具有角色管理权限,则可以改为使用

SELECT 'Yes' AS "Can I manage roles?" FROM pg_roles WHERE rolname = :'USER' AND (rolsuper OR rolcreaterole);
Can I manage roles?
---------------------
Yes
(1 row)

创建角色

验证您具有角色管理权限后,您可以开始在 PostgreSQL 中创建、修改或删除角色。

设置角色属性的一种方法是在创建角色时声明它们。这允许您设置角色的初始条件,但如果您想更改角色的访问级别,仍然可以在之后修改它们。您可以找到有关CREATE ROLE 命令的更多信息,我们将使用该命令来熟悉基本语法。

创建角色的一种方法是从命令行。PostgreSQL 包括一个 createuser 命令,该命令将在数据库集群中创建一个具有 LOGIN 权限的角色。

一般语法是

createuser <options> <rolename>

例如,要创建一个名为 admin 且具有 superuser 权限的角色,同时提示输入密码,您可以键入

createuser --superuser admin

然后,您将能够根据pg_hba.conf 文件中概述的身份验证方法,使用 admin 帐户登录。

要使用 SQL 创建角色,一般语法如下所示

CREATE ROLE <role>;

可以通过在角色名称后使用 WITH 来定义属性

CREATE ROLE <role> WITH <options>;

例如,要创建一个名为 user1 且可以使用密码 secretpassword 登录的角色,您可以键入

CREATE ROLE "user1" WITH LOGIN PASSWORD 'secretpassword';

要改为创建一个具有 superuser 权限(您还必须是 superuser 才能成功执行此命令)但不能登录的角色(用户必须使用 SET ROLE 才能更改为该角色),您可以键入

CREATE ROLE "user2" WITH SUPERUSER;

更改现有角色

要修改现有角色的属性,您可以改用 ALTER ROLE 命令。与角色创建一样,您当前的角色还必须具有 superuserCREATEROLE 权限。没有这些权限的用户只能使用 ALTER ROLE 命令来更改自己的密码。

更改角色允许您在创建后更改分配给角色的属性。角色创建部分中提到的相同属性可以与 ALTER ROLE 语法一起使用。一个区别是,每个属性类型都可以通过添加 NO 前缀来否定。例如,要允许角色登录到数据库集群,您可以为其赋予 LOGIN 属性。要删除该能力,您可以通过指定 NOLOGIN 来更改角色。

ALTER ROLE 命令仅更改显式提及的属性。换句话说,ALTER ROLE 命令指定对属性的更改,而不是完整的新属性集。

要允许 user2 角色登录到数据库集群,您可以键入

ALTER ROLE "user2" WITH LOGIN;

请记住,虽然这启用了登录能力,但允许的身份验证方法仍然由 pg_hba.conf 文件控制。

如果您希望 user2 能够登录、创建角色和创建数据库,则可以指定这三个属性,以空格分隔

ALTER ROLE "user2" WITH LOGIN CREATEROLE CREATEDB;

要撤销角色的 superuser 状态(您只能使用另一个 superuser 角色执行此命令),请键入

ALTER ROLE "user2" WITH NOSUPERUSER;

要更改角色的密码,您可以键入以下命令(所有角色都应该能够对其自身角色执行此命令,而与 CREATEROLEsuperuser 权限无关)

ALTER ROLE <role> WITH PASSWORD '<password>';

虽然上面的命令有效,但如果可能,最好使用 psql 元命令来更改密码。psql 命令自动提示输入密码并在将其发送到服务器之前对其进行加密。这有助于避免在日志中泄露敏感数据。

您可以使用 psql 通过键入以下命令来更改角色的密码

-- To change your own password
\password
-- To change the password for another role
\password <role>

您还可以使用 ALTER ROLE 命令来重命名角色

ALTER ROLE <role> RENAME TO <newrole>

请记住,您无法重命名当前会话角色。

删除角色

删除现有角色遵循与先前命令类似的模式。同样,您必须具有 CREATEROLEsuperuser 权限才能执行这些命令。

一个复杂的因素是,如果角色仍然被数据库中的对象引用,则无法删除角色。这意味着您必须删除或转移角色拥有的任何对象的所有权。之后,您还必须撤销角色对数据库对象的任何其他权限。

Database Administrators Stack Exchange 网站上的 Erwin Brandstetter 提供了关于如何适当地重新分配和删除权限的详细说明。以下使用了相同的过程。

首先,您可以使用 REASSIGNED OWNED 命令重新分配角色的所有已拥有对象。例如,如果您准备删除 user2 角色,则可以通过键入以下命令将其对象分配给 postgres 角色

REASSIGN OWNED BY "user2" TO "postgres";

现在对象归 postgres 所有,我们可以使用 DROP OWNED 命令来撤销我们已被授予的对象上的所有其他权限。此命令还会删除我们拥有的任何对象,但由于我们刚刚将它们转移到 postgres 角色,因此 user2 角色不再拥有任何对象。因此,该命令将仅撤销角色的任何其他权限

DROP OWNED BY "user2";

如果没有上面的 DROP OWNED 快捷方式,您将必须对角色具有权限的每个单独对象或对象类型执行 REVOKE ALL PRIVILEGES

撤销所有关联的权限后,您可以通过键入以下命令删除角色

DROP ROLE "user2";

使用 psql 登录

配置新角色并使用 pg_hba.conf 文件配置身份验证详细信息后,您可以使用新角色登录到数据库集群。psql 命令行客户端提供了一种简单的方法来执行此操作。

默认情况下,psql 假定您要使用与您的操作系统用户名匹配的角色进行连接。因此,如果您以 john 身份登录到计算机,psql 将假定您要尝试使用也称为 john 的角色连接到数据库。

要覆盖此行为,您可以传递 -U--username= 选项。例如,如果您要登录到名为 kerry 的角色,则可以键入

psql -U kerry

psql 命令的成功与否取决于 kerry 角色是否存在、您尝试连接的服务器是否可访问,以及服务器上定义的身份验证规则。

在会话期间更改为不同的角色

有时,您可能希望临时采用您有权访问的另一个角色的权限和身份。例如,如果您想获得您所属角色的权限,而您当前的角色没有 INHERIT 属性,则这是必要的。

要理解这是如何工作的,您必须了解 PostgreSQL 用于对活动角色进行分类的术语

  • 会话角色:会话角色是指您在初始连接到 PostgreSQL 数据库集群时登录所使用的角色。它设置您的初始权限并决定您对系统的访问权限。此角色必须具有 LOGIN 属性。
  • 当前角色:相比之下,当前角色是您当前正在扮演的角色。与当前角色关联的权限(无论是直接设置还是从其他角色继承)决定了您允许执行的操作以及您有权访问的对象。

您可以通过键入以下内容来查看您的会话角色和当前角色值

SELECT SESSION_USER, CURRENT_USER;
current_user | session_user
--------------+--------------
postgres | postgres
(1 row)

虽然更改会话角色的唯一方法是使用不同的角色启动新连接,但您可以使用 SET ROLE 命令来更改当前角色。SET ROLE 命令用于临时充当不同的角色。该命令还可以选择以下修饰符

  • SESSION:默认设置。这将导致 SET ROLE 命令影响整个数据库会话。
  • LOCAL:此修饰符将使命令仅针对当前事务更改角色。

要将当前角色更改为 user2 角色(对于会话的其余部分),请键入

SET ROLE "user2";

如果您检查您的会话角色和当前角色值,您将看到当前角色值已更改

SELECT SESSION_USER, CURRENT_USER;
current_user | session_user
--------------+--------------
user2 | postgres
(1 row)

您的所有操作现在都将使用 user2 角色作为其上下文。

要更改回您先前使用的会话角色,您可以键入

SET ROLE NONE;

另一种实现相同结果的方法是

RESET ROLE;

结论

PostgreSQL 的角色、角色属性、授权和身份验证系统创建了一个灵活的系统,使管理员能够有效地管理权限和数据库访问。本指南描述了角色究竟是什么,以及它们如何涵盖广泛的用例。它还介绍了如何创建、修改和删除角色,以及管理决定其全局能力的角色属性。了解如何管理这些身份对于保护您的数据库并为您的合法用户提供可用的访问权限是必要的。

常见问题解答

要在 PostgreSQL 中更改角色的密码,您可以使用带有 PASSWORDALTER 语句。语法如下所示

ALTER ROLE <role> WITH PASSWORD '<password>';

或者,您也可以使用 psql 元命令,如下所示

- To change your own password
\password
-- To change the password for another role
\password <role>

要查找当前角色的属性,您可以将 psql 元命令与 USER 变量一起使用,该变量将替换为当前连接的角色。

基本语法和结果如下所示

\du :USER
List of roles
Role name | Attributes | Member of
-----------+------------------------------------------------------------+-----------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}

要检查角色是否可以授予用户权限或创建角色,您可以使用以下 SQL 语句

SELECT rolname as "Users who can manage roles" FROM pg_roles WHERE rolsuper OR rolcreaterole;

要检查您的用户是否具有这些权限,您可以使用以下语句

SELECT 'Yes' AS "Can I manage roles?" FROM pg_roles WHERE rolname = :'USER' AND (rolsuper OR rolcreaterole);

REPLICATION 是 PostgreSQL 中的一个角色属性,它允许角色启动流式复制

具有此属性的角色还必须具有 LOGIN 属性。

您可以使用 CREATE ROLE 命令在 PostgreSQL 中创建角色。

基本语法如下所示

CREATE ROLE <role>;

以及带有属性的语法

CREATE ROLE <role> WITH <options>;
关于作者
Justin Ellingwood

Justin Ellingwood

自 2013 年以来,Justin 一直在撰写关于数据库、Linux、基础设施和开发者工具的文章。他目前与妻子和两只兔子住在柏林。他通常不必以第三人称写作,这让各方都感到欣慰。