PostgreSQL 9.5

客户端认证

当一个客户端应用连接一个数据库服务器时,它将指定以哪个PostgreSQL 数据库用户名连接,就像我们以一个特定用户登录一台 Unix 计算机一样。在 SQL 环境中,活动的数据库用户名决定对数据库对象的访问权限
认证是数据库服务器建立客户端身份的过程,并且服务器决定客户端应用(或者运行客户端应用的用户)是否被允许以请求的数据库用户名来连接。
PostgreSQL提供多种不同的客户端认证方式。被用来认证一个特定客户端连接的方法可以基于(客户端)主机地址、数据库和用户来选择。
PostgreSQL数据库用户名在逻辑上是和服务器运行的操作系统中的用户名相互独立的。

1. pg_hba.conf文件

客户端认证是由一个配置文件(通常名为pg_hba.conf并被存放在数据库集簇目录中)控制(HBA表示基于主机的认证)。
在initdb初始化数据目录时,它会安装一个默认的pg_hba.conf文件。
yum 安装的路径
[root@mysqlhq data]# pwd
/var/lib/pgsql/data
pg_hba.conf文件的常用格式是一组记录,每行一条。空白行将被忽略, #注释字符后面的任何文本也被忽略。记录不能跨行。
一条记录由若干用空格 和/或制表符分隔的域组成。如果域值用双引号包围,那么它可以包含空白。
每条记录指定一种连接类型、一个客户端 IP 地址范围(如果和连接类型相关)、一个数据库名、一个用户名以及对匹配这些参数的连接使用的认证方法。
如果选择了一条记录而且认证失败,那么将不再考虑后面的记录。如果没有匹配的记录,那么访问将被拒绝。
记录可以是下面七种格式之一:
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]
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]
各个域的含义如下:
local 这条记录匹配企图使用 Unix 域套接字的连接。如果没有这种类型的记录,就不允许Unix 域套接字连接
host 这条记录匹配企图使用 TCP/IP 建立的连接。host记录匹配SSL和非SSL的连接尝试。
  注意: 除非服务器带着合适的listen_addresses配置参数值启动,否则将不可能进行远程的
  TCP/IP 连接,因为默认的行为是只监听在本地环回地址localhost上的 TCP/IP 连接。
  hostssl 这条记录匹配企图使用 TCP/IP 建立的连接,但必须是使用SSL加密的连接。
  要使用这个选项,编译服务器的时候必须打开SSL支持。此外,在服务器启动的时候必
  须通过设置ssl配置参数打开SSL。
hostnossl 这条记录的行为与hostssl相反;它只匹配那些在 TCP/IP上不使用SSL的连接企图。
database 指定记录所匹配的数据库名称。值all指定该记录匹配所有数据库。
  值 sameuser指定如果被请求的数据库和请求的用户同名,则匹配。
  值samerole指定请求的用户必须是一个与数据库同名的角色中的成员
  通过用逗号分隔的方法指定多个数据库,也可以通过在文件名前面放@来指定一个包含数据库名的文件
user 指定这条记录匹配哪些数据库用户名。值all指定它匹配所有用户。
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 回环地址), 一个小型网络的 IPv6地址范围则类似于:fe80::7a31:c1ff:0000:0000/96。
  0.0.0.0/0表示所有 IPv4 地址,并且::0/0表示所有 IPv6 地址。
  要指定一个单一主机,IPv4 用一个长度为 32 的CIDR 掩码或者 IPv6 用 长度为 128 的 CIDR 掩码。在一个网络地址中,不要省略结尾的零。
  你也可以写all来匹配任何 IP 地址、写samehost来匹配任何本服务器自身的 IP 地址或者写samenet来匹配本服务器直接连接到的任意子网的任意地址

  若果指定了一个主机名(任何除 IP 地址单位或特殊关键字之外的都被作为主机名处理), 该名称会与客户端的 IP 地址的反向名字解析
  结果进行比较。主机名比较是大小写敏感的。
  一个以点号(.)开始的主机名声明匹配实际主机名的后缀。因此.example.com将匹配foo.example.com(但不匹配example.com)。
  当 主 机 名 在pg_hba.conf中 被 指 定 时 , 你 应 该 保 证 名 字 解 析 很 快 。 建 立 一 个 类似nscd的本地名字解析缓存是一种不错的选择。
  另外,你可能希望启用配置参数log_hostname来在日志中查看客户端的主机名而不是 IP 地址。
  这个域只适用于host、 hostssl和hostnossl记录。
