

# 将 SSL 与 PostgreSQL 数据库实例结合使用
<a name="PostgreSQL.Concepts.General.SSL"></a>

Amazon RDS 支持对 PostgreSQL 数据库实例进行安全套接字层 (SSL) 加密。使用 SSL 可加密应用程序与 PostgreSQL 数据库实例之间的 PostgreSQL 连接。默认情况下，RDS for PostgreSQL 使用并期望所有客户端使用 SSL/TLS 进行连接，但您也可以要求它这样做。RDS for PostgreSQL 支持传输层安全性协议（TLS）版本 1.1、1.2 和 1.3。

有关 SSL 支持和 PostgreSQL 数据库的一般信息，请参阅 PostgreSQL 文档中的 [SSL 支持](https://www.postgresql.org/docs/11/libpq-ssl.html)。有关通过 JDBC 使用 SSL 连接的信息，请参阅 PostgreSQL 文档中的[配置客户端](https://jdbc.postgresql.org/documentation/head/ssl-client.html)。

所有AWS区域均支持对 PostgreSQL 使用 SSL。在创建数据库实例时，Amazon RDS 会为 PostgreSQL 数据库实例创建一个 SSL 证书。如果启用 SSL 证书验证，SSL 证书会将数据库实例终端节点作为 SSL 证书的公用名 (CN) 包含在内以防止欺诈攻击。

**Topics**
+ [通过 SSL 连接到 PostgreSQL 数据库实例](#PostgreSQL.Concepts.General.SSL.Connecting)
+ [需要至 PostgreSQL 数据库实例的 SSL 连接](#PostgreSQL.Concepts.General.SSL.Requiring)
+ [确定 SSL 连接状态](#PostgreSQL.Concepts.General.SSL.Status)
+ [RDS for PostgreSQL 中的 SSL 密码套件](#PostgreSQL.Concepts.General.SSL.Ciphers)

## 通过 SSL 连接到 PostgreSQL 数据库实例
<a name="PostgreSQL.Concepts.General.SSL.Connecting"></a>

**通过 SSL 连接到 PostgreSQL 数据库实例**

1. 下载证书。

   有关下载证书的信息，请参阅 [使用 SSL/TLS 加密与数据库实例或集群的连接](UsingWithRDS.SSL.md)。

1. 通过 SSL 连接到您的 PostgreSQL 数据库实例。

   使用 SSL 连接时，客户端可以选择是否验证证书链。如果连接参数指定 `sslmode=verify-ca` 或 `sslmode=verify-full`，则客户端要求 RDS CA 证书位于其信任存储中或在连接 URL 中进行引用。此要求是为了验证签署您的数据库证书的证书链。

   当客户端（如 psql 或 JDBC）配置有 SSL 支持时，默认情况下，该客户端会首先尝试使用 SSL 连接到数据库。如果该客户端无法使用 SSL 进行连接，它将恢复为不使用 SSL 进行连接。基于 libpq 的客户端（例如 psql）和 JDBC 所使用的默认 `sslmode` 模式不同。基于 libpq 的客户端和 JDBC 客户端默认使用 `prefer`。

   使用 `sslrootcert` 参数引用证书，例如，`sslrootcert=rds-ssl-ca-cert.pem`。

以下是使用 `psql` 连接到 PostgreSQL 数据库实例的示例，该数据库实例使用 SSL 及证书验证。

```
$ psql "host=db-name.555555555555.ap-southeast-1.rds.amazonaws.com 
    port=5432 dbname=testDB user=testuser sslrootcert=rds-ca-rsa2048-g1.pem sslmode=verify-full"
```

## 需要至 PostgreSQL 数据库实例的 SSL 连接
<a name="PostgreSQL.Concepts.General.SSL.Requiring"></a>

您可以使用 `rds.force_ssl` 参数要求至 PostgreSQL 数据库实例的连接使用 SSL。对于 RDS for PostgreSQL 版本 15 及更高版本，`rds.force_ssl` 参数默认值为 1（开启）。对于所有其它 RDS for PostgreSQL 主要版本 14 及更早版本，此参数的默认值均为 0（关闭）。您可将 `rds.force_ssl` 参数设置为 1 (on) 以要求使用 SSL/TLS 连接到数据库集群。您可将 `rds.force_ssl` 参数设置为 1 (on) 以要求至数据库实例的 SSL 连接。

要更改此参数的值，您需要创建自定义数据库参数组。然后将自定义数据库参数组中的 `rds.force_ssl` 的值更改为 `1`，以启用此功能。如果您在创建 RDS for PostgreSQL 数据库实例之前准备了自定义数据库参数组，则可以在创建过程中选择它（而不是默认参数组）。如果您在 RDS for PostgreSQL 数据库实例已运行之后执行此操作，则需要重启该实例，以便您的实例使用自定义参数组。有关更多信息，请参阅 [Amazon RDS 的参数组](USER_WorkingWithParamGroups.md)。

当 `rds.force_ssl` 功能在数据库实例上处于活动状态时，不使用 SSL 的连接尝试将被拒绝，并显示以下消息：

```
$ psql -h db-name.555555555555.ap-southeast-1.rds.amazonaws.com port=5432 dbname=testDB user=testuser
psql: error: FATAL: no pg_hba.conf entry for host "w.x.y.z", user "testuser", database "testDB", SSL off
```

## 确定 SSL 连接状态
<a name="PostgreSQL.Concepts.General.SSL.Status"></a>

当您连接到数据库实例后，登录横幅中将显示连接的加密状态：

```
Password for user master: 
psql (10.3) 
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256) 
Type "help" for help.
postgres=>
```

也可加载 `sslinfo` 扩展，然后调用 `ssl_is_used()` 函数以判断是否在使用 SSL。如果连接使用的是 SSL，则此函数将返回 `t`；否则返回 `f`。

```
postgres=> CREATE EXTENSION sslinfo;
CREATE EXTENSION
postgres=> SELECT ssl_is_used();
ssl_is_used
---------
t
(1 row)
```

要获取更多详细信息，您可以使用以下查询从 `pg_settings` 中获取信息：

```
SELECT name as "Parameter name", setting as value, short_desc FROM pg_settings WHERE name LIKE '%ssl%';
             Parameter name             |                  value                  |                      short_desc
----------------------------------------+-----------------------------------------+-------------------------------------------------------
 ssl                                    | on                                      | Enables SSL connections.
 ssl_ca_file                            | /rdsdbdata/rds-metadata/ca-cert.pem     | Location of the SSL certificate authority file.
 ssl_cert_file                          | /rdsdbdata/rds-metadata/server-cert.pem | Location of the SSL server certificate file.
 ssl_ciphers                            | HIGH:!aNULL:!3DES                       | Sets the list of allowed SSL ciphers.
 ssl_crl_file                           |                                         | Location of the SSL certificate revocation list file.
 ssl_dh_params_file                     |                                         | Location of the SSL DH parameters file.
 ssl_ecdh_curve                         | prime256v1                              | Sets the curve to use for ECDH.
 ssl_key_file                           | /rdsdbdata/rds-metadata/server-key.pem  | Location of the SSL server private key file.
 ssl_library                            | OpenSSL                                 | Name of the SSL library.
 ssl_max_protocol_version               |                                         | Sets the maximum SSL/TLS protocol version to use.
 ssl_min_protocol_version               | TLSv1.2                                 | Sets the minimum SSL/TLS protocol version to use.
 ssl_passphrase_command                 |                                         | Command to obtain passphrases for SSL.
 ssl_passphrase_command_supports_reload | off                                     | Also use ssl_passphrase_command during server reload.
 ssl_prefer_server_ciphers              | on                                      | Give priority to server ciphersuite order.
(14 rows)
```

您还可以使用以下查询，按流程、客户端和应用程序收集有关 RDS for PostgreSQL 数据库实例 SSL 使用情况的所有信息：

```
SELECT datname as "Database name", usename as "User name", ssl, client_addr, application_name, backend_type
   FROM pg_stat_ssl
   JOIN pg_stat_activity
   ON pg_stat_ssl.pid = pg_stat_activity.pid
   ORDER BY ssl;
 Database name | User name | ssl |  client_addr   |    application_name    |         backend_type
---------------+-----------+-----+----------------+------------------------+------------------------------
               |           | f   |                |                        | autovacuum launcher
               | rdsadmin  | f   |                |                        | logical replication launcher
               |           | f   |                |                        | background writer
               |           | f   |                |                        | checkpointer
               |           | f   |                |                        | walwriter
 rdsadmin      | rdsadmin  | t   | 127.0.0.1      |                        | client backend
 rdsadmin      | rdsadmin  | t   | 127.0.0.1      | PostgreSQL JDBC Driver | client backend
 postgres      | postgres  | t   | 204.246.162.36 | psql                   | client backend
(8 rows)
```

要识别用于 SSL 连接的密码，可按如下方式进行查询：

```
postgres=> SELECT ssl_cipher();
ssl_cipher
--------------------
DHE-RSA-AES256-SHA
(1 row)
```

要了解有关 `sslmode` 选项的更多信息，请参阅 *PostgreSQL 文档*中的[数据库连接控制函数](https://www.postgresql.org/docs/11/libpq-connect.html#LIBPQ-CONNECT-SSLMODE)。

## RDS for PostgreSQL 中的 SSL 密码套件
<a name="PostgreSQL.Concepts.General.SSL.Ciphers"></a>

PostgreSQL 配置参数 [ssl\$1ciphers](https://www.postgresql.org/docs/current/runtime-config-connection.html#RUNTIME-CONFIG-CONNECTION-SSL) 指定在使用 TLS 1.2 及更低版本时，与数据库的 SSL 连接所支持的密码套件类别。

 在 RDS for PostgreSQL 16 及更高版本中，您可以修改 `ssl_ciphers` 参数，以使用列入许可列表的密码套件中的特定值。这是一个不要求重启数据库实例的动态参数。要查看列入许可列表的密码套件，请使用 Amazon RDS 控制台或以下 CLI AWS 命令：

```
aws rds describe-db-parameters --db-parameter-group-name <your-parameter-group> --region <region> --endpoint-url <endpoint-url> --output json | jq '.Parameters[] | select(.ParameterName == "ssl_ciphers")'
```

下表列出了支持自定义配置的版本的默认密码套件和许可的密码套件。


| PostgreSQL 引擎版本 | 默认 ssl\$1cipher 套件值 | 列入许可列表的自定义 ssl\$1cipher 套件值 | 
| --- | --- | --- | 
| 18 | HIGH:\$1aNULL:\$13DES |  `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384` `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256` `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384` `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256`  | 
| 17 | HIGH:\$1aNULL:\$13DES |  `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384` `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256` `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384` `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256`  | 
| 16 | HIGH:\$1aNULL:\$13DES |  `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384` `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256` `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384` `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256`  | 
| 15 | HIGH:\$1aNULL:\$13DES | 不支持自定义 ssl\$1cipher | 
| 14 | HIGH:\$1aNULL:\$13DES | 不支持自定义 ssl\$1cipher | 
| 13 | HIGH:\$1aNULL:\$13DES | 不支持自定义 ssl\$1cipher | 
| 12 | HIGH:\$1aNULL:\$13DES | 不支持自定义 ssl\$1cipher | 
| 11.4 及更高的次要版本 | HIGH:MEDIUM:\$13DES:\$1aNULL:\$1RC4 | 不支持自定义 ssl\$1cipher | 
| 11.1、11.2 | HIGH:MEDIUM:\$13DES:\$1aNULL | 不支持自定义 ssl\$1cipher | 
| 10.9 及更高的次要版本 | HIGH:MEDIUM:\$13DES:\$1aNULL:\$1RC4 | 不支持自定义 ssl\$1cipher | 
| 10.7 及更低的次要版本 | HIGH:MEDIUM:\$13DES:\$1aNULL | 不支持自定义 ssl\$1cipher | 

要将所有实例连接配置为使用 `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384` 密码套件，请修改参数组，如以下示例所示：

```
aws rds modify-db-parameter-group --db-parameter-group-name <your-parameter-group> --parameters "ParameterName='ssl_ciphers',ParameterValue='TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384',ApplyMethod=immediate"
```

此示例使用 ECDSA 密码，这要求您的实例使用具有椭圆曲线加密（ECC）的证书颁发机构来建立连接。有关 Amazon RDS 提供的证书颁发机构的信息，请参阅[证书颁发机构](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/singWithRDS.SSL.html#UsingWithRDS.SSL.RegionCertificateAuthorities)。

您可以通过[确定 SSL 连接状态](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/PostgreSQL.Concepts.General.SSL.html#PostgreSQL.Concepts.General.SSL.Status)中所述的方法来验证所使用的密码。

根据上下文，密码可能有不同的名称：
+ 您可以在参数组中配置的列入许可列表的密码以其 IANA 名称来引用。
+ `sslinfo` 和 `psql` 登录横幅使用密码的 OpenSSL 名称来引用这些密码。

默认情况下，RDS for PostgreSQL 16 及更高版本中 `ssl_max_protocol_version` 的值为 TLS v1.3。您必须将此参数的值设置为 TLS v1.2，因为 TLS v1.3 不使用在 `ssl_ciphers` 参数中指定的密码配置。当您将该值设置为 TLS v1.2 时，连接将仅使用您在 `ssl_ciphers` 中定义的密码。

```
aws rds modify-db-parameter-group --db-parameter-group-name <your-parameter-group> --parameters "ParameterName='ssl_max_protocol_version',ParameterValue='TLSv1.2',ApplyMethod=immediate"
```

为确保数据库连接使用 SSL，请在参数组中将 `rds.force_ssl parameter` 设置为 1。有关参数和参数组的更多信息，请参阅 [Amazon RDS 的参数组](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_WorkingWithParamGroups.html)。