受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

Chapter 20. 客户端认证

当客户端应用连接到数据库服务器时,它会指定要以哪个 PostgreSQL 数据库用户名连接,这很像以某个特定用户身份登录 Unix 计算机一样。在 SQL 环境中,当前活动的数据库用户名决定了对数据库对象的访问权限 — 详见 Chapter 21。因此,必须限制哪些数据库用户能够连接。

Note

Chapter 21 中所述,PostgreSQL 实际上是以 角色 为单位进行权限管理的。在本章中,我们统一使用 数据库用户 来表示 拥有 LOGIN 权限的角色

认证是数据库服务器确认客户端身份的过程,并据此决定是否允许该客户端应用(或者运行该客户端应用的用户)以请求的数据库用户名进行连接。

PostgreSQL 提供了多种不同的客户端认证方法。用于认证特定客户端连接的方法可以根据(客户端)主机地址、数据库和用户来选择。

PostgreSQL 数据库用户名在逻辑上独立于服务器所在操作系统中的用户名。如果某台服务器的所有用户在该机器上也都有账号,那么为他们分配与操作系统用户名一致的数据库用户名是有意义的。不过,接受远程连接的服务器可能有许多数据库用户并没有本地操作系统账号,在这种情况下,数据库用户名与操作系统用户名之间就不必存在任何对应关系。

20.1. pg_hba.conf 文件 #

客户端认证由一个配置文件控制,该文件按惯例命名为 pg_hba.conf,并存放在数据库集簇的数据目录中。 (HBA 代表 host-based authentication,即基于主机的认证。) 当数据目录由 initdb 初始化时,会安装一个默认的 pg_hba.conf 文件。不过,也可以把认证配置文件放在别处; 请参见配置参数 hba_file

pg_hba.conf 文件的一般格式是一组记录,每行一条。 空白行会被忽略,# 注释字符后面的任何文本也会被忽略。 记录可以通过在行尾加反斜线延续到下一行。(反斜线除出现在行尾之外,没有其他特殊含义。) 一条记录由若干个字段组成,这些字段之间以空格和/或制表符分隔。 如果字段值用双引号括起,则其中可以包含空白。 在数据库、用户或地址字段中给关键字加上引号(例如 allreplication),会使该词失去其特殊含义,而仅匹配同名的数据库、用户或主机。 即使在带引号的文本或注释中,也同样适用反斜线续行。

每条认证记录都指定一种连接类型、一个客户端 IP 地址范围(如果该连接类型需要)、一个数据库名、一个用户名,以及对匹配这些参数的连接要使用的认证方法。第一条同时匹配连接类型、客户端地址、请求数据库和用户名的记录会被用来执行认证。这里不存在 继续向后匹配后备 机制:如果选中某条记录而认证失败,就不会再考虑后续记录。如果没有任何记录匹配,则拒绝访问。

一条记录可以是 include 指令,也可以是认证记录。include 指令用于指定可被包含的文件,这些文件中可以含有额外记录;这些记录会插入到 include 指令所在的位置。include 指令只有两个字段:includeinclude_if_existsinclude_dir 指令本身,以及要包含的文件或目录。文件或目录既可以是相对路径,也可以是绝对路径,并且都可以用双引号括起。对于 include_dir 形式,将包含所有文件名不以 . 开头且以 .conf 结尾的文件。include 目录中的多个文件会按照文件名顺序处理(依据 C locale 规则,即数字排在字母前,大写字母排在小写字母前)。

一条记录可以有多种格式:

local         database  user  auth-method [auth-options]
host          database  user  address     auth-method  [auth-options]
hostssl       database  user  address     auth-method  [auth-options]
hostnossl     database  user  address     auth-method  [auth-options]
hostgssenc    database  user  address     auth-method  [auth-options]
hostnogssenc  database  user  address     auth-method  [auth-options]
host          database  user  IP-address  IP-mask      auth-method  [auth-options]
hostssl       database  user  IP-address  IP-mask      auth-method  [auth-options]
hostnossl     database  user  IP-address  IP-mask      auth-method  [auth-options]
hostgssenc    database  user  IP-address  IP-mask      auth-method  [auth-options]
hostnogssenc  database  user  IP-address  IP-mask      auth-method  [auth-options]
include       file
include_if_exists file
include_dir   directory

字段的含义如下:

local