IP-address
IP-mask这两个域可以被用作IP-address/ mask-length记号法的替代方案。和指定掩码长度不
  同,实际的掩码被指 定在一个单独的列中。例如,255.0.0.0表示 IPv4 CIDR 掩码长度8,而255.255.255.255表示 CIDR 掩码长度 32。
auth-method指定当一个连接匹配这个记录时,要使用的认证方法。
  详细:
    trust 无条件地允许连接。这种方法允许任何可以与PostgreSQL数据库服务器连接的用户以他们期望的任意PostgreSQL数据库用户身份登入,而不需要口令或者其他任何认证。
    reject 无条件地拒绝连接。这有助于从一个组中“过滤出”特定主机,
    md5要求客户端提供一个双重 MD5 加密的口令进行认证。
    password 要求客户端提供一个未加密的口令进行认证。因为口令是以明文形式在网络上发送的,所以我们不应该在不可信的网络上使用这种方式。
    gss用 GSSAPI 认证用户。只对 TCP/IP 连接可用。
    sspi用 SSPI 来认证用户。只在 Windows 上可用。
    ident通过联系客户端的 ident 服务器获取客户端的操作系统名,并且检查它是否匹配被请求的数据库用户名。
    Ident 认证只能在 TCIP/IP 连接上使用。当为本地连接指定这种认证方式时,将用 peer 认证来替代。
    peer从操作系统获得客户端的操作系统用户,并且检查它是否匹配被请求的数据库用户名。这只对本地连接可用。
    ldap使用LDAP服务器认证。
    radius用 RADIUS 服务器认证。
    cert使用 SSL 客户端证书认证。
    pam使用操作系统提供的可插入认证模块服务(PAM)认证。
auth-options在auth-method域的后面,可以是形如name=value的域,它们指定认证方法的选项
  用@结构包括的文件被读作一个名字列表,它们可以用空白或者逗号分隔。注释用#引入,就
  像在pg_hba.conf中那样,并且允许嵌套@结构。除非跟在@后面的文件名是一个绝对路径,
  文件名都被认为是相对于包含引用文件的目录。
  因为每一次连接尝试都会顺序地检查pg_hba.conf记录,所以这些记录的顺序是非常关键的。
  在启动以及主服务器进程收到SIGHUP信号时,pg_hba.conf文件会被读取。 如果你在活动
  的系统上编辑了该文件,你将需要通知 postmaster(使用pg_ctl reload或kill -HUP)重
  新读取该文件。
  提示: 要连接到一个特定数据库,一个用户必须不仅要通过pg_hba.conf检查,还必须要有该数
  据库上的CONNECT权限。如果你希望限制哪些用户能够连接到哪些数据库,授予/撤销CONNECT权
  限通常比在pg_hba.conf项中设置规则简单。
示例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

# 允许来自任意具有 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 md5

# 如果用户的口令被正确提供,允许 example.com 中主机上的任意用户连接到任意数据库。
# TYPE DATABASE USER ADDRESS METHOD
host all all .example.com md5

# 如果没有前面的 "host" 行,这两行将拒绝所有来自 192.168.54.1的连接(因为那些项将首先被匹配),
# 但是允许来自互联网其他任何地方的GSSAPI 连接。零掩码导致主机IP 地址中的所有位都不会被考虑,
# 因此它匹配任意主机。
# TYPE DATABASE USER ADDRESS METHOD
host all all 192.168.54.1/32 reject
host all all 0.0.0.0/0 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

