分享到

简介

使用 PostgreSQL 数据库时,您需要考虑的第一件事是如何连接并与数据库实例交互。这需要数据库客户端(您用来与数据库交互的组件)和数据库服务器(存储、组织和提供对数据的访问的实际 PostgreSQL 实例)之间的协调。

为了成功地管理此过程,您需要了解如何配置 PostgreSQL 实例以允许您所需的访问类型和 身份验证 方法。在本指南中,我们将介绍如何修改数据库服务器的身份验证机制以匹配您环境的要求。

在配套指南中,我们介绍了 如何使用数据库客户端连接到 PostgreSQL 实例。建议您阅读这两篇指南,以更全面地了解 PostgreSQL 中的身份验证机制。

了解 PostgreSQL 的身份验证文件

如果您想修改决定用户如何对 PostgreSQL 实例进行身份验证的规则,可以通过修改服务器的配置来实现。

需要修改的特定文件称为 pg_hba.conf

请注意,您需要重新启动 PostgreSQL 实例,才能使任何新的身份验证配置生效。不同的操作系统对此的处理方式不同。在大多数 Linux 发行版中,您可以输入 sudo systemctl restart postgresql。如果您通过 brew 安装了 PostgreSQL,可以尝试输入 brew services restart postgresql。在更广泛的系统上可能有效的替代方法是 pg_ctl restart

查找 pg_hba.conf 文件

要在服务器上找到 pg_hba.conf 文件,可以查看 PostgreSQL 配置目录。具体位置取决于您使用的操作系统和 PostgreSQL 版本。

如果您不知道身份验证配置文件的位置,但可以访问数据库,则可以查询 PostgreSQL 以获取文件位置,如 Craig Ringer 在此帖子中所演示的那样

如果您在命令行中,可以输入以下内容,它将查询 pg_hba.conf 文件的位置,并指示 PostgreSQL 仅打印文件位置,而不进行格式化

psql -t -P format=unaligned -c 'SHOW hba_file;'
/etc/postgresql/10/main/pg_hba.conf

如果您已经打开 PostgreSQL 会话,只需输入

SHOW hba_file;
hba_file
-------------------------------------
/etc/postgresql/10/main/pg_hba.conf
(1 row)

找到 pg_hba.conf 文件的位置后,在文本编辑器中打开它以查看配置并进行更改

vim /etc/postgresql/10/main/pg_hba.conf

默认情况下,该文件包含当前配置以及一些有用的注释。

了解 pg_hba.conf 文件格式

pg_hba.conf 文件使用纯文本实现的表格状结构。去除空行和注释后,基本文件可能如下所示

# TYPE DATABASE USER ADDRESS METHOD OPTIONS
local all postgres peer
local all all peer
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
local replication all peer
host replication all 127.0.0.1/32 md5
host replication all ::1/128 md5

让我们看看不同字段的含义以及如何解释文件内容。

如何构建和解释 pg_hba.conf 文件

pg_hba.conf 文件中的每一行都描述了客户端对系统进行身份验证的一种方式。每行的大部分内容描述了用于与传入连接请求进行比较的匹配条件。最后的组件指定了允许的身份验证方法以及身份验证所需的任何选项。

当 PostgreSQL 将连接请求与身份验证规则进行评估时,它是按顺序从上到下进行的。如果某行中的配置与连接请求的特性匹配,PostgreSQL 将使用该行中指定的身份验证信息来决定是否对客户端进行身份验证。

如果客户端成功进行身份验证,则将建立连接。如果身份验证失败,则连接将被拒绝。PostgreSQL 不会继续处理以查看是否有其他规则与请求匹配。因此,规则的顺序很重要。

在每行中,字段之间用空格隔开,可以使用空格或制表符。虽然将这些字段格式化为列通常在视觉上更有帮助,但 PostgreSQL 并不要求这样做。

pg_hba.conf 文件中每个字段的含义

现在您已经了解了文件结构和解析方式,我们可以开始讨论每个字段的含义。

我们将介绍以下字段:

  • 连接类型
  • 数据库
  • 用户名
  • 地址
  • 身份验证方法
  • 身份验证方法选项

