PostgreSQL原生支持使用SSL连接来加密客户端与服务器之间的通信,以提高安全性。这要求客户端和服务器系统上都安装了OpenSSL,并且在构建PostgreSQL时启用了该支持(见Chapter 17)。
术语SSL和TLS经常被交替使用,用来表示基于TLS协议的安全加密连接。SSL协议是TLS协议的前身,尽管SSL协议本身已不再受支持,SSL一词仍常被用来泛指这类加密连接。在PostgreSQL中,SSL与TLS也是这样互换使用的。
如果构建时启用了SSL支持,那么只需在postgresql.conf中把参数ssl设为on,PostgreSQL服务器就可以启用基于TLS协议的加密连接支持。服务器会在同一个 TCP 端口上同时监听普通连接和SSL连接,并与每个连接进来的客户端协商是否使用SSL。默认情况下,这由客户端决定;关于如何把服务器配置为要求某些或全部连接必须使用SSL,请参阅Section 20.1。
要以SSL模式启动服务器,必须存在包含服务器证书和私钥的文件。默认情况下,这些文件应分别命名为server.crt和server.key,并放在服务器的数据目录中;不过也可以通过配置参数ssl_cert_file和ssl_key_file指定其他名称和位置。
在 Unix 系统上,server.key的权限必须禁止组和其他用户访问;可以通过chmod 0600 server.key实现。或者,该文件也可以由 root 拥有并授予组读权限(即0640)。这种设置适用于证书和密钥文件由操作系统统一管理的安装方式。运行PostgreSQL服务器的用户此时应属于有权访问这些证书和密钥文件的组。
如果数据目录允许组读取访问,那么为了满足上面概述的安全要求,证书文件可能需要放在数据目录之外。通常,启用组访问权限是为了允许非特权用户备份数据库;在这种情况下,备份软件将无法读取证书文件,并且很可能会报错。
如果私钥受密码保护,服务器会提示输入该密码,并在输入之前不会启动。默认情况下,使用密码会禁用无需重启服务器即可更改 SSL 配置的能力,不过参见ssl_passphrase_command_supports_reload。此外,在 Windows 上完全无法使用带密码保护的私钥。
server.crt中的第一个证书必须是服务器证书,因为它必须与服务器私钥相匹配。“中间”证书颁发机构的证书也可以追加到该文件中。假设根证书和中间证书是使用v3_ca扩展创建的(这会将证书的 CA 基本约束设为 true),这样做就可以避免在客户端上存储中间证书。同时,这也使中间证书更容易单独过期。
无需把根证书加入server.crt。相反,客户端必须持有服务器证书链对应的根证书。
PostgreSQL会读取系统范围的OpenSSL配置文件。默认情况下,该文件名为openssl.cnf,位于openssl version -d报告的目录中。可以通过把环境变量OPENSSL_CONF设为所需配置文件的名称,覆盖这一默认值。
OpenSSL支持种类繁多、强度不一的密码套件和认证算法。虽然可以在OpenSSL配置文件中指定密码套件列表,但你也可以通过修改postgresql.conf中的ssl_ciphers,专门为数据库服务器指定要使用的密码套件。
使用NULL-SHA或NULL-MD5密码套件,可以在几乎没有加密开销的情况下完成认证。不过,中间人仍然能够读取并转发客户端与服务器之间的通信。此外,与认证的开销相比,加密开销本身通常很小。基于这些原因,不建议使用 NULL 密码套件。
若要要求客户端提供受信任的证书,请把你信任的根证书颁发机构(CA)证书放入数据目录中的某个文件里,在postgresql.conf中把参数ssl_ca_file设为该文件名,并在pg_hba.conf中相应的hostssl行上添加认证选项clientcert=verify-ca或clientcert=verify-full。这样,SSL 连接启动时就会向客户端请求证书。(关于如何在客户端设置证书,请见Section 32.19。)
对于带有clientcert=verify-ca的hostssl条目,服务器会验证客户端证书是否由某个受信任的证书颁发机构签署。如果指定的是clientcert=verify-full,服务器不仅会验证证书链,还会检查用户名或其映射是否与所提供证书的cn(通用名称)相匹配。请注意,在使用cert认证方法时,总会确保进行证书链验证(见Section 20.12)。
如果你希望避免在客户端上存储中间证书,那么与现有根证书构成链的中间证书也可以出现在ssl_ca_file文件中(前提是根证书和中间证书是使用v3_ca扩展创建的)。如果设置了参数ssl_crl_file或ssl_crl_dir,还会检查证书吊销列表(CRL)条目。
clientcert认证选项适用于所有认证方法,但只适用于pg_hba.conf中指定为hostssl的行。未指定clientcert时,只有在客户端实际提供了证书且配置了 CA 的情况下,服务器才会依据其 CA 文件验证客户端证书。
有两种方法可以强制用户在登录时提供证书。
第一种方法是在pg_hba.conf的hostssl条目上使用cert认证方法,这样证书本身就会用于认证,同时也提供 SSL 连接安全性。详见Section 20.12。(使用cert认证方法时,无需显式指定任何clientcert选项。)在这种情况下,会检查证书中的cn(通用名称)是否与用户名或适用映射相匹配。
第二种方法是在hostssl条目上结合任意认证方法和客户端证书验证,即把clientcert认证选项设为verify-ca或verify-full。前者只强制证书有效,后者则还会确保证书中的cn(通用名称)与用户名或适用映射相匹配。
Table 18.2概括了服务器端 SSL 设置相关的文件。(表中显示的是默认文件名;本地实际配置的名称可能不同。)
Table 18.2. SSL 服务器文件用法
| 文件 | 内容 | 效果 |
|---|---|---|
ssl_cert_file ($PGDATA/server.crt) |
服务器证书 | 发送给客户端,用于表明服务器身份 |
ssl_key_file ($PGDATA/server.key) |
服务器私钥 | 证明服务器证书是其所有者发送的,并不说明证书所有者是值得信任的 |
| ssl_ca_file | 可信的证书颁发机构 | 检查客户端证书是由一个可信的证书颁发机构签名的 |
| ssl_crl_file | 被证书颁发机构吊销的证书 | 客户端证书不能出现在这个列表上 |
服务器会在启动时以及每次重新加载配置时读取这些文件。在Windows系统上,每当为新的客户端连接生成新的后端进程时,也会重新读取它们。
如果在服务器启动时检测到这些文件有错误,服务器将拒绝启动。但如果在重新加载配置时检测到错误,这些文件会被忽略,旧的 SSL 配置将继续使用。在Windows系统上,如果在后端启动时检测到这些文件有错误,该后端将无法建立 SSL 连接。在所有这些情况下,错误都会记录到服务器日志中。
要为服务器创建一个有效期为 365 天的简单自签名证书,可以使用下面的OpenSSL命令,并将dbhost.yourdomain.com替换为服务器主机名:
openssl req -new -x509 -days 365 -nodes -text -out server.crt \
-keyout server.key -subj "/CN=dbhost.yourdomain.com"
然后执行:
chmod og-rwx server.key
如果该文件权限比这更宽松,服务器会拒绝使用它。关于如何创建服务器私钥和证书的更多细节,请参阅OpenSSL文档。
虽然自签名证书可用于测试,但在生产环境中应使用由证书颁发机构(CA,通常是企业范围内的根 CA)签名的证书。
要创建一个可由客户端验证其身份的服务器证书,首先要创建证书签名请求(CSR)以及公钥/私钥文件:
openssl req -new -nodes -text -out root.csr \
-keyout root.key -subj "/CN=root.yourdomain.com"
chmod og-rwx root.key
然后,使用该密钥对请求进行签名,以创建一个根证书颁发机构(这里使用的是Linux上OpenSSL配置文件的默认位置):
openssl x509 -req -in root.csr -text -days 3650 \ -extfile /etc/ssl/openssl.cnf -extensions v3_ca \ -signkey root.key -out root.crt
最后,创建一个由新根证书颁发机构签名的服务器证书:
openssl req -new -nodes -text -out server.csr \
-keyout server.key -subj "/CN=dbhost.yourdomain.com"
chmod og-rwx server.key
openssl x509 -req -in server.csr -text -days 365 \
-CA root.crt -CAkey root.key -CAcreateserial \
-out server.crt
server.crt和server.key应存放在服务器上,而root.crt应存放在客户端上,以便客户端能够验证服务器的叶子证书是否由其受信任的根证书签名。root.key应离线保存,以供将来签发证书时使用。
也可以创建包含中间证书的信任链:
# root openssl req -new -nodes -text -out root.csr \ -keyout root.key -subj "/CN=root.yourdomain.com" chmod og-rwx root.key openssl x509 -req -in root.csr -text -days 3650 \ -extfile /etc/ssl/openssl.cnf -extensions v3_ca \ -signkey root.key -out root.crt # intermediate openssl req -new -nodes -text -out intermediate.csr \ -keyout intermediate.key -subj "/CN=intermediate.yourdomain.com" chmod og-rwx intermediate.key openssl x509 -req -in intermediate.csr -text -days 1825 \ -extfile /etc/ssl/openssl.cnf -extensions v3_ca \ -CA root.crt -CAkey root.key -CAcreateserial \ -out intermediate.crt # leaf openssl req -new -nodes -text -out server.csr \ -keyout server.key -subj "/CN=dbhost.yourdomain.com" chmod og-rwx server.key openssl x509 -req -in server.csr -text -days 365 \ -CA intermediate.crt -CAkey intermediate.key -CAcreateserial \ -out server.crt
server.crt和intermediate.crt应拼接为一个证书文件包并存放在服务器上。server.key也应存放在服务器上。root.crt应存放在客户端上,以便客户端验证服务器的叶子证书是否由一条可追溯到其受信任根证书的证书链签名。root.key和intermediate.key应离线保存,以供将来签发证书时使用。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。