该记录匹配使用 Unix 域套接字的连接尝试。没有这种类型的记录时,Unix 域套接字连接将被禁止。

host

该记录匹配使用 TCP/IP 发起的连接尝试。 host 记录既匹配 SSL 或非 SSL 连接尝试, 也匹配使用 GSSAPI 加密或 不使用 GSSAPI 加密的连接尝试。

Note

除非服务器以适当的 listen_addresses 配置参数值启动, 否则远程 TCP/IP 连接将不可用,因为默认行为是只在本地回环地址 localhost 上监听 TCP/IP 连接。

hostssl

该记录匹配使用 TCP/IP 发起的连接尝试,但仅当连接使用 SSL 加密时才匹配。

要使用此选项,服务器必须在构建时启用 SSL 支持。 此外,还必须通过设置 ssl 配置参数来启用 SSL (有关更多信息,请参见Section 18.9)。 否则,hostssl 记录将被忽略,只会记录一条警告,说明它无法匹配任何连接。

hostnossl

该记录类型与 hostssl 的行为相反;它只匹配通过 TCP/IP 发起且不使用 SSL 的连接尝试。

hostgssenc

该记录匹配使用 TCP/IP 发起的连接尝试,但仅当连接使用 GSSAPI 加密时才匹配。

要使用此选项,服务器必须在构建时启用 GSSAPI 支持。 否则,hostgssenc 记录将被忽略,只会记录一条警告,说明它无法匹配任何连接。

hostnogssenc

该记录类型与 hostgssenc 的行为相反; 它只匹配通过 TCP/IP 发起且不使用 GSSAPI 加密的连接尝试。

database

指定此记录匹配的数据库名称。值all指定匹配所有数据库。 值sameuser指定如果请求的数据库与请求的用户具有相同的名称,则记录匹配。 值samerole指定请求的用户必须是与请求的数据库具有相同名称的角色的成员。 (samegroupsamerole的一种过时但仍被接受的写法。) 对于 samerole 而言,超级用户并不会仅因其超级用户身份就被视为某个角色的成员;只有当其显式地直接或间接属于该角色时,才会被视为成员。 值replication表示当请求的是物理复制连接时匹配,但不匹配逻辑复制连接。请注意,物理复制连接不指定任何特定数据库,而逻辑复制连接会指定数据库。 否则,这里可以是某个特定PostgreSQL数据库的名称,或者一个正则表达式。 多个数据库名和/或正则表达式可以用逗号分隔提供。

如果数据库名以斜线(/)开头,则其余部分会被视为一个正则表达式。 (关于 PostgreSQL 正则表达式语法的细节,见 Section 9.7.3.1。)

也可以通过在文件名前加上@来指定一个单独文件,该文件中包含数据库名和/或正则表达式。

user

指定此记录匹配哪些数据库用户名。值all表示匹配所有用户。 否则,这里可以是某个特定数据库用户的名称、一个正则表达式(以斜线(/)开头时),或者一个以前缀 + 标识的组名。 (请记住,在PostgreSQL中,用户和组之间并没有真正区别; + 标记实际上表示匹配直接或间接属于该角色的任意角色,而没有 + 标记的名称只匹配该特定角色。) 为此目的,只有在超级用户显式地直接或间接属于该角色时,才会被视为该角色的成员,而不会仅因其超级用户身份而被视为成员。 多个用户名和/或正则表达式可以用逗号分隔提供。

如果用户名以斜线(/)开头,则其余部分会被视为一个正则表达式。 (关于 PostgreSQL 正则表达式语法的细节,见 Section 9.7.3.1。)

也可以通过在文件名前加上@来指定一个单独文件,该文件中包含用户名和/或正则表达式。

address

指定此记录匹配的客户端机器地址。此字段可以包含主机名、IP地址范围或下面提到的特殊关键字之一。

IP地址范围使用标准的数字表示法来指定起始地址,然后是斜杠(/)和一个CIDR掩码长度。 掩码长度表示客户端IP地址必须匹配的高位比特数。给定IP地址中右侧的比特应为零。 IP地址、/和CIDR掩码长度之间不得有任何空格。