连接类型

每条记录的第一个字段指定要匹配的连接请求类型。只有使用指定连接的连接才会匹配每条规则。

连接类型必须是以下之一:

  • local:带有 local 的记录匹配通过本地 Unix 域套接字文件而不是通过网络建立的连接。出于安全和性能原因,在可能的情况下优先使用本地连接。
  • host:以 host 开头的行匹配通过网络进行的任何连接请求。这是一个针对网络连接的通用匹配规则。可以使用以下类型进行更细粒度的匹配。
  • hostsslhostssl 连接类型匹配通过网络使用 TLS/SSL 加密建立的任何连接。这通常是允许外部连接时使用的最佳连接类型。
  • hostnosslhostnossl 类型匹配任何未由 TLS/SSL 保护的网络连接。

从 PostgreSQL 12 开始,已添加对 GSSAPI 连接 的支持,并引入了以下其他选项:

  • hostgssenchostgssenc 连接类型匹配任何使用 GSSAPI 加密的网络连接。此选项仅对已使用 GSSAPI 进行安全保护的用户才有意义。
  • hostnogssenchostnogssen 类型匹配所有不使用 GSSAPI 加密的网络连接。

数据库

下一个字段指定连接请求尝试访问的数据库。连接请求中指定的数据库必须满足此列中找到的值,该行才能匹配。

这些值可以是以下任何一种:

  • allall 的数据库值是一个通配符值,匹配任何请求的数据库。如果您不希望当前匹配规则评估数据库值,这将非常有用。
  • sameusersameuser 值匹配请求的数据库和用户名相同的连接。
  • samerole:如果用户指定的数据库是与请求的数据库同名的角色的成员,则 samerole 数据库值将匹配连接。
  • replication:使用 replication 的值将匹配用于数据库复制的任何传入连接。用于复制的连接不会提供数据库目标,因此这将匹配复制请求而不是其他请求。
  • [特定数据库名称]:您还可以提供一个或多个特定数据库名称来匹配。这些将仅匹配连接,前提是它们请求列出的数据库之一。您可以用逗号分隔多个数据库名称,或通过在文件名之前加上 @ 符号来指定要读取名称的文件。

用户

下一个字段用于匹配连接请求提供的用户。连接的用户名值必须满足规则的用户名字段,才能匹配该规则。

用户名字段可以采用以下选项:

  • allall 的值告诉 PostgreSQL,连接的用户名参数中的任何值都满足该规则的用户名要求。
  • [特定用户或组名]:用户名字段的唯一其他选项是提供特定用户、用户列表或组。可以通过逗号分隔多个用户来指定它们。如果名称以 + 符号开头,则将其解释为组名而不是用户名。在这种情况下,如果请求的用户是规则指定的组的成员,则该规则将匹配。同样,您可以告诉 PostgreSQL 从文件中读取值,而不是内联提供它们,方法是提供以 @ 符号开头的文件名。

地址

对于所有以 host 开头的连接类型(hosthostsslhostnossl,以及 PostgreSQL 12 及更高版本中的 hostgssenchostnogssenc),接下来是地址字段。对于 local 连接,此字段将被跳过。

地址字段指定客户端机器的地址或模式,以匹配连接的地址。这意味着连接将根据其源地址进行评估。连接的源地址必须满足规则的地址值,该规则才能匹配。

地址字段可以使用以下任何一种来填写:

  • allall 的地址值告诉 PostgreSQL,任何客户端地址都将满足此条件。
  • samehostsamehost 值用于指示来自服务器自身 IP 地址之一的任何网络连接都应该匹配。
  • samenetsamenet 值指示来自服务器网络子网的任何 IP 地址都将匹配。
  • [CIDR IP 地址范围]:您还可以使用 CIDR 表示法 来提供 IP 地址范围。这可以指定单个 IP 地址(对于 IPv4 地址使用 /32 子网,或对于 IPv6 地址使用 /128 子网),或者通过提供更广泛的 CIDR 掩码来指定地址范围。IP 地址范围将仅匹配来自指定范围内使用指定 IP 协议的客户端连接。
  • [主机名]:还可以直接指定主机名。在这种情况下,客户端的主机名将使用正向和反向 DNS 查询进行评估,以确保其按预期解析。如果指定的主机名以点开头,则在该域上正确解析的任何主机都将满足要求。

