RabbitMQ指南(七) SSL\TLS通信

论坛 期权论坛 脚本     
匿名技术用户   2020-12-29 10:48   20   0

RabbitMQ指南(七) SSL\TLS通信

7.1 证书生成和配置

7.2 Java客户端

7.3 C#客户端


7.1 证书生成和配置
 RabbitMQ对外提供服务时,为保证通信的安全性,通常使用SSL/TLS加密通信。
 关于非对称加密、SSL\TLS协议、证书授权中心(Certificate Authority,CA)可参考其他资料,本文仅演示RabbitMQ SSL\TLS通信的具体操作。对于生成证书,本文使用RabbitMQ官网推荐的tls-gen工具,该工具可在MacOS和Linux系统中使用,要求系统中装有openssl和Python 3.5以上版本。
 使用tls-gen生成证书:
# 下载,也可手工从以下网址下载后上传至服务器
git clone https://github.com/michaelklishin/tls-gen tls-gen
cd tls-gen/basic
# 123456是自定义的私钥密码,客户端会用到
make PASSWORD=123456
make verify
make info
1234567
 证书生成完毕后,会在basic目录下生成result、testca、server和client四个文件夹。
 通常使用单向认证的方式进行SSL\TLS通信,所需的文件为:
 (1)CA的证书文件testca/cacert.cer,C#客户端需要信任签名的CA;
 (2)CA证书文件result/ca_certificate.pem,用于服务端配置;
 (3)服务端证书文件result/server_certificate.pem,用于服务端配置;
 (4)服务端私钥文件result/server_key.pem,用于服务端配置;
 (5)客户端证书文件result/client_key.p12,用于客户端。
 在RabbitMQ解压目录的etc/rabbitmq/路径下,加入文件rabbitmq.conf(本文使用新格式配置文件,旧格式相应配置可自行参照官网的示例文件)。该路径为RabbitMQ默认配置文件路径,也可以RABBITMQ_CONFIG_FILE环境变量指定配置文件的路径。
 rabbitmq.conf内容:
# 限定非SSL\TLS的通信仅可在服务端本地连接
listeners.tcp.default = 127.0.0.1:5672
# SSL\TLS通信的端口
listeners.ssl.default = 5671
# 服务端私钥和证书文件配置
ssl_options.cacertfile = /root/tls-gen/basic/result/ca_certificate.pem
ssl_options.certfile = /root/tls-gen/basic/result/server_certificate.pem
ssl_options.keyfile = /root/tls-gen/basic/result/server_key.pem
# 有verify_none和verify_peer两个选项,verify_none表示完全忽略验证证书的结果,verify_peer表示要求验证对方证书
ssl_options.verify = verify_peer
# 若为true,服务端会向客户端索要证书,若客户端无证书则中止SSL握手;若为false,则客户端没有证书时依然可完成SSL握手
ssl_options.fail_if_no_peer_cert = true
123456789101112


7.2 Java客户端
 使用Java提供的keytool工具,将服务端证书server_certificate.pem转换为keystore证书文件:
keytool -import -alias rabbitmqserver -file F:/server_certificate.pem -keystore F:/server.keystore
 其中,“F:/server_certificate.pem”是服务端证书文件路径,“F:/server.keystore”是生成的keystore证书文件的路径。生成文件时要求设置一个密钥库口令,本文设置为“abcdef”。
 Java客户端如下:
import java.io.FileInputStream;
import java.security.KeyStore;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;


public class Sender {

// RabbitMQ服务端地址、端口、用户名、密码
private static final String ADDRESS = "10.176.64.227";
private static final int PORT = 5671;
private static final String USERNAME = "mqtester";
private static final String PASSWORD = "mqtester";

private static final String DEFAULT_EXCHANGE = "";
private static final String QUEUE_NAME = "Queue_Java";

// 使用tls-gen工具生成证书文件时设置的私钥密码
private static final String CLIENT_KEYSTORE_PASSWORD = "123456";
// 客户端证书文件client_key.p12路径
private static final String CLIENT_KEYSTORE_PATH = System.getProperty("user.dir") + "\\client_key.p12";
// 使用keytool生成证书文件时填写的密码
private static final String SERVER_KEYSTORE_PASSWORD = "abcdef";
// 使用keytool生成的服务端证书文件路径
private static final String SERVER_KEYSTORE_PATH = System.getProperty("user.dir") + "\\server.keystore";


public static void main(String[] args) throws Exception {

ConnectionFactory factory = new ConnectionFactory();
factory.setHost(ADDRESS);
factory.setPort(PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);

// 启用SSL\TLS
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream(CLIENT_KEYSTORE_PATH), CLIENT_KEYSTORE_PASSWORD.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, CLIENT_KEYSTORE_PASSWORD.toCharArray());

KeyStore tks = KeyStore.getInstance("JKS");
tks.load(new FileInputStream(SERVER_KEYSTORE_PATH), SERVER_KEYSTORE_PASSWORD.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(tks);

SSLContext ctx = SSLContext.getInstance("TLSv1.2");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

factory.useSslProtocol(ctx);

// 发送消息,测试连接
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);

byte[] message = ("test message").getBytes();
channel.basicPublish(DEFAULT_EXCHANGE, QUEUE_NAME, null, message);

channel.close();
connection.close();
}
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869


7.3 C#客户端
 由于使用tls-gen生成证书时,是自己作为CA进行签名的,需将CA的证书导入受信任的根证书颁发机构。
 运行“certmgr.msc”:

 将testca/cacert.cer文件导入受信任的根证书颁发机构:

 证书导入后如下:

 C#客户端如下:
public class Sender
{
// RabbitMQ服务端地址、端口、用户名、密码
private const string ADDRESS = "10.176.64.227";
private const int PORT = 5671;
private const string USERNAME = "mqtester";
private const string PASSWORD = "mqtester";

private const string DEFAULT_EXCHANGE = "";
private const string QUEUE_NAME = "Queue_C#";

// 使用tls-gen生成证书的服务器的主机名,该值必须填写正确
private const string SERVER_NAME = "centos7";
// 客户端证书文件client_key.p12路径
private const string CLIENT_CERT_PATH = "F:\\client_key.p12";
// 使用tls-gen工具生成证书文件时设置的私钥密码
private const string CLIENT_CERT_PASSWORD = "123456";

public static void Main(string[] args)
{
var factory = new ConnectionFactory()
{
HostName = ADDRESS,
Port = PORT,
UserName = USERNAME,
Password = PASSWORD,
};
// 启用SSL\TLS
factory.Ssl.ServerName = SERVER_NAME;
factory.Ssl.CertPath = CLIENT_CERT_PATH;
factory.Ssl.CertPassphrase = CLIENT_CERT_PASSWORD;
factory.Ssl.Enabled = true;

// 发送消息,测试连接
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(QUEUE_NAME, false, false, false, null);
byte[] message = Encoding.UTF8.GetBytes("test message");
channel.BasicPublish(DEFAULT_EXCHANGE, QUEUE_NAME, null, message);
}
}
}
}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP