

# 更新应用程序以使用新的 SSL/TLS 证书连接到 MySQL 数据库实例
<a name="ssl-certificate-rotation-mysql"></a>

自 2023 年 1 月 13 日起，Amazon RDS 发布了新的证书颁发机构（CA）证书，以便使用安全套接字层或传输层安全性协议（SSL/TLS）连接到 RDS 数据库实例。接下来，您可以找到有关更新应用程序以使用新证书的信息。

本主题可帮助您确定是否有任何客户端应用程序使用 SSL/TLS 连接到您的数据库实例。如果是这样，您可以进一步检查这些应用程序是否需要证书验证才能连接。

**注意**  
某些应用程序配置为仅在它们可以成功验证服务器上的证书时才连接到 MySQL 数据库实例。对于此类应用程序，您必须更新客户端应用程序信任存储，以包括新的 CA 证书。  
您可以指定以下 SSL 模式：`disabled`、`preferred` 和 `required`。当您使用 `preferred` SSL 模式且 CA 证书不存在或不是最新时，连接会恢复为不使用 SSL，在不加密的情况下连接。  
不建议使用 `preferred` 模式。在 `preferred` 模式下，如果连接遇到无效证书，则会停止使用加密并在未加密的状态下继续。

更新客户端应用程序信任存储中的 CA 证书后，可以在数据库实例上轮换这些证书。强烈建议在生产环境中实现这些过程之前，先在开发或测试环境中测试它们。

有关证书轮换的更多信息，请参阅[轮换 SSL/TLS 证书](UsingWithRDS.SSL-certificate-rotation.md)。有关下载证书的更多信息，请参阅[使用 SSL/TLS 加密与数据库实例或集群的连接](UsingWithRDS.SSL.md)。有关对 MySQL 数据库实例使用 SSL/TLS 的信息，请参阅[Amazon RDS 上 MySQL 数据库实例的 SSL/TLS 支持](MySQL.Concepts.SSLSupport.md)。

