Skip to content

19.9. 使用 SSL 保护 TCP/IP 连接#

19.9.1. 基本设置
19.9.2. OpenSSL 配置
19.9.3. 使用客户端证书
19.9.4. SSL 服务器文件用法
19.9.5. 创建证书

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

SSL和TLS这两个术语通常可以互换使用,表示使用TLS协议的安全加密连接。SSL协议是TLS协议的前身,即使SSL协议不再受支持,SSL一词仍然用于加密连接。SSL在PostgreSQL中与TLS可以互换使用。

19.9.1. 基本设置#

在编译了SSL支持后,可以通过设置postgresql.conf中的参数sslon来启动PostgreSQL服务器,并支持使用启用了TLS协议的加密连接。服务器将在同一 TCP 端口上侦听正常连接和SSL连接,并将与任何连接客户端协商是否使用SSL。默认情况下,这取决于客户端的选择;请参阅第 21.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。相反,客户端必须具有服务器证书链的根证书。

19.9.2. OpenSSL 配置#

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

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

注意

可以通过使用NULL-SHANULL-MD5密码来实现无加密开销的身份验证。但是,中间人可以读取和传递客户端和服务器之间的通信。此外,与身份验证开销相比,加密开销很小。由于这些原因,不建议使用 NULL 密码。

19.9.3. 使用客户端证书#

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

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

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

对于所有身份验证方法都提供clientcert身份验证选项,但仅在指定为hostsslpg_hba.conf行中提供。当未指定clientcert时,仅当提供客户端证书且配置了 CA 时,服务器才会根据其 CA 文件验证客户端证书。

有两种方法可以强制用户在登录期间提供证书。

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

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

19.9.4. SSL 服务器文件使用#

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

表 19.2. SSL 服务器文件使用

文件内容效果
ssl_cert_file ($PGDATA/server.crt)服务器证书发送给客户端以表明服务器的身份
ssl_key_file ($PGDATA/server.key)服务器私钥证明服务器证书是由所有者发送的;并不表明证书所有者值得信赖
ssl_ca_file受信任的证书颁发机构检查客户端证书是否由受信任的证书颁发机构签名
ssl_crl_file证书颁发机构吊销的证书客户端证书不得在此列表中

服务器在服务器启动时以及服务器配置重新加载时读取这些文件。在Windows系统上,每当为新客户端连接生成新的后端进程时,也会重新读取这些文件。

如果在服务器启动时检测到这些文件中的错误,服务器将拒绝启动。但是,如果在配置重新加载期间检测到错误,则这些文件将被忽略,并且将继续使用旧的 SSL 配置。在Windows系统上,如果在后端启动时检测到这些文件中的错误,该后端将无法建立 SSL 连接。在所有这些情况下,错误情况都会在服务器日志中报告。

19.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离线存储,以便在创建未来证书时使用。