20.1. pg_hba.conf 文件 #
客户端认证由一个配置文件控制,该文件按惯例命名为
pg_hba.conf,并存放在数据库集簇的数据目录中。(HBA 代表 host-based authentication,即基于主机的认证。)当数据目录由 initdb 初始化时,会安装一个默认的
pg_hba.conf 文件。不过,也可以把认证配置文件放在别处;请参见配置参数 hba_file。
在启动时以及主服务器进程收到 SIGHUP 信号时,pg_hba.conf 文件会被读取。如果你在运行中的系统上编辑了该文件,就需要通知 postmaster(使用 pg_ctl reload、调用 SQL 函数 pg_reload_conf(),或者使用 kill -HUP)重新读取该文件。
注意
前面的说明不适用于 Microsoft Windows:在 Windows 上,pg_hba.conf 文件中的任何更改会立即被应用到后续的新连接上。
系统视图 pg_hba_file_rules 有助于预先测试对 pg_hba.conf 文件的修改,也可以在加载该文件没有产生预期效果时用于诊断问题。视图中 error 字段非空的行表示文件对应行存在问题。
pg_hba.conf 文件的一般格式是一组记录,每行一条。空白行会被忽略,# 注释字符后面的任何文本也会被忽略。记录可以通过在行尾加反斜线延续到下一行。(反斜线除出现在行尾之外,没有其他特殊含义。)一条记录由若干个字段组成,这些字段之间以空格和/或制表符分隔。如果字段值用双引号括起,则其中可以包含空白。在数据库、用户或地址字段中给关键字加上引号(例如 all 或 replication),会使该词失去其特殊含义,而仅匹配同名的数据库、用户或主机。即使在带引号的文本或注释中,也同样适用反斜线续行。
每条认证记录都指定一种连接类型、一个客户端 IP 地址范围(如果该连接类型需要)、一个数据库名、一个用户名,以及对匹配这些参数的连接要使用的认证方法。第一条同时匹配连接类型、客户端地址、请求数据库和用户名的记录会被用来执行认证。这里不存在“继续向后匹配”或“后备”机制:如果选中某条记录而认证失败,就不会再考虑后续记录。如果没有任何记录匹配,则拒绝访问。
一条记录可以是 include 指令,也可以是认证记录。include 指令用于指定可被包含的文件,这些文件中可以含有额外记录;这些记录会插入到 include 指令所在的位置。include 指令只有两个字段:include、include_if_exists 或 include_dir 指令本身,以及要包含的文件或目录。文件或目录既可以是相对路径,也可以是绝对路径,并且都可以用双引号括起。对于 include_dir 形式,将包含所有文件名不以 . 开头且以 .conf 结尾的文件。include 目录中的多个文件会按照文件名顺序处理(依据 C locale 规则,即数字排在字母前,大写字母排在小写字母前)。
一条记录可以有多种格式:
localdatabaseuserauth-method[auth-options] hostdatabaseuseraddressauth-method[auth-options] hostssldatabaseuseraddressauth-method[auth-options] hostnossldatabaseuseraddressauth-method[auth-options] hostgssencdatabaseuseraddressauth-method[auth-options] hostnogssencdatabaseuseraddressauth-method[auth-options] hostdatabaseuserIP-addressIP-maskauth-method[auth-options] hostssldatabaseuserIP-addressIP-maskauth-method[auth-options] hostnossldatabaseuserIP-addressIP-maskauth-method[auth-options] hostgssencdatabaseuserIP-addressIP-maskauth-method[auth-options] hostnogssencdatabaseuserIP-addressIP-maskauth-method[auth-options] includefileinclude_if_existsfileinclude_dirdirectory
字段的含义如下:
local#该记录匹配使用 Unix 域套接字的连接尝试。没有这种类型的记录时,Unix 域套接字连接将被禁止。
host#该记录匹配使用 TCP/IP 发起的连接尝试。
host记录既匹配 SSL 或非 SSL 连接尝试,也匹配使用 GSSAPI 加密或不使用 GSSAPI 加密的连接尝试。注意
除非服务器以适当的 listen_addresses 配置参数值启动,否则远程 TCP/IP 连接将不可用,因为默认行为是只在本地回环地址
localhost上监听 TCP/IP 连接。hostssl#该记录匹配使用 TCP/IP 发起的连接尝试,但仅当连接使用 SSL 加密时才匹配。
要使用此选项,服务器必须在构建时启用 SSL 支持。此外,还必须通过设置 ssl 配置参数来启用 SSL(有关更多信息,请参见第 18.9 节)。否则,
hostssl记录将被忽略,只会记录一条警告,说明它无法匹配任何连接。hostnossl#该记录类型与
hostssl的行为相反;它只匹配通过 TCP/IP 发起且不使用 SSL 的连接尝试。hostgssenc#该记录匹配使用 TCP/IP 发起的连接尝试,但仅当连接使用 GSSAPI 加密时才匹配。
要使用此选项,服务器必须在构建时启用 GSSAPI 支持。否则,
hostgssenc记录将被忽略,只会记录一条警告,说明它无法匹配任何连接。hostnogssenc#该记录类型与
hostgssenc的行为相反;它只匹配通过 TCP/IP 发起且不使用 GSSAPI 加密的连接尝试。database#指定此记录匹配的数据库名称。值
all指定匹配所有数据库。值sameuser指定如果请求的数据库与请求的用户具有相同的名称,则记录匹配。值samerole指定请求的用户必须是与请求的数据库具有相同名称的角色的成员。(samegroup是samerole的一种过时但仍被接受的写法。)对于samerole而言,超级用户并不会仅因其超级用户身份就被视为某个角色的成员;只有当其显式地直接或间接属于该角色时,才会被视为成员。值replication表示当请求的是物理复制连接时匹配,但不匹配逻辑复制连接。请注意,物理复制连接不指定任何特定数据库,而逻辑复制连接会指定数据库。否则,这里可以是某个特定 PostgreSQL 数据库的名称,或者一个正则表达式。多个数据库名和/或正则表达式可以用逗号分隔提供。如果数据库名以斜线(
/)开头,则其余部分会被视为一个正则表达式。(关于 PostgreSQL 正则表达式语法的细节,见第 9.7.3.1 节。)也可以通过在文件名前加上
@来指定一个单独文件,该文件中包含数据库名和/或正则表达式。user#指定此记录匹配哪些数据库用户名。值
all表示匹配所有用户。否则,这里可以是某个特定数据库用户的名称、一个正则表达式(以斜线(/)开头时),或者一个以前缀+标识的组名。(请记住,在 PostgreSQL 中,用户和组之间并没有真正区别;+标记实际上表示“匹配直接或间接属于该角色的任意角色”,而没有+标记的名称只匹配该特定角色。)为此目的,只有在超级用户显式地直接或间接属于该角色时,才会被视为该角色的成员,而不会仅因其超级用户身份而被视为成员。多个用户名和/或正则表达式可以用逗号分隔提供。如果用户名以斜线(
/)开头,则其余部分会被视为一个正则表达式。(关于 PostgreSQL 正则表达式语法的细节,见第 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 范围内。
你也可以写
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记录。注意
用户有时会想知道为什么主机名以这种看似复杂的方式处理,包括两次名称解析,其中包括对客户端 IP 地址的反向查找。如果客户端的反向 DNS 条目未设置或返回了不符合预期的主机名,则使用该功能会变得复杂。这主要是为了效率:这样,连接尝试最多需要两次解析器查找,一次反向查找和一次正向查找。如果某个地址存在解析器问题,那就只会成为该客户端的问题。一个只进行正向查找的假设替代实现,在每次连接尝试期间都必须解析
pg_hba.conf中提到的每个主机名。如果列出了许多名称,这可能会非常慢。如果其中一个主机名存在解析器问题,那么这将成为所有人的问题。此外,实现后缀匹配功能需要进行反向查找,因为需要知道实际客户端主机名以便将其与模式进行匹配。
请注意,这种行为与其他流行的基于主机名的访问控制实现一致,例如 Apache HTTP 服务器和 TCP Wrappers。
IP-addressIP-mask#这两个字段可以用作
IP-address/mask-length表示法的替代方案。不指定掩码长度,而是在单独一列中指定实际掩码。例如,255.0.0.0表示 IPv4 的 CIDR 掩码长度为 8,而255.255.255.255表示 CIDR 掩码长度为 32。这些字段不适用于
local记录。auth-method#指定连接匹配此记录时要使用的认证方法。可选值在此处做了概述;详细说明见第 20.3 节。所有选项都必须使用小写并且区分大小写,因此即使是像
ldap这样的首字母缩写也必须写成小写。trust#无条件允许连接。这种方法允许任何能够连接到 PostgreSQL 数据库服务器的人以任意他们希望的 PostgreSQL 用户身份登录,无需密码或任何其他认证。详见第 20.4 节。
reject#无条件拒绝连接。这对于“过滤掉”某些主机很有用,例如一个
reject行可以阻止特定主机连接,而后面的行允许特定网络中的其余主机连接。scram-sha-256#执行 SCRAM-SHA-256 认证以校验用户密码。详见第 20.5 节。
md5#执行 SCRAM-SHA-256 或 MD5 认证以校验用户密码。详见第 20.5 节。
password#要求客户端提供未加密的密码以完成认证。由于密码会以明文形式通过网络发送,因此不应在不受信任的网络上使用。详见第 20.5 节。
gss#使用 GSSAPI 对用户进行认证。这仅适用于 TCP/IP 连接。详见第 20.6 节。它可以与 GSSAPI 加密配合使用。
sspi#使用 SSPI 对用户进行认证。这仅适用于 Windows。详见第 20.7 节。
ident#通过联系客户端上的 ident 服务器获取客户端的操作系统用户名,并检查它是否与请求的数据库用户名匹配。Ident 认证只能用于 TCP/IP 连接。当为本地连接指定时,将改为使用 peer 认证。详见第 20.8 节。
peer#从操作系统获取客户端的操作系统用户名,并检查是否与请求的数据库用户名匹配。这仅适用于本地连接。有关详细信息,请参见第 20.9 节。
ldap#使用 LDAP 服务器进行认证。详见第 20.10 节。
radius#使用 RADIUS 服务器进行认证。详见第 20.11 节。
cert#使用 SSL 客户端证书进行认证。详见第 20.12 节。
pam#使用操作系统提供的可插拔认证模块(PAM)服务进行认证。详见第 20.13 节。
bsd#使用操作系统提供的 BSD 认证服务进行认证。详见第 20.14 节。
auth-options#在
auth-method字段之后,可以有一个或多个形如name=value的字段,用于指定认证方法的选项。下文会详细说明各认证方法有哪些可用选项。除了下面列出的特定于方法的选项外,还有一个方法无关的认证选项
clientcert,可以在任何hostssl记录中指定。此选项可以设置为verify-ca或verify-full。这两个选项都要求客户端提供有效(受信任的)SSL 证书,而verify-full还要求证书中的cn(通用名称)与用户名或适用映射匹配。这种行为类似于cert认证方法(见第 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 地址指定密码认证的记录之前。
提示
要连接到一个特定数据库,一个用户不仅要通过 pg_hba.conf 检查,还必须有该数据库上的 CONNECT 权限。如果你希望限制哪些用户能够连接到哪些数据库,授予/撤销 CONNECT 权限通常比在 pg_hba.conf 项中设置规则简单。
例 20.1 展示了一些 pg_hba.conf 条目示例。有关不同认证方法的详细信息,参见下一节。
例 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 md5
local all /^.*helpdesk$ md5
local all @admins md5
local all +support md5
# 上面的最后两行可以被整合为一行:
local all @admins,+support md5
# 数据库列也可以用列表和文件名:
local db1,db2,@demodbs all md5
报告文档问题
阅读 上游文档. 通过 PostgreSQL 文档反馈表单.