身份验证方法

如果连接满足所有先前的匹配条件,则会应用给定的身份验证方法。这是每行中的下一个字段。

身份验证方法是 PostgreSQL 用于决定是否接受匹配规则的连接的方式。它可以设置为以下任何选择:

  • trusttrust 的值立即接受连接,无需进一步要求。这假设其他外部身份验证方法已到位。在大多数情况下不建议使用它。
  • rejectreject 的值立即拒绝连接。这主要用于过滤掉与不需要的模式匹配的连接。
  • scram-sha-256scram-sha-256 方法将使用 SCRAM-SHA-256 身份验证 检查用户提供的密码。如果您的所有客户端都支持它,那么目前这是最安全的密码身份验证选项。
  • md5md5 方法也检查用户密码。此方法不如 scram-sha-256 安全,但支持范围更广。如果密码使用 SCRAM 加密,则当前实现即使指定了 md5,也会自动使用 scram-sha-256
  • passwordpassword 方法是最不安全的密码身份验证方法。它以明文形式发送密码,不应使用,除非连接使用 TLS/SSL 对整个连接进行加密。
  • gssgss 方法使用 GSSAPI 进行身份验证。无论连接是否使用 GSSAPI 加密,都可以使用它进行身份验证。这允许通过 Kerberos 和类似软件进行身份验证。
  • sspisspi 方法使用仅限 Windows 的安全支持提供程序接口 API 来验证客户端。
  • identident 方法与客户端的 ident 服务器核实启动连接的用户。由于这依赖于客户端的机器,因此它应该仅用于受信任的网络,在这些网络中,客户端机器受到严格控制。
  • peerpeer 身份验证方法用于本地连接。它向本地操作系统询问客户端的系统用户名。它检查该名称是否与请求的数据库名称匹配。
  • ldapldap 方法使用 LDAP 服务器 来验证用户名和密码进行身份验证。
  • radius: 选择 radius 使用 RADIUS 服务器 检查用户名和密码组合。
  • cert: cert 方法使用 TLS/SSL 客户端证书对客户端进行身份验证。 此方法仅适用于 TLS/SSL 连接。 客户端证书必须是有效的、可信的证书才能被接受。
  • pam: pam 选项将身份验证委托给操作系统的 PAM 服务
  • bsd: bsd 方法使用 BSD 身份验证服务 验证用户名和密码。 此方法仅适用于 OpenBSD 主机。

以上方法中,有些仅适用于特定类型的连接,或需要额外的基础设施。 对于大多数部署,rejectpeerscram-sha-256md5 已经足够,可以根据您的基础设施添加其他方法,例如 ldap

身份验证选项

在身份验证方法之后,可能还会出现一个可选的最后一列,以提供身份验证方法的附加选项。 此列的使用在很大程度上取决于所选身份验证方法的类型。

对于引用外部服务器的身份验证方法,这些选项通常指定主机和连接信息,以便 PostgreSQL 可以成功查询身份验证服务。 另一个在许多身份验证方法中都很常见的选项是 map 参数,它允许您在系统用户名和 PostgreSQL 数据库用户名之间进行转换。

每个身份验证方法都有自己的一套有效选项。 请务必查看 PostgreSQL 文档 中每个方法页面上的相关选项。

配置常见的身份验证策略

我们已经介绍了一些主要的身份验证选项,但如何使用这些选项来实施合理的策略? 在本节中,我们将介绍如何配置一些最常见的身份验证策略。

允许本地用户连接到匹配的数据库

通常情况下,会将 PostgreSQL 配置为允许同一台机器上的用户认证到同一个 PostgreSQL 用户名。 例如,使用 peer 身份验证,如果 PostgreSQL 也具有名为 john 的用户名,则名为 john 的操作系统用户将能够自动登录,无需密码。

