網上的各類文章不是很細,配置出了問題很難發現解決,我已經踩了不少坑,結合網上些文章,以及官網網站給出的例子,最終整理出了一套本身的配置模式,參考本章便可不出任何錯誤的完成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一塊兒分析,或者聯繫我!一般來說,若是你將個人每一步複製,不可能出現問題。 完結!