网上的各类文章不是很细,配置出了问题很难发现解决,我已经踩了不少坑,结合网上些文章,以及官网网站给出的例子,最终整理出了一套本身的配置模式,参考本章便可不出任何错误的完成RabbitMQ
的SSL
配置。html
erlang
是RabbitMQ
的运行环境,为何要强调安装erlang
,若是你随便去下载erlang
官网的包,可能会缺乏不少依赖,若是你已经安装好了erlang
,执行命令看是否和如下结果一致。 java
在RabbitMQ
官方网站有一段话,说明了ssl环境须要erlang哪些扩展包。原地址:RMQ官方SSL说明git
Erlang/OTP Requirements for TLS Support In order to support TLS connections, RabbitMQ needs TLS and crypto-related modules to be available in the Erlang/OTP installation. The recommended Erlang/OTP version to use with TLS is the most recent supported Erlang release. Earlier versions, even if they are supported, may work for most certificates but have known limitations (see below).github
The Erlang asn1, crypto, public_key, and ssl libraries (applications) must be installed and functional. On Debian and Ubuntu this is provided by the erlang-asn1, erlang-crypto, erlang-public-key, and erlang-ssl packages, respectively. The zero dependency Erlang RPM for RabbitMQ includes the above modules.shell
If Erlang/OTP is compiled from source, it is necessary to ensure that configure finds OpenSSL and builds the above libraries.vim
大概意思是安装erlang
前你的系统中必须已经安装了openssl
,而后erlang
开启ssl须要哪些依赖包,最终他给了一个0依赖的erlang
下载地址,这个erlang
包他默认包含了全部ssl须要的依赖。而后他给出的erlang
和RabbitMQ
的版本对比,下载你须要的版本.bash
rpm安装事后,将erl命令地址配置到环境变量中,若是在重装过程当中遇到了文件冲突,使用以下指令。app
rpm -Uivh erlang.rpm --replacefiles
复制代码
erlang
环境装好后,RabbitMQ
安装就再也不介绍,使用rpm安装就行,没有什么坑。less
接下来会简述证书生成,ssl端口开放jvm
git clone https://github.com/Berico-Technologies/CMF-AMQP-Configuration.git
复制代码
cd CMF-AMQP-Configuration/ssl
复制代码
配置当前目录下的openssl.cnf
,基本上不须要改动,证书默认生成后的有效期是一年,若是须要延长能够修改default_days = 365
.
该脚本是会在当前目录下生成一个ca目录,里面存放着一些证书颁发机构信息,和已经签发的证书记录
sh setup_ca.sh RabbitSSL
复制代码
RabbitSSL
: 签发机构名称,自定义。该脚本是会在当前目录下生成一个server目录,里面存放着服务端的公钥,和私钥文件。该文件生成后会在ca目录文件中有签发记录。
sh make_server_cert.sh rabbit-server rabbit
复制代码
rabbit-server
: 生成的密钥前缀名,自定义。rabbit
: 访问该密钥的密码,自定义。该脚本是会在当前目录下生成一个client目录,里面存放着客户端的公钥,和私钥文件。该文件生成后会在ca目录文件中有签发记录。
sh create_client_cert.sh rabbit-client rabbit
复制代码
rabbit-client
: 生成的密钥前缀名,自定义。rabbit
: 访问该密钥的密码,自定义。不一样的语言操做方式不同,这里咱们使用的是java
语言,使用java
的keytool
工具生成,首先确保已经安装java
而且在环境变量中已经配置
keytool -import -alias rabbit-server -file server/rabbit-server.cert.pem -keystore rabbitStore -storepass rabbit
复制代码
用服务端的公钥生成证书,这个步骤很关键,该证书用于客户端和服务端通讯。
server/rabbit-server.cert.pem: 上个步骤已经生成好的服务端公钥
若是须要删除已经生成的证书,可执行如下命令
keytool -delete -alias rabbit-server -keystore rabbitStore -storepass rabbit
复制代码
若是你跟着文章一步一步作到这,说明你离成功就只差最后一步了,接下来检查咱们前几个步骤的结果,通过几个步骤咱们在CMF-AMQP-Configuration/ssl/目录下生成了:
若是以上的几个目录和这个证书都存在,说明该大步骤已经完美结束。接下来进入最关键的一步了。
接下来的步骤就比较关键了,须要用到咱们上面全部生成的文件,将它们配置到
RabbitMQ
的config
文件中.
ca
,server
,client
,rabbitStore
拷贝到/etc/rabbitmq
目录下cp -r ca server client rabbitStore /etc/rabbitmq/ssl
复制代码
/etc/rabbitmq
目录下没有rabbitmq.config
,建立该文件。vim /etc/rabbitmq/rabbitmq.config
复制代码
rabbitmq.config
中%%Disable SSLv3.0 and TLSv1.0 support.
[
{ssl, [{versions, ['tlsv1.2', 'tlsv1.1']}]},
{rabbit, [
{tcp_listeners, [5672]},
{ssl_listeners, [5671]},
{ssl_options, [{cacertfile,"/etc/rabbitmq/ssl/ca/cacert.pem"},
{certfile,"/etc/rabbitmq/ssl/server/rabbit-server.cert.pem"},
{keyfile,"/etc/rabbitmq/ssl/server/rabbit-server.key.pem"},
{verify, verify_peer},
{ciphers, ["ECDHE-ECDSA-AES256-GCM-SHA384","ECDHE-RSA-AES256-GCM-SHA384",
"ECDHE-ECDSA-AES256-SHA384","ECDHE-RSA-AES256-SHA384", "ECDHE-ECDSA-DES-CBC3-SHA",
"ECDH-ECDSA-AES256-GCM-SHA384","ECDH-RSA-AES256-GCM-SHA384","ECDH-ECDSA-AES256-SHA384",
"ECDH-RSA-AES256-SHA384","DHE-DSS-AES256-GCM-SHA384","DHE-DSS-AES256-SHA256",
"AES256-GCM-SHA384","AES256-SHA256","ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-RSA-AES128-GCM-SHA256","ECDHE-ECDSA-AES128-SHA256","ECDHE-RSA-AES128-SHA256",
"ECDH-ECDSA-AES128-GCM-SHA256","ECDH-RSA-AES128-GCM-SHA256","ECDH-ECDSA-AES128-SHA256",
"ECDH-RSA-AES128-SHA256","DHE-DSS-AES128-GCM-SHA256","DHE-DSS-AES128-SHA256",
"AES128-GCM-SHA256","AES128-SHA256","ECDHE-ECDSA-AES256-SHA",
"ECDHE-RSA-AES256-SHA","DHE-DSS-AES256-SHA","ECDH-ECDSA-AES256-SHA",
"ECDH-RSA-AES256-SHA","AES256-SHA","ECDHE-ECDSA-AES128-SHA",
"ECDHE-RSA-AES128-SHA","DHE-DSS-AES128-SHA","ECDH-ECDSA-AES128-SHA",
"ECDH-RSA-AES128-SHA","AES128-SHA"]},
{honor_cipher_order, true},
{fail_if_no_peer_cert, true},
{versions, ['tlsv1.2', 'tlsv1.1']}
]},
{auth_mechanisms,['PLAIN', 'AMQPLAIN', 'EXTERNAL']}
]}
].
复制代码
在以上配置中咱们将证书颁发机构以及服务端的公钥和私钥配置进去了。client
目录和rabbitStore
是给客户端使用的,咱们使用5671
端口做为咱们ssl通讯端口,5672
保持不变,继续为内网tcp提供服务
如下命令是参考,每一个人服务安装方式不同,总之将它重启就能够
systemctl restart rabbit-server.service
复制代码
less /var/log/rabbitmq/xxx.log
复制代码
log显示成这样,表明ssl开启成功
或者访问网页查看
5671
是否开启ssl
如上,ssl服务已经开启.最后一步代码测试
将前面尚未用到的
client
目录和rabbitStore
证书拷贝的项目中,放入到resource目录下,执行如下代码作测试;
public class SslReceiver {
public static void main(String[] args) throws TimeoutException {
String classpath = SslReceiver.class.getResource("/").getPath();
//证书密码
char[] sslPwd = "rabbit".toCharArray();
//读取client密钥,和rabbitStore证书
try (InputStream sslCardStream = new FileInputStream(classpath + "keyStore/client/rabbit-client.keycert.p12");
InputStream rabbitStoreStream = new FileInputStream(classpath + "keyStore/rabbitStore")) {
//加载秘钥
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(sslCardStream, sslPwd);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(ks, sslPwd);
//读取受权证书,只含有服务端的公钥
KeyStore jks = KeyStore.getInstance("JKS");
jks.load(rabbitStoreStream, sslPwd);
TrustManagerFactory keyStoreManager = TrustManagerFactory.getInstance("SunX509");
keyStoreManager.init(jks);
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(keyManagerFactory.getKeyManagers(), keyStoreManager.getTrustManagers(), null);
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("rabbitTest");
factory.setPassword("123456");
factory.setHost("127.0.0.1");
factory.setPort(5671);
factory.setAutomaticRecoveryEnabled(true);
//设置sslContext
factory.useSslProtocol(context);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("rabbitmq-queue", false, true, true, null); //rabbitmq-queue是rabbitmq队列
channel.basicPublish("", "rabbitmq-queue", null, "Test,Test".getBytes());
GetResponse chResponse = channel.basicGet("rabbitmq-queue", false);
if (chResponse == null){
System.out.println("No message retrieved");
}else {
byte[] body = chResponse.getBody();
System.out.println("Recieved: " + new String(body));
}
channel.close();
connection.close();
} catch (KeyStoreException | UnrecoverableKeyException | KeyManagementException
| CertificateException | NoSuchAlgorithmException | IOException e) {
log.error("SSL证书解析失败", e);
}
}
}
复制代码
若是收到了那条消息,到此ssl结束,若是有异常信息,请在启动jvm中传递参数 -Djavax.net.debug=all
,查看链接过程,在结合服务端/var/log/rabbitmq
下的log一块儿分析,或者联系我!一般来说,若是你将个人每一步复制,不可能出现问题。 完结!