这将适用于使用 PostgreSQL 套接字文件进行的任何本地连接。 如果您指定任何网络地址,即使是 127.0.0.1 本地环回设备,连接也不会使用套接字,也不会匹配 peer 身份验证行。 但是,连接到 localhost 将使用套接字文件,并将匹配这些行。

要允许所有 PostgreSQL 用户从匹配的操作系统用户进行身份验证,请添加一行匹配 local 连接类型,允许所有数据库和用户名,并使用 peer 身份验证

# TYPE DATABASE USER ADDRESS METHOD OPTIONS
local all all peer

如果您想限制此功能,以便只有 johnsue PostgreSQL 用户能够以这种方式进行身份验证,请限制 USER 列的范围

# TYPE DATABASE USER ADDRESS METHOD OPTIONS
local all john,sue peer

如果您需要允许名为 sue 的操作系统用户认证到名为 susan 的数据库用户,您可以在行尾指定一个 map 选项。 选择一个地图名称来标识此映射

# TYPE DATABASE USER ADDRESS METHOD OPTIONS
local all john,sue peer map=my-map-name

然后,您可以通过在同一目录中打开 pg_ident.conf 文件来映射您的用户

vim pg_ident.conf

通过在该文件中添加一行来创建您需要的地图,指定您选择的地图名称、操作系统用户名和 PostgreSQL 用户名,用空格分隔

# MAPNAME SYSTEM-USERNAME PG-USERNAME
my-map-name sue susan

现在,sue 操作系统将能够使用 peer 身份验证认证到 susan PostgreSQL 用户,就像他们匹配一样。

允许来自同一台机器的网络连接使用密码

要使用密码对来自 PostgreSQL 服务器机器的网络连接进行身份验证(非套接字连接),您需要匹配 host 连接类型,而不是 local。 然后,您可以将可接受的地址限制为本地环回设备,并允许用户使用 md5scram-sha-256 进行身份验证。

例如,如果 PostgreSQL 主机上的用户尝试通过指定 127.0.0.1 作为主机来连接,PostgreSQL 可以执行密码身份验证。

要进行设置,我们需要使用 host 连接类型。 接下来,我们需要指定可接受地址的范围。 由于此规则应该只匹配本地连接,我们将指定本地环回设备。 我们将不得不添加两行来匹配 IPv4 和 IPv6 环回设备。

之后,您可以指定要用于身份验证的密码方案。 scram-sha-256 方法更安全,但 md5 方法支持更广泛。

完成的身份验证行将如下所示

# TYPE DATABASE USER ADDRESS METHOD OPTIONS
host all all 127.0.0.1/32 md5
host all all ::1/128 md5

您可以通过将相应的列从 all 更改为特定实体的逗号分隔列表来限制允许使用此方法进行身份验证的数据库或用户。

允许自动维护

各种自动化维护任务会定期执行。 为了确保这些操作能够按预期进行身份验证和运行,您需要确保管理员帐户能够以非交互方式进行身份验证。

默认情况下,postgres 帐户使用 peer 身份验证为该角色配置。 此行很可能已经存在于您的 pg_hba.conf 文件中

# TYPE DATABASE USER ADDRESS METHOD OPTIONS
local all postgres peer

确保此行或类似行存在于您的文件中,尤其是在您更改了许多其他身份验证方法的情况下。

允许用于复制的连接

复制是一个特殊的过程,它将数据从一个数据库复制到另一个数据库,通常是频繁发生的。 与其他类型的连接不同,复制连接不会指定要连接到的特定数据库。

数据库列中的 replication 关键字用于匹配这些复制连接。 任何具有 复制权限 的用户都可以建立复制连接。

要允许所有本地复制连接,以类似于我们之前针对常规连接的值(Unix 套接字上的 peer 和本地网络上的 md5)的方式,我们可以添加以下行

# TYPE DATABASE USER ADDRESS METHOD OPTIONS
local replication all peer
host replication all 127.0.0.1/32 md5
host replication all ::1/128 md5

