2024 年 9 月 26 日: PostgreSQL 17 发布!
支持的版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不支持的版本:11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

18.9. 使用 SSL 的安全 TCP/IP 连接 #

PostgreSQL 原生支持使用SSL连接来加密客户端/服务器通信,以增强安全性。这要求在客户端和服务器系统上都安装了 OpenSSL,并且在编译时启用了 PostgreSQL 中的支持(参见 第 17 章)。

术语SSLTLS通常可以互换使用,表示使用TLS协议的安全加密连接。SSL协议是TLS协议的前身,术语SSL仍然用于加密连接,即使SSL协议不再受支持。SSLPostgreSQL 中与TLS互换使用。

18.9.1. 基本设置 #

启用SSL支持后,PostgreSQL 服务器可以通过设置参数 sslpostgresql.conf 中为 on,来启动支持加密连接使用TLS协议。服务器将在同一个 TCP 端口上监听普通连接和SSL连接,并将与任何连接的客户端协商是否使用SSL。默认情况下,这由客户端决定;参见 第 20.1 节 关于如何设置服务器以要求使用SSL进行某些或所有连接。

要以SSL模式启动,必须存在包含服务器证书和私钥的文件。默认情况下,这些文件预计分别命名为 server.crtserver.key,位于服务器的数据目录中,但可以使用配置参数 ssl_cert_filessl_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。相反,客户端必须拥有服务器证书链的根证书。

18.9.2. OpenSSL 配置 #

PostgreSQL 读取系统范围的 OpenSSL 配置文件。默认情况下,此文件名为 openssl.cnf,位于 openssl version -d 报告的目录中。此默认值可以通过将环境变量 OPENSSL_CONF 设置为所需配置文件的名称来覆盖。

OpenSSL 支持各种强度不同的密码和身份验证算法。虽然可以在 OpenSSL 配置文件中指定密码列表,但可以通过修改 postgresql.conf 中的 ssl_ciphers 来指定专门供数据库服务器使用的密码。

注意

可以使用 NULL-SHANULL-MD5 密码进行身份验证,而不会产生加密开销。但是,中间人可以读取和传递客户端和服务器之间的通信。此外,与身份验证的开销相比,加密开销很小。出于这些原因,不推荐使用 NULL 密码。

18.9.3. 使用客户端证书 #

要要求客户端提供受信任的证书,请将您信任的根证书颁发机构 (CAs) 的证书放在数据目录中的文件中,将参数 ssl_ca_filepostgresql.conf 中设置为新文件名,并将身份验证选项 clientcert=verify-caclientcert=verify-full 添加到 pg_hba.conf 中相应的 hostssl 行。然后,在 SSL 连接启动期间,将从客户端请求证书。(参见 第 32.19 节,了解如何在客户端上设置证书。)

对于带有 clientcert=verify-cahostssl 条目,服务器将验证客户端证书是否由其中一个受信任的证书颁发机构签名。如果指定了 clientcert=verify-full,则服务器不仅会验证证书链,还会检查用户名或其映射是否与提供的证书的 cn(公用名)匹配。请注意,当使用 cert 身份验证方法时,始终会确保证书链验证(参见 第 20.12 节)。

如果希望避免在客户端上存储它们(假设根证书和中间证书是用 v3_ca 扩展创建的),则链接到现有根证书的中间证书也可以出现在 ssl_ca_file 文件中。如果设置了参数 ssl_crl_filessl_crl_dir,也会检查证书吊销列表 (CRL) 条目。

clientcert 身份验证选项适用于所有身份验证方法,但仅适用于指定为 hostsslpg_hba.conf 行。如果未指定 clientcert,则服务器仅在提供客户端证书且配置了 CA 时,才会将其与 CA 文件进行验证。

强制用户在登录时提供证书有两种方法。

第一种方法利用 pg_hba.confhostssl 条目的 cert 身份验证方法,这样证书本身就用于身份验证,同时还提供 ssl 连接安全性。有关详细信息,请参见 第 20.12 节。(使用 cert 身份验证方法时,不必显式指定任何 clientcert 选项。)在这种情况下,证书中提供的 cn(公用名)将与用户名或适用的映射进行检查。

第二种方法将 hostssl 条目的任何身份验证方法与客户端证书验证相结合,方法是将 clientcert 身份验证选项设置为 verify-caverify-full。前一个选项仅强制执行证书有效,而后一个选项还确保证书中的 cn(公用名)与用户名或适用的映射匹配。

18.9.4. SSL 服务器文件使用 #

表 18.2 总结了与服务器上的 SSL 设置相关的文件。(显示的文件名是默认名称。本地配置的名称可能不同。)

表 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 连接。在所有这些情况下,错误状况都会在服务器日志中报告。

18.9.5. 创建证书 #

要为服务器创建一个简单的自签名证书,有效期为 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.crtserver.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.crtintermediate.crt 应连接到一个证书文件捆绑包中,并存储在服务器上。 server.key 也应存储在服务器上。 root.crt 应存储在客户端上,以便客户端可以验证服务器的叶子证书是否由链接到其受信任的根证书的证书链签署。 root.keyintermediate.key 应脱机存储,以便用于创建将来的证书。

提交更正

如果您在文档中看到任何不正确的内容,不符合您对特定功能的体验,或者需要进一步澄清,请使用 此表格 报告文档问题。