以这种方式指定的IPv4地址范围的典型示例包括172.20.143.89/32用于单个主机, 或172.20.143.0/24用于小型网络,或10.6.0.0/16用于较大的网络。 IPv6地址范围可能看起来像::1/128用于单个主机(在这种情况下是IPv6环回地址)或 fe80::7a31:c1ff:0000:0000/96用于小型网络。 0.0.0.0/0代表所有IPv4地址,::0/0代表所有IPv6地址。 要指定单个主机,请对IPv4使用32的掩码长度,对IPv6使用128。在网络地址中,不要省略尾部的零。

以IPv4格式给出的条目将仅匹配IPv4连接,以IPv6格式给出的条目将仅匹配IPv6连接, 即使所代表的地址在IPv4-in-IPv6范围内。请注意,如果系统的C库不支持IPv6地址, 以IPv6格式给出的条目将被拒绝。

你也可以写all来匹配任何IP地址, samehost来匹配服务器自己的任何IP地址, 或samenet来匹配服务器直接连接到的任何子网中的任何地址。

如果指定了主机名(任何不是IP地址范围或特殊关键字的内容都被视为主机名), 则将该名称与客户端IP地址的反向名称解析结果进行比较(例如,如果使用DNS,则进行反向DNS查找)。 主机名比较不区分大小写。如果匹配成功,则对主机名执行正向名称解析(例如,进行正向DNS查找), 以检查其解析为的任何地址是否等于客户端IP地址。如果两个方向都匹配,则将条目视为匹配。 (在pg_hba.conf中使用的主机名应该是客户端IP地址的地址到名称解析返回的名称, 否则该行将不会匹配。一些主机名数据库允许将IP地址与多个主机名关联, 但操作系统在要求解析IP地址时只会返回一个主机名。)

以点(.)开头的主机名规范匹配实际主机名的后缀。 因此,.example.com将匹配foo.example.com (但不仅仅是example.com)。

当在pg_hba.conf中指定主机名时,应确保名称解析相对快速。 最好设置一个本地名称解析缓存,如nscd。 此外,还可能希望启用配置参数log_hostname,以便在日志中看到客户端的主机名而不是 IP 地址。

这些字段不适用于local记录。

Note

用户有时会想知道为什么主机名以这种看似复杂的方式处理,包括两次名称解析,其中包括对客户端IP地址的反向查找。 如果客户端的反向DNS条目未设置或生成了一些不良的主机名,则使用该功能会变得复杂。 这主要是为了效率:这样,连接尝试最多需要两次解析器查找,一次反向查找和一次正向查找。 如果某个地址存在解析器问题,那就只会成为该客户端的问题。 一个假设的替代实现只进行正向查找的情况下,在每次连接尝试期间都必须解析pg_hba.conf中提到的每个主机名。 如果列出了许多名称,这可能会非常慢。 如果其中一个主机名存在解析器问题,那么这将成为所有人的问题。

此外,实现后缀匹配功能需要进行反向查找,因为需要知道实际客户端主机名 以便将其与模式进行匹配。

请注意,这种行为与其他流行的基于主机名的访问控制实现一致,例如 Apache HTTP服务器和TCP包装器。

IP-address
IP-mask

这两个字段可以用作IP地址/掩码长度 表示法的替代方案。而不是指定掩码长度,实际掩码在一个单独的列中指定。 例如,255.0.0.0表示IPv4的CIDR掩码长度为8, 而255.255.255.255表示CIDR掩码长度为32。

这些字段不适用于local记录。

auth-method

指定连接匹配此记录时要使用的认证方法。可选值在此处做了概述;详细说明见 Section 20.3。所有选项都必须使用小写并且区分大小写,因此即使是像 ldap 这样的首字母缩写也必须写成小写。

trust

无条件允许连接。这种方法允许任何能够连接到PostgreSQL数据库服务器的人以任意他们希望的PostgreSQL用户身份登录,无需密码或任何其他认证。详见Section 20.4

reject

无条件拒绝连接。这对于过滤掉某些主机很有用,例如一个reject行可以阻止特定主机连接, 而后面的行允许特定网络中的其余主机连接。

scram-sha-256

执行 SCRAM-SHA-256 认证以校验用户密码。详见Section 20.5

md5

执行 SCRAM-SHA-256 或 MD5 认证以校验用户密码。详见Section 20.5

password

要求客户端提供未加密的密码以完成认证。 由于密码会以明文形式通过网络发送,因此不应在不受信任的网络上使用。 详见Section 20.5

gss

使用 GSSAPI 对用户进行认证。这仅适用于 TCP/IP 连接。详见Section 20.6。它可以与 GSSAPI 加密配合使用。