要允许来自其他位置的复制,您可以添加其他地址。 例如,要允许来自本地 192.0.2.0/24 网络上的任何机器的复制,您可以添加一行,如下所示

# TYPE DATABASE USER ADDRESS METHOD OPTIONS
host replication all 192.0.2.0/24 md5

这将允许来自该网络中任何机器的任何复制连接使用 md5 加密的密码进行身份验证。

允许来自本地网络的连接使用密码

在上面,我们演示了如何为本地复制连接配置密码身份验证。 这可以概括为允许任何本地网络连接使用密码进行身份验证。

要允许来自本地 192.0.2.0/24 网络的任何连接使用 md5 密码进行身份验证,您可以添加一行,如下所示

# TYPE DATABASE USER ADDRESS METHOD OPTIONS
host all all 192.0.2.0/24 md5

这将允许 192.0.2.0/24 网络中的所有主机使用 md5 加密的密码通过网络对 PostgreSQL 进行身份验证。

允许远程连接使用 SSL 和密码

为了允许来自不受信任网络的连接,你应该始终通过安全的加密隧道连接,例如TLS/SSL。如果你需要允许这些连接,你应该匹配hostssl连接类型。

例如,要允许从任何可以连接到数据库服务器的地方进行密码验证,但前提是必须使用TLS/SSL,你可以在你的身份验证文件中添加如下所示的一行:

# TYPE DATABASE USER ADDRESS METHOD OPTIONS
hostssl all all all md5

这将允许任何使用TLS/SSL的外部连接使用md5加密的密码进行身份验证。你可以通过指定更严格的地址轻松地限制访问权限。

如果你使用hostssl连接类型,你需要为你的PostgreSQL实例配置SSL。你需要生成或以其他方式获得SSL证书、SSL密钥和SSL根证书,然后修改postgresql.conf配置文件,如PostgreSQL配置SSL文档中所述。

允许使用SSL和SSL客户端证书的远程连接

如果你已经强制对外部连接使用SSL,你可能需要考虑使用SSL客户端证书进行身份验证,而不是使用密码。这将允许客户端提供其SSL客户端证书。服务器会检查证书是否有效并由可信证书颁发机构签署。如果是,它将根据提供的规则允许身份验证。

为了设置SSL客户端身份验证,我们可以使用类似于之前使用的行:

# TYPE DATABASE USER ADDRESS METHOD OPTIONS
hostssl all all all cert

有了这种配置,服务器将不会提示用户输入密码,而是会要求提供有效的SSL证书。证书的通用名称(CN)字段必须与正在请求的数据库用户匹配,或者在map文件中进行配置。

例如,对于CN为katherine的证书,要身份验证到名为kate的PostgreSQL用户,你需要在pg_hba.conf文件中指定一个映射文件:

# TYPE DATABASE USER ADDRESS METHOD OPTIONS
hostssl all all all cert map=my-map-name

之后,你需要编辑pg_ident.conf文件,明确映射这两个用户:

vim pg_ident.conf
# MAPNAME SYSTEM-USERNAME PG-USERNAME
my-map-name katherine kate

你可以在PostgreSQL关于TLS/SSL客户端证书的文档中学习如何创建和配置客户端证书。

结论

在本指南中,我们介绍了从服务器端进行PostgreSQL身份验证。我们演示了如何修改PostgreSQL实例的配置,以更改允许客户端进行身份验证的方式。在讨论身份验证文件中可用的不同选项后,我们介绍了如何使用我们之前学到的知识来实现一些常见身份验证策略。

了解如何配置身份验证,结合对如何使用PostgreSQL客户端连接的理解,可以让你向合法客户端授予访问权限,同时防止不必要的连接。这种配置是保护你的数据库实例和防止可能阻碍你的操作的破坏性登录问题的重要组成部分。

关于作者
Justin Ellingwood

Justin Ellingwood

Justin从2013年开始撰写有关数据库、Linux、基础设施和开发者工具的文章。他现在和妻子以及两只兔子住在柏林。他通常不需要以第三人称写作,这对所有相关方来说都是一种解脱。