目录
当客户端应用连接到数据库服务器时,它会指定要以哪个 PostgreSQL 数据库用户名连接,这很像以某个特定用户身份登录 Unix 计算机一样。在 SQL 环境中,当前活动的数据库用户名决定了对数据库对象的访问权限 — 详见 Chapter 21。因此,必须限制哪些数据库用户能够连接。
如 Chapter 21 中所述,PostgreSQL 实际上是以 “角色” 为单位进行权限管理的。在本章中,我们统一使用 数据库用户 来表示 “拥有 LOGIN 权限的角色”。
认证是数据库服务器确认客户端身份的过程,并据此决定是否允许该客户端应用(或者运行该客户端应用的用户)以请求的数据库用户名进行连接。
PostgreSQL 提供了多种不同的客户端认证方法。用于认证特定客户端连接的方法可以根据(客户端)主机地址、数据库和用户来选择。
PostgreSQL 数据库用户名在逻辑上独立于服务器所在操作系统中的用户名。如果某台服务器的所有用户在该机器上也都有账号,那么为他们分配与操作系统用户名一致的数据库用户名是有意义的。不过,接受远程连接的服务器可能有许多数据库用户并没有本地操作系统账号,在这种情况下,数据库用户名与操作系统用户名之间就不必存在任何对应关系。
pg_hba.conf 文件 #客户端认证由一个配置文件控制,该文件通常名为 pg_hba.conf,存储在数据库集簇的数据目录中。(HBA 表示基于主机的认证。)initdb 初始化数据目录时,会安装一个默认的 pg_hba.conf 文件。不过,也可以将认证配置文件放在其他位置;参见 hba_file 配置参数。
pg_hba.conf 文件的基本格式是一组记录,每行一条。空行和 # 注释字符之后的所有文本都会被忽略。记录不能跨行续写。每条记录由若干字段组成,字段之间用空格和/或制表符分隔。如果字段值用双引号括起来,就可以包含空白。在数据库、用户或地址字段中,将关键字(例如 all 或 replication)用引号括起来,会使其失去特殊含义,只匹配同名的数据库、用户或主机。
每条认证记录都指定一种连接类型、一个客户端 IP 地址范围(如果该连接类型需要)、一个数据库名、一个用户名,以及对匹配这些参数的连接要使用的认证方法。第一条同时匹配连接类型、客户端地址、请求数据库和用户名的记录会被用来执行认证。这里不存在 “继续向后匹配” 或 “后备” 机制:如果选中某条记录而认证失败,就不会再考虑后续记录。如果没有任何记录匹配,则拒绝访问。
记录可以采用以下七种格式之一
localdatabaseuserauth-method[auth-options] hostdatabaseuseraddressauth-method[auth-options] hostssldatabaseuseraddressauth-method[auth-options] hostnossldatabaseuseraddressauth-method[auth-options] hostdatabaseuserIP-addressIP-maskauth-method[auth-options] hostssldatabaseuserIP-addressIP-maskauth-method[auth-options] hostnossldatabaseuserIP-addressIP-maskauth-method[auth-options]
各字段的含义如下:
local该记录匹配使用 Unix 域套接字的连接尝试。没有这种类型的记录时,Unix 域套接字连接将被禁止。
host此记录匹配通过 TCP/IP 发起的连接尝试。host 记录既匹配 SSL 连接,也匹配非 SSL 连接。
除非服务器以适当的 listen_addresses 配置参数值启动, 否则远程 TCP/IP 连接将不可用,因为默认行为是只在本地回环地址 localhost 上监听 TCP/IP 连接。
hostssl该记录匹配使用 TCP/IP 发起的连接尝试,但仅当连接使用 SSL 加密时才匹配。
要使用此选项,服务器必须在构建时启用 SSL 支持。 此外,还必须通过设置 ssl 配置参数来启用 SSL (有关更多信息,请参见Section 18.9)。 否则,hostssl 记录将被忽略,只会记录一条警告,说明它无法匹配任何连接。
hostnossl该记录类型与 hostssl 的行为相反;它只匹配通过 TCP/IP 发起且不使用 SSL 的连接尝试。
database指定此记录匹配的数据库名称。all 表示匹配所有数据库。sameuser 表示请求的数据库与请求的用户同名时才匹配。samerole 要求请求的用户是与所请求数据库同名的角色的成员。(samegroup 是 samerole 已过时但仍被接受的写法。)对于 samerole,只有显式地直接或间接属于该角色,超级用户才被视为其成员,仅凭超级用户身份并不算。replication 表示请求物理复制连接时匹配此记录(注意,复制连接不指定任何特定数据库)。其他值则表示某个特定的 PostgreSQL 数据库的名称。可以用逗号分隔多个数据库名称。也可以在文件名前加 @,指定一个单独存放数据库名称的文件。
user指定此记录匹配的数据库用户名。all 表示匹配所有用户。其他值可以是某个特定数据库用户的名称,也可以是前面带 + 的组名。(请记住,在 PostgreSQL 中,用户和组并无实质区别;+ 实际表示“匹配直接或间接属于此角色的任何角色”,而不带 + 的名称仅匹配该角色本身。)为此,只有显式地直接或间接属于该角色,超级用户才被视为其成员,仅凭超级用户身份并不算。可以用逗号分隔多个用户名。也可以在文件名前加 @,指定一个单独存放用户名的文件。
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 地址。
此字段仅适用于 host、hostssl 和 hostnossl 记录。
用户有时会想知道为什么主机名以这种看似复杂的方式处理,包括两次名称解析,其中包括对客户端IP地址的反向查找。 如果客户端的反向DNS条目未设置或生成了一些不良的主机名,则使用该功能会变得复杂。 这主要是为了效率:这样,连接尝试最多需要两次解析器查找,一次反向查找和一次正向查找。 如果某个地址存在解析器问题,那就只会成为该客户端的问题。 一个假设的替代实现只进行正向查找的情况下,在每次连接尝试期间都必须解析pg_hba.conf中提到的每个主机名。 如果列出了许多名称,这可能会非常慢。 如果其中一个主机名存在解析器问题,那么这将成为所有人的问题。
此外,实现后缀匹配功能需要进行反向查找,因为需要知道实际客户端主机名 以便将其与模式进行匹配。
请注意,这种行为与其他流行的基于主机名的访问控制实现一致,例如 Apache HTTP服务器和TCP包装器。
IP-addressIP-mask这两个字段可以用作IP地址/掩码长度 表示法的替代方案。而不是指定掩码长度,实际掩码在一个单独的列中指定。 例如,255.0.0.0表示IPv4的CIDR掩码长度为8, 而255.255.255.255表示CIDR掩码长度为32。
这些字段仅适用于 host、hostssl 和 hostnossl 记录。
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。
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 记录中指定。将其设为 1 时,除了满足认证方法的其他要求外,客户端还必须提供有效(受信任)的 SSL 证书。
由 @ 构造引用的文件会被读取为名称列表,其中的名称可以用空白或逗号分隔。注释仍然用 # 引入,与 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)使其重新读取该文件。
前面的说明在Microsoft Windows上不为真:在Windows上,pg_hba.conf文件中的任何更改会立即被应用到后续的新连接上。
系统视图pg_hba_file_rules 有助于预先测试对 pg_hba.conf 文件的修改,也可以在加载该文件没有产生预期效果时用于诊断问题。视图中 error 字段非空的行表示文件对应行存在问题。
要连接到一个特定数据库,一个用户必须不仅要通过pg_hba.conf检查,还必须要有该数据库上的CONNECT权限。如果你希望限制哪些用户能够连接到哪些数据库,授予/撤销CONNECT权限通常比在pg_hba.conf项中设置规则简单。
Example 20.1 展示了一些 pg_hba.conf 条目示例。有关不同认证方法的详细信息,参见下一节。
Example 20.1. 示例 pg_hba.conf 项
# Allow any user on the local system to connect to any database with # any database user name using Unix-domain sockets (the default for local # connections). # # TYPE DATABASE USER ADDRESS METHOD local all all trust # The same using local loopback TCP/IP connections. # # TYPE DATABASE USER ADDRESS METHOD host all all 127.0.0.1/32 trust # The same as the previous line, but using a separate netmask column # # TYPE DATABASE USER IP-ADDRESS IP-MASK METHOD host all all 127.0.0.1 255.255.255.255 trust # The same over IPv6. # # TYPE DATABASE USER ADDRESS METHOD host all all ::1/128 trust # The same using a host name (would typically cover both IPv4 and IPv6). # # TYPE DATABASE USER ADDRESS METHOD host all all localhost trust # Allow any user from any host with IP address 192.168.93.x to connect # to database "postgres" as the same user name that ident reports for # the connection (typically the operating system user name). # # TYPE DATABASE USER ADDRESS METHOD host postgres all 192.168.93.0/24 ident # Allow any user from host 192.168.12.10 to connect to database # "postgres" if the user's password is correctly supplied. # # TYPE DATABASE USER ADDRESS METHOD host postgres all 192.168.12.10/32 scram-sha-256 # Allow any user from hosts in the example.com domain to connect to # any database if the user's password is correctly supplied. # # Require SCRAM authentication for most users, but make an exception # for user 'mike', who uses an older client that doesn't support SCRAM # authentication. # # TYPE DATABASE USER ADDRESS METHOD host all mike .example.com md5 host all all .example.com scram-sha-256 # In the absence of preceding "host" lines, these two lines will # reject all connections from 192.168.54.1 (since that entry will be # matched first), but allow GSSAPI connections from anywhere else # on the Internet. The zero mask causes no bits of the host IP # address to be considered, so it matches any host. # # TYPE DATABASE USER ADDRESS METHOD host all all 192.168.54.1/32 reject host all all 0.0.0.0/0 gss # Allow users from 192.168.x.x hosts to connect to any database, if # they pass the ident check. If, for example, ident says the user is # "bryanh" and he requests to connect as PostgreSQL user "guest1", the # connection is allowed if there is an entry in pg_ident.conf for map # "omicron" that says "bryanh" is allowed to connect as "guest1". # # TYPE DATABASE USER ADDRESS METHOD host all all 192.168.0.0/16 ident map=omicron # If these are the only three lines for local connections, they will # allow local users to connect only to their own databases (databases # with the same name as their database user name) except for administrators # and members of role "support", who can connect to all databases. The file # $PGDATA/admins contains a list of names of administrators. Passwords # are required in all cases. # # TYPE DATABASE USER ADDRESS METHOD local sameuser all md5 local all @admins md5 local all +support md5 # The last two lines above can be combined into a single line: local all @admins,+support md5 # The database column can also use lists and file names: local db1,db2,@demodbs all md5