git clone https://github.com/michaelklishin/tls-gen tls-gen
执行生成命令
cd tls-gen/basic
执行make命令(如提示make命令不存在,请安装python3,同时请确保已存在openssl,可通过openssl命令,如进入命令行,则表示存在,123456为后续加载服务端证书和客户端证书的密码)
make PASSWORD=123456
执行命令后出现如图的四个文件夹
执行make verify命令,出现ok则表明客户端证书与服务端证书匹配
cd result
在result目录下可看到
使用ca_certificate.pem,server_certificate.pem,server_key.pem,client_key.p12这四个文件。rabbitmq服务端使用ca_certificate.pem,server_certificate.pem,server_key.pem这三个证书,
客户端(java)使用server_certificate.pem生成的truststore文件和client_key.p12这两个证书
证书默认有效期为5年,可修改有效期,tls-gen的basic目录下打开openssl.cnf文件
修改default_days可修改有效期,再重新执行上述命令,重新生成证书。
生成java客户端truststore
keytool -import -alias server1 -file /path/to/server_certificate.pem -keystore /path/to/rabbitstore
keytool命令是jdk自带的命令,如没有该命令,请安装jdk1.8
server1为信任库中该证书的名字,需要改为自己想要的名称,名称可任意
/path/to/server_certificate.pem 为当前server_certificate.pem证书所在的位置,
/path/to/rabbitstore 最后生成truststore的位置和名称,名称为rabbitstore
ca_certificate.pem,server_certificate.pem,server_key.pem,将这三个证书转移到rabbitmq/ssl目录下
编辑配置文件(老版)
[
{rabbit, [
{tcp_listeners, [5672]},
{ssl_listeners, [5671]},
{ssl_options, [{cacertfile,"/etc/rabbitmq/ssl/ca_certificate.pem"},
{certfile, “/etc/rabbitmq/ssl/server_certificate.pem”},
{keyfile, “/etc/rabbitmq/ssl/server_key.pem”},
{verify,verify_peer},
{fail_if_no_peer_cert, true},
{password, “123456”}
]}
]}
].
注意:最后有一个点
编辑配置文件(新版)
listeners.tcp.default = 5672
#默认用户的密码
default_pass = 123456
#默认账号为admin
default_user = admin
#ssl登陆的关键配置,必须打开5671端口,后续客户端要连接5671端口
listeners.ssl.default = 5671
#三个rabbitmq服务端 证书,此处是容器中的路径,不要修改,对应的是宿主机上的/etc/rabbitmq/ssl目录,只要将这三个证书放到宿主机的/etc/rabbitmq/ssl目录下,则此处就可以加载到
ssl_options.cacertfile = /etc/rabbitmq/ssl/ca_certificate.pem
ssl_options.certfile = /etc/rabbitmq/ssl/server_certificate.pem
ssl_options.keyfile = /etc/rabbitmq/ssl/server_key.pem
ssl_options.verify = verify_peer
ssl_options.fail_if_no_peer_cert = true
#make命令执行时的密码
ssl_options.password = 123456
ssl_options.versions.1 = tlsv1.2
ssl_options.versions.2 = tlsv1.1
重启rabbitmq服务,使用15672端口,登录控制台,查看
显示监听5671端口,则启动成功
引入pom依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.7.0</version>
</dependency>
ConnectionFactory factory = new ConnectionFactory();
//设置ip,根据实际情况进行设置
factory.setHost("localhost");
//端口,ssl端口为5671,不可修改
factory.setPort(5671);
//123456为生成证书时,执行make的时候的密码
char[] keyPassphrase = "123456".toCharArray();
KeyStore ks = KeyStore.getInstance("PKCS12");
//在执行make命令后,生成的result目录下的client_key.p12文件,按实际情况填写
ks.load(new FileInputStream("/etc/rabbitmq/ssl/client_key.p12"), keyPassphrase);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keyPassphrase);
//执行keytool命令时 要求输入的密码,按实际情况填写
char[] trustPassphrase = "123456".toCharArray();
KeyStore tks = KeyStore.getInstance("JKS");
//执行keytool命令后生成的truststore文件,按实际情况填写
tks.load(new FileInputStream("/etc/rabbitmq/ssl/rabbitstore"), trustPassphrase);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(tks);
SSLContext c = SSLContext.getInstance("TLSv1.2");
c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
factory.useSslProtocol(c);
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
channel.queueDeclare("rabbitmq -test", false, true, true, null);
channel.basicPublish("", "rabbitmq -test", null, "rabbitmq via SSL".getBytes());
GetResponse chResponse = channel.basicGet("rabbitmq-test", false);
if (chResponse == null)
{
System.out.println("No message retrieved");
}
else
{
byte[] body = chResponse.getBody();
System.out.println("Recieved: " + new String(body));
}
channel.close();
conn.close();
出现打印rabbitmq via SSL,则表明连接成功
注意:
经过测试,rabbitmq-server 3.7.4+Erlang20.2.3版本不支持ssl,erlang无法加载服务端证书,导致连接失败,故需使用此组合之后的版本
经验证,rabbitmq-server 3.7.18+Erlang22.3.4.11版本支持ssl,配置文件需要使用老版的配置文件格式