本地环境
工具环境 | 版本号 |
---|---|
JDK | 1.8.0_402 |
MySQL | 8.0.24 |
步骤一:准备 SSL 证书文件
ca.pem 通常位于 MySQL 的数据目录中
文件说明:
- ca.pem(CA 证书)作用:自签名的根证书,用于验证 server-cert.pem 和 client-cert.pem(如果启用双向认证)。
- client-cert.pem (客户端证书)
- client-key.pem(客户端私钥)
- server-cert.pem(服务器证书)
- server-key.pem(服务器私钥)
利用JVM的keytool工具,将此证书导入到truststore仓库中
在pem所在的服务器目录下执行命令:
命令1:创建一个名为truststoremysql的新JKS格式TrustStore文件,将CA证书ca.pem以别名Cacert导入到该TrustStore中,并配置访问密码为password123
keytool -importcert -alias Cacert -file ca.pem -keystore truststoremysql -storepass password123
命令2:将客户端证书和私钥打包为PKCS12文件
openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -name "mysqlclient" -passout pass:mypassword -out client-keystore.p12
命令3:将PKCS12格式的client-keystore.p12转换为JKS格式的keystoremysql,存储密码为password123
keytool -importkeystore -srckeystore client-keystore.p12 -srcstoretype pkcs12 -srcstorepass mypassword -destkeystore keystoremysql -deststoretype JKS -deststorepass password123
此时可以看到目录下生成了3个文件:
此时我们要把生成的truststoremysql
和keystoremysql
下载下来,后面客户端连接要使用
步骤二:配置 MySQL 启用 SSL
1.确认MySQL服务器支持SSL
MySQL 5.7 及更高版本默认启用了 SSL支持,但具体是否强制要求 SSL 连接取决于配置
通过命令查看:
SHOW VARIABLES LIKE '%ssl%';
-- 应看到如下输出:
-- have_ssl = YES 服务器支持 SSL
-- ssl_ca = ca.pem 证书所在目录
2.确认用户使用ssl认证
# 创建新用户并要求其使用SSL连接:
CREATE USER 'ssl_user'@'%' IDENTIFIED BY 'password456' REQUIRE SSL;
# 或者对现有用户修改要求:
ALTER USER 'existing_user'@'%' REQUIRE SSL;
步骤三:测试&连接配置
Java测试类测试SSL连接是否可用
我们将步骤一下载的keystoremysql和truststoremysql文件存放到本地D:mysql_ssl目录下面,运行下面Java测试类连接mysql
public class SSLTest {
public static void main(String[] args) {
String jdbcUrl = "jdbc:mysql://xxx.xxx.xxx.xxx:3306/test1?useUnicode=true&characterEncoding=utf8&useSSL=true" +
"&verifyServerCertificate=true&requireSSL=true" +
"&clientCertificateKeyStoreUrl=file:D:/mysql_ssl/keystoremysql" +
"&clientCertificateKeyStorePassword=password123" +
"&trustCertificateKeyStoreUrl=file:D:/mysql_ssl/truststoremysql" +
"&trustCertificateKeyStorePassword=password123" +
"&serverTimezone=GMT%2b8&allowMultiQueries=true";
String username = "ssl_user";
String password = "password456";
try {
// 1. 加载 MySQL JDBC 驱动(可选,新版 JDBC 会自动加载)
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 尝试建立连接
System.out.println("SSL尝试连接 MySQL...");
Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
System.out.println("SSL连接成功!");
// 3. 关闭连接
connection.close();
} catch (ClassNotFoundException e) {
System.err.println("找不到 MySQL JDBC 驱动!");
e.printStackTrace();
} catch (SQLException e) {
System.err.println("SSL连接 MySQL 失败!");
e.printStackTrace();
}
}
}
执行结果:
SSL尝试连接 MySQL...
SSL连接成功!
Process finished with exit code 0
SpringBoot配置文件:
# 证书路径和密码配置
ssl.cert-path="file:/mysql_ssl"
ssl.ca-password=password123
# 数据库连接配置
spring.datasource.url=jdbc:mysql://mysql:3306/test1?useUnicode=true&characterEncoding=utf8&useSSL=true\
&verifyServerCertificate=true&requireSSL=true\
&clientCertificateKeyStoreUrl=${ssl.cert-path}/keystoremysql\
&clientCertificateKeyStorePassword=${ssl.ca-password}\
&trustCertificateKeyStoreUrl=${ssl.cert-path}/truststoremysql\
&trustCertificateKeyStorePassword=${ssl.ca-password}
spring.datasource.username=dbuser
spring.datasource.password=dbpassword
其中:要把两个密钥库文件keystoremysql和truststoremysql放到SpringBoot项目的运行目录下/mysql_ssl文件夹
常见问题排查
启动报错:
java.sql.SQLNonTransientConnectionException:
Cannot open file:///mysql_ssl/truststoremysql [Invalid keystore format]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:110)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:70)
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:824)
at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:444)
at com.mysql.cj.jdbc.ConnectionImpl.getInstance$original$yk0S8sJ6(ConnectionImpl.java:237)
at com.mysql.cj.jdbc.ConnectionImpl.getInstance$original$yk0S8sJ6$accessor$ih7rNNBM(ConnectionImpl.java)
at com.mysql.cj.jdbc.ConnectionImpl$auxiliary$YA0j3WZF.call(Unknown Source)
at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsInter.intercept(StaticMethodsInter.java:83)
at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect$original$XhEXUi6M(NonRegisteringDriver.java:198)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect$original$XhEXUi6M$accessor$wKqoCl8c(NonRegisteringDriver.java)
at com.mysql.cj.jdbc.NonRegisteringDriver$auxiliary$6LJkgYBD.call(Unknown Source)
at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter.intercept(InstMethodsInter.java:86)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java)
at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1644)
at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1710)
at com.alibaba.druid.pool.DruidDataSource.init(DruidDataSource.java:912)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
解决方案:
在使用keytool工具时Java环境和项目运行的Java环境不一致导致,要保证生成keystoremysql和truststoremysql文件的Java版本和项目运行的Java版本一致
参考:
https://blog.csdn.net/xiangshui021/article/details/126379645