目录
开篇
由于最近工作中有涉及到为mysql配置ssl连接的需求,而且客户的生产环境是windows系统的,所以小编在自己本地安装了mysql,查阅了很多资料,踩了无数坑,终于实现了基本的ssl配置。以下是本人融合很多博客和自己的总结写出的教程,而且博客的最下方的附录中,还会有相关的工具或教程的参考链接。如果有不足之处,敬请批评指正!
开发环境
- 操作系统:win10
- Mysql: 5.6.45
- OpenSSL: Win64OpenSSL_Light-1_1_0L
- jdk: 1.8
- Springboot: 2.0.5.RELEASE
正文
安装OpenSSL
OpenSSL是用来创建 SSL 证书和私钥的工具。这里,我根据我自己的系统,选择了版本为Win64OpenSSL_Light-1_1_0L的OpenSSL下载并安装。下载安装教程见附录。
开启远程连接支持
一般配置ssl,都是为了能够在远程连接时,对数据进行加密传输。mysql默认是不支持远程连接的,需要我们手动开启。
use mysql;
update user set host = '%' where user = 'root';
FLUSH PRIVILEGES;
这里将主机名称设置为“%”,即匹配所有的ip,而且指定的登陆账号是root,也就是说对root账号开通远程连接支持。我们可以查看修改后的结果。
select host,user,ssl_type from mysql.user where user ='root';
可以看到,root账号除了支持本地登陆之外,还支持远程登陆。ssl_type这个字段,我们后面会说到。
另外,还需要开放3306端口。参考链接见附录。
查看是否支持SSL
SHOW VARIABLES LIKE 'have_ssl';
当 have_ssl 为 YES 时, 表示此时 MySQL 服务已经支持ssl了。如果是 DESABLE, 则需要在启动 MySQL 服务时, 使能 ssl功能。
创建SSL证书和私钥
创建存放证书和私钥的目录
目录可以在任何路径下创建,小编为了方便,将目录创建在mysql配置文件my.ini的同级目录下。
select @@datadir;
运行这个sql,可以看到mysql的数据目录,它的上一级目录,就是配置文件my.ini所在的目录。我的配置文件所在目录:C:\ProgramData\MySQL\MySQL Server 5.6。在这个目录下创建cert目录,用于存放证书和私钥。
生成证书和私钥
在配置文件目录下,进入命令行,使用OpenSSL命令,生成一个CA私钥ca-key.pem。
openssl genrsa 2048 > cert/ca-key.pem
使用私钥生成一个CA证书ca-cert.pem,过期时间为10年
openssl req -sha1 -new -x509 -nodes -days 3650 -key ./cert/ca-key.pem > cert/ca-cert.pem
如下,命令执行后,需要你依次输入国家,地区,城市,组织,组织单位,域名和邮箱。这些信息一般都可以不填,直接回车即可。但是如果你想验证证书的有效性,这里的域名,即common name,填写0.0.0.0,表示匹配网络中的所有主机。
生成服务端的密钥server-key.pem和申请服务端证书的请求文件server-req.pem。
openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -keyout cert/server-key.pem > cert/server-req.pem
如下,执行后,依然要你输入相关的信息,其他信息都可以为空,直接回车即可,这里的域名,即common name,要填写你的有效的域名,或者直接填写你的本地ip,否者,可能造成证书无法被验证的局面。
将生成的服务端私钥server-key.pem,转化为RSA的格式
openssl rsa -in cert/server-key.pem -out cert/server-key.pem
使用上面生成的服务端请求文件server-req.pem、CA证书ca-cert.pem、CA私钥ca-key.pem,生成服务端的证书server-cert.pem。
openssl x509 -sha1 -req -in cert/server-req.pem -days 3650 -CA cert/ca-cert.pem -CAkey cert/ca-key.pem -set_serial 01 > cert/server-cert.pem
生成客户端的密钥client-key.pem和申请客户端证书的请求文件client-req.pem。
openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -keyout cert/client-key.pem > cert/client-req.pem
同样的,命令执行后,根据提示,域名,即common name这一项,填写你的本机ip,其他的直接为空,回车即可。请注意,服务端和客户端的common name这一项必须一致,而且不能与CA证书的common name相同,否则会导致证书验证失败!
将生成的客户端私钥client-key.pem,转化为RSA格式。
openssl rsa -in cert/client-key.pem -out cert/client-key.pem
使用上面生成的客户端请求文件client-req.pem、CA证书ca-cert.pem、CA私钥ca-key.pem,生成客户端的证书client-cert.pem。
openssl x509 -sha1 -req -in cert/client-req.pem -days 3650 -CA cert/ca-cert.pem -CAkey cert/ca-key.pem -set_serial 01 > cert/client-cert.pem
校验CA证书ca-cert.pem、服务端证书server-cert.pem、客户端证书client-cert.pem。
openssl verify -CAfile cert/ca-cert.pem cert/server-cert.pem cert/client-cert.pem
出现如下字眼,说明证书和私钥成功生成。
生成的文件如下:
mysql的SSL开启与证书配置
修改配置文件my.ini,在[mysqld] 配置域下,配置CA证书、服务端证书和服务端密钥地址,并配置MySQL 服务可以接收来自所有 ip 地址的客户端。
ssl-ca=C:/ProgramData/MySQL/MySQL Server 5.6/cert/ca-cert.pem
ssl-cert=C:/ProgramData/MySQL/MySQL Server 5.6/cert/server-cert.pem
ssl-key=C:/ProgramData/MySQL/MySQL Server 5.6/cert/server-key.pem
bind-address = 0.0.0.0
配置root账号使用ssl登陆,这里的密码需要正确填写你当前的root账号密码,否则配置不生效。
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' REQUIRE SSL;
FLUSH PRIVILEGES;
查看是否修改成功。
select host,user,ssl_type from mysql.user where user ='root';
root账号对应的一个host为“%”,并且ssl_type为"ANY",说明root账号已经支持ssl的远程登陆了。
重启mysql服务,使配置生效。
本地ssl登陆
使用命令行本地登陆(需要携带CA证书、客户端证书、客户端密钥路径等信息),当然,直接普通登陆也行,因为从上面sql的运行结果可以看出,同时支持本地普通登陆,但是远程登陆必须使用ssl。
mysql --ssl-ca="C:/ProgramData/MySQL/MySQL Server 5.6/cert/ca-cert.pem" --ssl-cert="C:/ProgramData/MySQL/MySQL Server 5.6/cert/client-cert.pem" --ssl-key="C:/ProgramData/MySQL/MySQL Server 5.6/cert/client-key.pem" -u root -p
登陆成功后,执行命令:
\s
可以看到如下字眼,说明ssl配置成功,而且使用的算法是DHE-RSA-AES256-SHA。
这时候执行:
show variables like '%ssl%' ;
可以看到,已经支持ssl登陆了,并且还可以看到CA证书和服务端证书、密钥的相关信息。
远程ssl登陆
使用Navicat尝试远程登陆成功。
Java ssl连接配置
生成truststore.jks和keystore.jks
定位到证书的目录,在命令行中,使用CA证书ca-cert.pem,生成truststore.jks,这里的密码我使用123456。
keytool -import -noprompt -file ca-cert.pem -keystore truststore.jks -storepass 123456
使用客户端私钥client-key.pem,将客户端证书client-cert.pem,转化为P12格式,这里的密码我使用相同的123456。
openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -out keystore.p12 -passout pass:123456
使用生成的keystore.p12,生成keystore.jks,这里的密码需要保持一致。
keytool -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 -destkeystore keystore.jks -srcstorepass 123456 -deststorepass 123456
出现如下提示,则说明密钥库已经导入成功。
Springboot项目配置ssl证书连接mysql
小编创建了用来测试ssl连接的简单的Springboot项目,已经上传到了github。如果需要获取,请点击附录中的链接。
在项目根目录下,创建config目录,存放truststore.jks和keystore.jks文件,如下:
新建配置类Params,设置truststore.jks和keystore.jks路径和密码信息
package com.hejianlin.ssl_jdbc_demo.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties("params")
@Data
public class Params {
public String trustStorePath="config/truststore.jks";
public String trustStorePassword="123456";
public String keyStorePath = "config/keystore.jks";
public String keyStorePassword = "123456";
public String defaultType = "JKS";
}
在启动类中,注入Params,并通过@PostConstruct注解,使用Springboot启动时,自动将ssl证书相关配置,注入到系统变量中。
package com.hejianlin.ssl_jdbc_demo;
import com.hejianlin.ssl_jdbc_demo.config.Params;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.PostConstruct;
import java.io.File;
@SpringBootApplication(scanBasePackages = {"com.hejianlin.ssl_jdbc_demo"})
public class SslJdbcApplication {
@Autowired
Params params;
public static void main(String[] args) {
SpringApplication.run(SslJdbcApplication.class, args);
}
@PostConstruct
void postConstruct(){
File trustStoreFilePath = new File(params.trustStorePath);
String tsp = trustStoreFilePath.getAbsolutePath();
System.setProperty("javax.net.ssl.trustStore", tsp);
System.setProperty("javax.net.ssl.trustStorePassword", params.trustStorePassword);
System.setProperty("javax.net.ssl.keyStoreType", params.defaultType);
File keyStoreFilePath = new File(params.keyStorePath);
String ksp = keyStoreFilePath.getAbsolutePath();
System.setProperty("Security.KeyStore.Location", ksp);
System.setProperty("Security.KeyStore.Password", params.keyStorePassword);
}
}
新建Springboot测试类,通过简单的jdbc,测试mysql的ssl链接是否成功,这里的表是我随便创建的一个表。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SslJdbcApplication.class)
public class JdbcTest {
@Test
public void test(){
Connection conn=null;
Statement sta=null;
try {
Class.forName("com.mysql.jdbc.Driver");
String url="jdbc:mysql://192.168.31.89:3306/test?verifyServerCertificate=true&useSSL=true&requireSSL=true";
String username="root";
String password="123456";
conn= DriverManager.getConnection(url, username, password);
sta=conn.createStatement();
String sql="INSERT into a (id,sid,type) value (38,6,'dds')";
int row=sta.executeUpdate(sql);
System.out.println("增加行数:"+row);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if(sta!=null){
try {
sta.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
查看结果,看到行数增加了,说明ssl连接成功。
附录
windows下载安装OpenSSL
mysql使用SSL链接
windows开放指定端口
pem证书转化为jks格式
Springboot加载ssl证书
测试ssl连接的demo项目