sspi

使用 SSPI 对用户进行认证。这仅适用于 Windows。详见Section 20.7

ident

通过联系客户端上的 ident 服务器获取客户端的操作系统用户名, 并检查它是否与请求的数据库用户名匹配。 Ident 认证只能用于 TCP/IP 连接。 当为本地连接指定时,将改为使用 peer 认证。 详见Section 20.8

peer

从操作系统获取客户端的操作系统用户名,并检查是否与请求的数据库用户名匹配。 这仅适用于本地连接。 有关详细信息,请参见Section 20.9

ldap

使用LDAP服务器进行认证。详见Section 20.10

radius

使用 RADIUS 服务器进行认证。详见Section 20.11

cert

使用 SSL 客户端证书进行认证。详见Section 20.12

pam

使用操作系统提供的可插拔认证模块(PAM)服务进行认证。详见Section 20.13

bsd

使用操作系统提供的 BSD 认证服务进行认证。详见Section 20.14

auth-options

auth-method字段之后,可以是形如name=value的字段, 用于指定认证方法的选项。关于哪些选项适用于哪些认证方法的详细信息见下文。

除了下面列出的特定于方法的选项外,还有一个方法无关的认证选项 clientcert, 可以在任何hostssl记录中指定。 此选项可以设置为verify-caverify-full。 这两个选项都要求客户端提供有效(受信任的)SSL证书, 而verify-full还要求证书中的cn(通用名称)与用户名或适用映射匹配。 这种行为类似于 cert 认证方法(见Section 20.12), 但允许把客户端证书验证与任何支持 hostssl 条目的认证方法配合使用。

对于任何使用客户端证书认证的记录(即使用 cert 认证方法的记录,或使用 clientcert 选项的记录),都可以通过 clientname 选项指定要匹配客户端证书凭据中的哪一部分。此选项有两个可选值。如果指定 clientname=CN,这也是默认值,则用户名将与证书的 Common Name (CN) 匹配。如果改为指定 clientname=DN,则用户名将与证书的完整 Distinguished Name (DN) 匹配。此选项通常最好与用户名映射配合使用。比较时使用的是 RFC 2253 格式的 DN。要查看以这种格式表示的客户端证书 DN,请执行

openssl x509 -in myclient.crt -noout -subject -nameopt RFC2253 | sed "s/^subject=//"

在使用此选项时需要小心,特别是在使用正则表达式匹配DN时。

include

这一行会被给定文件的内容替换。

include_if_exists

如果给定文件存在,这一行会被该文件的内容替换;否则会记录一条消息,说明该文件已被跳过。

include_dir

这一行会被目录中找到的所有文件内容替换,前提是这些文件名不以 . 开头并且以 .conf 结尾;这些文件会按照文件名字典序处理(依据 C locale 规则,即数字排在字母前,大写字母排在小写字母前)。

@ 构造引用的文件会被读取为名称列表,其中的名称可以用空白或逗号分隔。注释仍然用 # 引入,与 pg_hba.conf 中相同,并且允许嵌套的 @ 构造。除非 @ 后面的文件名是绝对路径,否则它会被视为相对于引用它的文件所在目录。

因为每一次连接尝试都会顺序地检查pg_hba.conf记录,所以这些记录的顺序是非常关键的。通常,靠前的记录有比较严的连接匹配参数和比较弱的认证方法,而靠后的记录有比较松的匹配参数和比较强的认证方法。 例如,我们希望对本地 TCP/IP 连接使用trust认证,而对远程 TCP/IP 连接要求密码。在这种情况下为来自于 127.0.0.1 的连接指定trust认证的记录将出现在为一个更宽范围的客户端 IP 地址指定密码认证的记录前面。

在启动以及主服务器进程收到SIGHUP信号时,pg_hba.conf文件会被读取。 如果你在活动的系统上编辑了该文件,你将需要通知 postmaster(使用pg_ctl reload,调用SQL函数pg_reload_conf(),或使用kill -HUP)使其重新读取该文件。

Note

前面的说明在Microsoft Windows上不为真:在Windows上,pg_hba.conf文件中的任何更改会立即被应用到后续的新连接上。

系统视图pg_hba_file_rules 有助于预先测试对 pg_hba.conf 文件的修改,也可以在加载该文件没有产生预期效果时用于诊断问题。视图中 error 字段非空的行表示文件对应行存在问题。

