Postgresql 中文操作指南

19.9. Secure TCP/IP Connections with SSL #

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

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

19.9.1. Basic Setup #

在编译了 SSL 支持的情况下,可以通过设置 postgresql.conf 中的参数 sslon 来启动 PostgreSQL 服务器,使其支持使用 TLS 协议进行加密连接。服务器将在同一 TCP 端口上侦听正常连接和 SSL 连接,并将与任何连接的客户端协商是否使用 SSL。默认情况下,这在客户端的选择中;有关如何设置服务器以要求某些或所有连接使用 SSL,请参见 Section 21.1

要在 SSL 模式下启动,必须存在包含服务器证书和私钥的文件。默认情况下,这些文件分别位于服务器数据目录中,但可以使用配置参数 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 Configuration #

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

OpenSSL 支持各种强度各异的密码和身份验证算法。可以在 OpenSSL 配置文件中指定密码列表,也可以通过修改 _postgresql.conf_中的 ssl_ciphers,指定特定密码供数据库服务器使用。

Note

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

19.9.3. Using Client Certificates #

要要求客户端提供可信证书,请将您信任的根证书颁发机构 (CA) 的证书放在数据目录中的一个文件中,将 _postgresql.conf_中的参数 ssl_ca_file设置为新的文件名,并在 _pg_hba.conf_中将身份验证选项 _clientcert=verify-ca_或 _clientcert=verify-full_添加到适当的 _hostssl_行中。然后,将在 SSL 连接启动期间向客户端请求证书。(有关如何在客户端上设置证书的说明,请参阅 Section 34.19。)

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

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

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

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

第一个方法对 pg_hba.conf_中 _hostssl_条目的 _cert_身份验证方法进行了使用,因此该方法使用证书本身进行身份验证,同时还提供 SSL 连接安全。有关详细信息,请参阅 Section 21.12。(使用 _cert_身份验证方法时,无需显式指定任何 _clientcert_选项。)在这种情况下,证书中提供的 _cn(通用名称)会与用户名或适用的映射进行比较。

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

19.9.4. SSL Server File Usage #

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

Table 19.2. SSL Server File Usage

File

Contents

Effect

ssl_cert_file ($PGDATA/server.crt)

server certificate

发送给客户端以指示服务器的标识

ssl_key_file ($PGDATA/server.key)

server private key

证明服务器证书是由所有者发送的;不表示证书所有者是可信的

ssl_ca_file

trusted certificate authorities

检查客户端证书是否由受信任的证书颁发机构签名

ssl_crl_file

证书颁发机构吊销的证书

客户端证书不得在此列表中

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

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

19.9.5. Creating Certificates #

若要为服务器创建一个简单的自签名证书,有效期为 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 应离线存储,以用于创建将来的证书。