網上的各種文章不是很細,配置出了問題很難發現解決,我已經踩了很多坑,結合網上些文章,以及官網網站給出的例子,最終整理出了一套自己的配置模式,參考本章即可不出任何錯誤的完成RabbitMQ
的SSL
配置。
Erlang語言的安裝
erlang
是RabbitMQ
的執行環境,為什麼要強調安裝erlang
,如果你隨便去下載erlang
官網的包,可能會缺少很多依賴,如果你已經安裝好了erlang
,執行命令看是否和以下結果一致。
重灌erlang
在RabbitMQ
官方網站有一段話,說明了ssl環境需要erlang哪些擴充套件包。原地址:RMQ官方SSL說明
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).
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.
If Erlang/OTP is compiled from source, it is necessary to ensure that configure finds OpenSSL and builds the above libraries.
大概意思是安裝erlang
前你的系統中必須已經安裝了openssl
,然後erlang
開啟ssl需要哪些依賴包,最終他給了一個0依賴的erlang
下載地址,這個erlang
包他預設包含了所有ssl需要的依賴。然後他給出的erlang
和RabbitMQ
的版本對比,下載你需要的版本.
rpm安裝過後,將erl命令地址配置到環境變數中,如果在重灌過程中遇到了檔案衝突,使用如下指令。
rpm -Uivh erlang.rpm --replacefiles
複製程式碼
erlang
環境裝好後,RabbitMQ
安裝就不再介紹,使用rpm安裝就行,沒有什麼坑。
配置RabbitMQ的SSL埠
接下來會簡述證照生成,ssl埠開放
下載SSL證照生成器
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/目錄下生成了:
- ca
- server
- client
- rabbitStore 證照
如果以上的幾個目錄和這個證照都存在,說明該大步驟已經完美結束。接下來進入最關鍵的一步了。
修改RabbitMQ的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提供服務
- 重啟rabbitmq服務
以下命令是參考,每個人服務安裝方式不一樣,總之將它重啟就可以
systemctl restart rabbit-server.service
複製程式碼
- 檢視rabbitmq日誌輸出
less /var/log/rabbitmq/xxx.log
複製程式碼
log顯示成這樣,代表ssl開啟成功
或者訪問網頁檢視
5671
是否開啟ssl
如上,ssl服務已經開啟.最後一步程式碼測試
編寫Java程式碼測試證照授權
將前面還沒有用到的
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一起分析,或者聯絡我!通常來講,如果你將我的每一步複製,不可能出現問題。
完結!