Tip

要连接到一个特定数据库,一个用户必须不仅要通过pg_hba.conf检查,还必须要有该数据库上的CONNECT权限。如果你希望限制哪些用户能够连接到哪些数据库,授予/撤销CONNECT权限通常比在pg_hba.conf项中设置规则简单。

Example 20.1中展示了pg_hba.conf项的一些示例。不同认证方法的详情请见下一节。

Example 20.1. 示例 pg_hba.conf

# 允许本地系统上的任何用户
# 通过 Unix 域套接字以任意
# 数据库用户名连接到任意数据库(本地连接的默认值)。
#
# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   all             all                                     trust

# 相同的规则,但是使用本地环回 TCP/IP 连接。
#
# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    all             all             127.0.0.1/32            trust

# 和前一行相同,但是使用了一个独立的掩码列
#
# TYPE  DATABASE        USER            IP-ADDRESS      IP-MASK             METHOD
host    all             all             127.0.0.1       255.255.255.255     trust

# IPv6 上相同的规则
#
# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    all             all             ::1/128                 trust

# 使用主机名的相同规则(通常同时覆盖 IPv4 和 IPv6)。
#
# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    all             all             localhost               trust

# 使用 DATABASE 正则表达式的相同规则,它允许连接到任何
# 名称以 "db" 开头并以两到四位数字结尾的数据库
# (例如 "db1234" 或 "db12")。
#
# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    "/^db\d{2,4}$"  all             localhost               trust

# 允许来自任意具有 IP 地址192.168.93.x 的主机上任意
# 用户以 ident 为该连接所报告的相同用户名连接到
# 数据库 "postgres"(通常是操作系统用户名)。
#
# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    postgres        all             192.168.93.0/24         ident

# 如果用户的密码被正确提供,允许来自主机 192.168.12.10
# 的任意用户连接到数据库 "postgres"。
#
# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    postgres        all             192.168.12.10/32        scram-sha-256

# 如果用户的密码被正确提供,允许 example.com 中主机上
# 的任意用户连接到任意数据库。
#
# 为大部分用户要求SCRAM认证,但是用户'mike'是个例外,
# 他使用的是不支持SCRAM认证的旧客户端。
#
# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    all             mike            .example.com            md5
host    all             all             .example.com            scram-sha-256

# 如果没有前面的 "host" 行,这三行
# 将拒绝所有来自 192.168.54.1的连接(因为那些项将首先被匹配),
# 但是允许来自互联网其他任何地方的
# GSSAPI 加密连接。零掩码表示不会考虑主机 IP 地址中的任何位,
# 因此它会匹配任意主机。未加密的 GSSAPI 连接
# (由于 "hostgssenc" 只匹配加密的 GSSAPI 连接,因此它们会继续匹配到第三行)
# 也是允许的,但只能来自 192.168.12.10。
#
# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    all             all             192.168.54.1/32         reject
hostgssenc all          all             0.0.0.0/0               gss
host    all             all             192.168.12.10/32        gss

# 允许来自 192.168.x.x 主机的用户连接到任意数据库,如果它们能够
# 通过 ident 检查。例如,假设 ident说用户是 "bryanh" 并且他要求以
# PostgreSQL 用户 "guest1" 连接,如果在 pg_ident.conf 有一个映射
# "omicron" 的选项说 "bryanh" 被允许以 "guest1" 连接,则该连接将被允许。
#
# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    all             all             192.168.0.0/16          ident map=omicron

# 如果这些是本地连接的唯一四行,它们将允许本地用户只连接到它们
# 自己的数据库(与其数据库用户名同名的数据库),不过用户名以
# "helpdesk" 结尾的用户、管理员以及角色 "support" 的成员除外
# (它们可以连接到所有数据库)。文件 $PGDATA/admins 包含一个
# 管理员名字的列表。在所有情况下都要求密码。
#
# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   sameuser        all                                     scram-sha-256
local   all             /^.*helpdesk$                           scram-sha-256
local   all             @admins                                 scram-sha-256
local   all             +support                                scram-sha-256

# 上面的最后两行可以被整合为一行:
local   all             @admins,+support                        scram-sha-256

# 数据库列也可以用列表和文件名:
local   db1,db2,@demodbs  all                                   scram-sha-256

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。