18.9. 用 SSL 进行安全的 TCP/IP 连接

18.9.1. 基本设置
18.9.2. OpenSSL配置
18.9.3. 使用客户端证书
18.9.4. SSL 服务器文件用法
18.9.5. 创建证书

PostgreSQL有一个对使用SSL连接加密客户端/服务器通讯的本地支持,它可以增加安全性。这个特性要求在客户端和服务器端都安装OpenSSL并且在编译PostgreSQL的时候打开这个支持(见Chapter 16)。

18.9.1. 基本设置

SSL支持被编译在PostgreSQL中时,可以通过将postgresql.conf中的 ssl设置为onPostgreSQL服务器带着SSL支持被启动。 服务器在同一个 TCP 端口监听普通连接和SSL连接,并且将与任何正在连接的客户端协商是否使用SSL。默认情况下,这是客户端的选项,关于如何设置服务器来要求某些或者所有连接使用SSL请见Section 20.1

要在SSL模式中开始,必须存在包含服务器证书和私钥的文件。默认情况下,这些文件应该被分别命名为server.crtserver.key并且位于服务器的数据目录中,但也可以使用配置参数ssl_cert_filessl_key_file指定其他的名称和位置。

在Unix系统上,server.key上的权限必须不允许对全世界或组的任何访问,这可以用命令chmod 0600 server.key实现。另一种可供选择的方式是,该文件可以由根用户拥有并且有组读访问(即0640权限)。那种设置的目标是证书和密钥文件被操作系统管理的安装。用于运行PostgreSQL服务器的用户接着应该被作为能够访问那些证书和密钥文件的组的成员。

如果数据目录允许组的读访问,那么证书文件可能需要被放置在数据目录之外以便符合上面描述的安全性要求。通常,组访问会被启用以允许一个无特权用户备份数据库,在那种情况下备份软件将不能读取证书文件并且很有可能会出错。

如果私钥被密码保护着,服务器将提示要求输入密码并且在输入前不会启动。使用密码也会禁用不重启服务器更改服务器的SSL配置的能力。此外,密码保护的私钥完全不能在Windows上使用。

server.crt中的第一个证书必须是服务器的证书,因为它必须匹配该服务器的私钥。也可以在该文件中追加中间证书机构的证书。假定根证书和中间证书是用v3_ca扩展创建,这样做可以避免在客户端存储中间证书。这可以让中间证书的过期更加容易。

没有必要在server.crt中加入根证书。相反,客户端必须有服务器的证书链的根证书。

18.9.2. OpenSSL配置

PostgreSQL读取系统范围的OpenSSL配置文件。默认情况下,这个文件名为openssl.cnf并且被放置在openssl version -d所报告的目录中。通过设置环境变量OPENSSL_CONF指定你想要的配置文件名可以覆盖此默认配置。

OpenSSL支持范围广泛的密码和认证算法。而在OpenSSL配置文件可以指定一个密码列表, 你可以通过在postgresql.conf中修改ssl_ciphers来指定数据库服务器使用的专用密码。

Note

使用NULL-SHANULL-MD5可以得到身份验证但没有加密开销。不过,中间人能够读取和传递客户端和服务器之间的通信。此外,加密开销相比身份认证的开销是最小的。出于这些原因,我们建议不要使用 NULL 密码。

18.9.3. 使用客户端证书

要求客户端提供受信任的证书,把你信任的根证书颁发机构(CA)的证书放置在数据目录的一个文件中。并且修改postgresql.conf中的参数ssl_ca_file为那个新文件名,还要把认证选项clientcert=1加入到pg_hba.conf文件中合适的hostssl行上。然后将在 SSL 连接启动时从客户端请求该证书(一段对于如何在客户端设置证书的描述请见Section 34.18)。服务器将验证客户端的证书是由受信任的证书颁发机构之一签名。

如果你希望避免在客户端上存储中间证书(假定根证书和中间证书用v3_ca扩展创建),链到已有根证书的中间证书还可以出现在ssl_ca_file文件中。如果参数ssl_crl_file被设置,还将检查证书撤销列表(CRL)项(这哪是SSL证书用法的图请见http://h41379.www4.hpe.com/doc/83final/ba554_90007/ch04s02.html)。

clientcert认证选项适用于所有的认证方法,但仅适用于pg_hba.conf中用hostssl指定的行。 当clientcert没有指定或设置为 0时,如果配置了 CA 文件,服务器将仍然会根据它验证任何提交的客户端证书 — 但是它将不会坚持要求出示一个客户端证书。

如果你在设置客户端证书,你可能希望用cert认证方法,这样证书控制用户认证以及提供连接安全。详见Section 20.12(在使用cert认证方法时,没有必要显式地指定clientcert=1)。

18.9.4. SSL 服务器文件用法

Table 18.2总结了与服务器上 SSL 配置有关的文件(显示的文件名是默认的或者是经典名称。本地配置的名称可能会不同)。

Table 18.2. SSL 服务器文件用法

文件内容效果
ssl_cert_file ($PGDATA/server.crt)服务器证书发送给客户端来说明服务器的身份
ssl_key_file ($PGDATA/server.key)服务器私钥证明服务器证书是其所有者发送的,并不说明证书所有者是值得信任的
ssl_ca_file ($PGDATA/root.crt)可信的证书颁发机构检查客户端证书是由一个可信的证书颁发机构签名的
ssl_crl_file ($PGDATA/root.crl)被证书授权机构撤销的证书客户端证书不能出现在这个列表上

服务器会在重启以及服务器配置被重载时读取这些文件。在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应该被离线存储以便创建未来的证书。