# 如果这些是本地连接的唯一三行,它们将允许本地用户只连接到它们自己的数据库(与其数据库用户名
# 同名的数据库),不过管理员和角色 "support" 的成员除外(它们可以连接到所有数据库)。文件
# $PGDATA/admins 包含一个管理员名字的列表。在所有情况下都要求口令。
# TYPE DATABASE USER ADDRESS METHOD
local sameuser all md5
local all @admins md5
local all +support md5
# 上面的最后两行可以被整合为一行:
local all @admins,+support md5
# 数据库列也可以用列表和文件名:
local db1,db2,@demodbs all md5

2. 用户名映射

当使用像 Ident 或者 GSSAPI 外部认证系统时,发起连接的操作系统用户名可能不同于他要使用的数据库用户。
在这种情况下,一个用户名映射可被用来把操作系统用户名映射到数据库用户。要使用用户名映射,在pg_hba.conf的选项域指定map=map-name。
此选项支持所有接收外部用户名的认证方法。由于不同的连接可能需要不同的映射,在pg_hba.conf中的map-name参数
中指定要被使用的映射名,用以指示哪个映射用于每个个体连接。
map-name system-username database-username
map-name是一个任意名称,它将被用于在pg_hba.conf中引用该映射。其他两个域指定一个操作系统用户名和一个匹配的数据库用
户名。相同的map-name可以被反复地用在同一个映射中指定多个用户映射。
对于一个给定操作系统用户可以对应多少个数据库用户没有限制,反之亦然。
mymap /^(.*)@mydomain\.com$ \1
mymap /^(.*)@otherdomain\.com$ guest
将 为 用 户 移 除 以@mydomain.com结 束 的 系 统 用 户 名 的 域 部 分 , 以 及 允 许 系 统 名
以@otherdomain.com结束的任意用户作为guest登入。
提示: 记住在默认情况下,一个正则表达式可以只匹配字符串的一部分。如上例所示,使
用^和$来强制匹配整个系统用户名通常是明智的。
一个示例pg_ident.conf 文件
# MAPNAMESYSTEM-USERNAMEPG-USERNAME
omicronbryanhbryanh
omicronannann
# bob 在这些机器上有用户名robert
omicronrobertbob
# bryanh 也可以作为 guest1 连接
omicronbryanhguest1

3. 认证方法

3.1. 信任认证

当trust认证被指定时,PostgreSQL假设任何可以连接到服务器的人都被授权使用他们指定
的任何数据库用户名(即使是超级用户)访问数据库。当然,在database和 user列中设置
的限制仍然适用。只有当在操作系统层对进入服务器的连接有足够保护时,才应该使用这种
方法。
trust认证对于单用户工作站的本地连接是非常合适和方便的。通常它本身不适用于一台多用户机器。

3.2. 口令认证

基于口令的认证方法是md5和password。即分别是 MD5 哈希以及明文。
md5不能和db_user_namespace特性一起使用,如果连接受SSL加密保护,那么password可以被安全地使用。
PostgreSQL数据库口令独立于操作系统用户口令。每个数据库用户的口令被存储在pg_authid系统目录中。
口令可以用 SQL 命令CREATE USER和ALTER ROLE管理,例如CREATE USER foo WITH PASSWORD ’secret’。
如果没有为一个用户设置口令,那么存储的口令为空并且对该用户的口令认证总会失败。

3.3. GSSAPI 认证

GSSAPI是用于 RFC 2743 中定义的安全认证的一个工业标准协议。
PostgreSQL根据 RFC 1964支持带Kerberos认证的GSSAPI。GSSAPI为支持它的系统提供自动认证(单点登录)。认证
本身是安全的,但通过数据库连接发送的数据将不被加密,除非使用SSL。

3.4. SSPI 认证