**Topics**
+ [确定是否有任何应用程序使用 SSL 连接到 MySQL 数据库实例](#ssl-certificate-rotation-mysql.determining-server)
+ [确定客户端是否需要证书验证才能连接](#ssl-certificate-rotation-mysql.determining-client)
+ [更新应用程序信任存储](#ssl-certificate-rotation-mysql.updating-trust-store)
+ [用于建立 SSL 连接的示例 Java 代码](#ssl-certificate-rotation-mysql.java-example)

## 确定是否有任何应用程序使用 SSL 连接到 MySQL 数据库实例
<a name="ssl-certificate-rotation-mysql.determining-server"></a>

如果您使用的是 Amazon RDS for MySQL 版本 5.7、8.0 或 8.4，并且启用了 Performance Schema，请运行以下查询来检查连接是否使用了 SSL/TLS。有关启用 Performance Schema 的信息，请参阅 MySQL 文档中的 [Performance Schema 快速入门](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-quick-start.html)。

```
mysql> SELECT id, user, host, connection_type 
       FROM performance_schema.threads pst 
       INNER JOIN information_schema.processlist isp 
       ON pst.processlist_id = isp.id;
```

在该示例输出中，您可以看到自己的会话 (`admin`) 以及作为 `webapp1` 登录的应用程序均在使用 SSL。

```
+----+-----------------+------------------+-----------------+
| id | user            | host             | connection_type |
+----+-----------------+------------------+-----------------+
|  8 | admin           | 10.0.4.249:42590 | SSL/TLS         |
|  4 | event_scheduler | localhost        | NULL            |
| 10 | webapp1         | 159.28.1.1:42189 | SSL/TLS         |
+----+-----------------+------------------+-----------------+
3 rows in set (0.00 sec)
```

## 确定客户端是否需要证书验证才能连接
<a name="ssl-certificate-rotation-mysql.determining-client"></a>

您可以检查 JDBC 客户端和 MySQL 客户端是否需要证书验证才能连接。

### JDBC
<a name="ssl-certificate-rotation-mysql.determining-client.jdbc"></a>

以下使用 MySQL Connector/J 8.0 的示例显示了一种方法，用于检查应用程序的 JDBC 连接属性以确定成功的连接是否需要有效证书。有关 MySQL 的所有 JDBC 连接选项的更多信息，请参阅 MySQL 文档中的[配置属性](https://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html)。

当使用 MySQL Connector/J 8.0 时，如果连接属性将 `sslMode` 设置为 `VERIFY_CA` 或 `VERIFY_IDENTITY`，则 SSL 连接需要对数据库服务器证书进行验证，如以下示例所示。

```
Properties properties = new Properties();
properties.setProperty("sslMode", "VERIFY_IDENTITY");
properties.put("user", DB_USER);
properties.put("password", DB_PASSWORD);
```

**注意**  
如果您使用 MySQL Java Connector v5.1.38 或更高版本或者 MySQL Java Connector v8.0.9 或更高版本连接到数据库，即使您没有明确配置应用程序在连接到数据库时使用 SSL/TLS，这些客户端驱动程序仍默认为使用 SSL/TLS。此外，在使用 SSL/TLS 时，它们会执行部分证书验证，如果数据库服务器证书过期，则无法连接。

### MySQL
<a name="ssl-certificate-rotation-mysql.determining-client.mysql"></a>

以下使用 MySQL 客户端的示例显示了两种方法，用于检查脚本的 MySQL 连接以确定成功的连接是否需要有效证书。有关 MySQL 客户端的所有连接选项的更多信息，请参阅 MySQL 文档中的[加密连接的客户端配置](https://dev.mysql.com/doc/refman/8.0/en/using-encrypted-connections.html#using-encrypted-connections-client-side-configuration)。

当使用 MySQL 客户端 5.7 及更高版本时，如果对于 `--ssl-mode` 选项，您指定 `VERIFY_CA` 或 `VERIFY_IDENTITY`，则 SSL 连接需要对服务器 CA 证书进行验证，如以下示例所示。

```
mysql -h mysql-database.rds.amazonaws.com -uadmin -ppassword --ssl-ca=/tmp/ssl-cert.pem --ssl-mode=VERIFY_CA                
```

## 更新应用程序信任存储
<a name="ssl-certificate-rotation-mysql.updating-trust-store"></a>

有关更新 MySQL 应用程序的信任存储的信息，请参阅 MySQL 文档中的[安装 SSL 证书](https://dev.mysql.com/doc/mysql-monitor/8.0/en/mem-ssl-installation.html)。

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

有关导入证书的示例脚本，请参阅 [将证书导入信任存储的示例脚本](UsingWithRDS.SSL-certificate-rotation.md#UsingWithRDS.SSL-certificate-rotation-sample-script)。

**注意**  
更新信任存储时，除了添加新证书外，还可以保留较旧证书。

如果在应用程序中使用 mysql JDBC 驱动程序，请在该应用程序中设置以下属性。

```
System.setProperty("javax.net.ssl.trustStore", certs);
System.setProperty("javax.net.ssl.trustStorePassword", "password");
```

启动应用程序时，请设置以下属性。

```
java -Djavax.net.ssl.trustStore=/path_to_trust_store/MyTruststore.jks -Djavax.net.ssl.trustStorePassword=my_trust_store_password com.companyName.MyApplication        
```

**注意**  
作为安全最佳实践，请指定除此处所示提示以外的密码。

## 用于建立 SSL 连接的示例 Java 代码
<a name="ssl-certificate-rotation-mysql.java-example"></a>

以下代码示例展示了如何设置使用 JDBC 验证服务器证书的 SSL 连接。

```
public class MySQLSSLTest {
     
        private static final String DB_USER = "username";
        private static final String DB_PASSWORD = "password";
        // This trust store has only the prod root ca.
        private static final String TRUST_STORE_FILE_PATH = "file-path-to-trust-store";
        private static final String TRUST_STORE_PASS = "trust-store-password";
            
        public static void test(String[] args) throws Exception {
            Class.forName("com.mysql.jdbc.Driver");
                    
            System.setProperty("javax.net.ssl.trustStore", TRUST_STORE_FILE_PATH);
            System.setProperty("javax.net.ssl.trustStorePassword", TRUST_STORE_PASS);
            
            Properties properties = new Properties();
            properties.setProperty("sslMode", "VERIFY_IDENTITY");
            properties.put("user", DB_USER);
            properties.put("password", DB_PASSWORD);
            
     
            Connection connection = null;
            Statement stmt = null;
            ResultSet rs = null;
            try {
                connection = DriverManager.getConnection("jdbc:mysql://mydatabase.123456789012.us-east-1.rds.amazonaws.com:3306",properties);
                stmt = connection.createStatement();
                rs=stmt.executeQuery("SELECT 1 from dual");
            } finally {
                if (rs != null) {
                    try {
                        rs.close();
                    } catch (SQLException e) {
                    }
                }
                if (stmt != null) {
                   try {
                        stmt.close();
                    } catch (SQLException e) {
                   }
                }
                if (connection != null) {
                    try {
                        connection.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
            return;
        }
    }
```

**重要**  
在确定了数据库连接使用 SSL/TLS 并更新了应用程序信任存储之后，可以更新数据库以使用 rds-ca-rsa2048-g1 证书。有关说明，请参阅 [通过修改数据库实例或集群来更新 CA 证书](UsingWithRDS.SSL-certificate-rotation.md#UsingWithRDS.SSL-certificate-rotation-updating) 中的步骤 3。  
作为安全最佳实践，请指定除此处所示提示以外的密码。