SSPI是一种用于带单点登录的安全认证的Windows技术。

3.5. Ident 认证

ident 认证方法通过从一个 ident 服务器获得客户端的操作系统用户名并且用它作为被允许的
数据库用户名(和可选的用户名映射)来工作。它只在 TCP/IP 连接上支持。
注意: 当为一个本地(非 TCP/IP)连接指定 ident 时,将实际使用 peer 认证
实际上每个类 Unix 操作系统都带着一个默认监听 TCP 113 端口的 ident 服务器。ident 服务器的基本功能是回答类似这样的问
题:“哪个用户从你的端口X发起了连接并且连到了我的端口Y?” 。因为当一个物理连接被建立后,PostgreSQL既知道X也知道Y,
所以它可以询问尝试连接的客户端主机上的 ident 服务器并且在理论上可以判断任意给定连接的操作系统用户。

3.6. Peer 认证

Peer 认证方法通过从内核获得客户端的操作系统用户名并把它用作被允许的数据库用户名
(和可选的用户名映射)来工作。这种方法只在本地连接上支持。
Peer 认证只在提供getpeereid()函数、SO_PEERCRED套接字参数或相似机制的操作系统上
可用。这些 OS 当前包括Linux、大部分的BSD包括OS X以及Solaris。

3.7. LDAP 认证

这种认证方法操作起来类似于password, 只不过它使用 LDAP 作为密码验证方法。LDAP
只被用于验证用户名/口令对。因此,在使用 LDAP 进行认证之前,用户必须已经存在于数据
库中。

3.8. RADIUS 认证

这种认证方法的操作类似于password,不过它使用 RADIUS 作为密码验证方式。RADIUS
只被用于验证 用户名/密码对。因此,在 RADIUS 能被用于认证之前,用户必须已经存在于
数据库中。

3.9. 证书认证

这种认证方法使用 SSL 客户端证书执行认证。因此,它只适用于 SSL 连接。当使用这种认
证方法时,服务器将要求客户端提供一个有效的证书。不会有密码提示将被发送到客户端。
证书的cn(通用名)属性将与被请求的数据库用户名进行比较,并且如果匹配将允许登录。
用户名映射可以被用来允许cn与数据库用户名不同。

3.10. PAM 认证

这种认证方法操作起来类似password, 只不过它使用 PAM (插入式验证模块)作为认证
机制。默认的 PAM 服务名是postgresql。PAM 只被用于验证用户名/口令对。因此,在
使用 PAM 进行认证之前,用户必须已经存在于数据库中。
注意: 如果 PAM 被设置为读取/etc/shadow,认证将会失败,因为 PostgreSQL 服务器是由一个
非 root 用户启动 。然而,当 PAM 被配置为使用 LDAP 或其他认证验证方法时这就不是一个问
题。

4. 认证问题

认证失败以及相关的问题通常由类似下面的错误消息显示:
FATAL: no pg_hba.conf entry for host "123.123.123.123", user "andym", database "testdb"
最可能出现的情况是你成功地联系了服务器,但它不愿意和你说话。就像消息本身
所建议的,服务器拒绝了连接请求,因为它没有在其pg_hba.conf配置文件里找到匹配项。

FATAL: password authentication failed for user "andym"
表示你联系了服务器,并且它也愿意和你交谈,但是你必须通过pg_hba.conf文
件中指定的认证方法。检查你提供的口令,或者如果错误消息提到了 Kerberos 或 ident 认证
类型,检查那些软件。

FATAL: user "andym" does not exist
指示的数据库用户没有被找到。

FATAL: database "testdb" does not exist
你试图连接的数据库不存在。请注意如果你没有声明数据库名,默认会用数据库用户名作为
数据库名,这可能正确也可能不正确。
提示: 服务器日志可能包含比报告给客户端的更多的有关认证失败的信息。如果你为失败的原因
而困惑,那么请检查服务器日志。

05-24 04:19