RabbitMQ SSL设置

最近在配置RabbitMQ SSL连接支持,阅读了RabbitMQ官方的文档,觉得官方文档不是那么好理解;

在Google了一番之后,我发现了这篇文章:

http://www.gettingcirrius.com/2013/01/configuring-ssl-for-rabbitmq.html

国内的童鞋们也许需要通过代理才能访问,不过没关系,作者还在github上写了一些shell脚本方便生成证书,项目github地址为:

https://github.com/Berico-Technologies/CMF-AMQP-Configuration

可直接通过git命令进行clone到本地:

git clone https://github.com/Berico-Technologies/CMF-AMQP-Configuration.git

 在clone后的项目目录中,doc文件夹下有详细的说明shell脚本如何使用。

 

对RabbitMQ SSL支持官方文档感兴趣的童鞋,请移步:

https://www.rabbitmq.com/ssl.html

 

1. 确保已经安装好了openssl,具体安装方法请自行google;

切换到 CMF-AMQP-Configuration/ssl 文件夹,运行

sh setup_ca.sh MyRabbitMQCA

 此处我将自己的Certificate Authority名称定义为"MyRabbitMQCA",这个名字可以自行指定,用于在证书中显示证书颁发机构名;

 

2. 生成服务器证书

运行

sh make_server_cert.sh www.myrabbit.com rabbit

 生成服务器证书

 第一个参数是服务器名,第二个参数是密码;

 

3. 生成客户端证书

运行

sh create_client_cert.sh rabbit-client rabbit

 生成客户端证书

 第一个参数是客户端名称,第二个参数是密码

 

4. 执行完以上步骤之后,会在ssl目录下生产以下文件夹:

  - ca

  - server

  - client

 

配置RabbitMQ SSL只会用到以下3个文件:

  • ca/cacert.pem
  • server/{hostname}.cert.pem
  • server/{hostname}.key.pem

5. 配置RabbitMQ

修改RabbitMQ的配置文件(该文件位于:/etc/rabbitmq/rabbitmq.config)

sudo vi /etc/rabbitmq/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,"/path/to/ca/cacert.pem"},
            {certfile,"/path/to/server/{hostname}.cert.pem"},
            {keyfile,"/path/to/server/{hostname}.key.pem"},
            {verify, verify_peer},
            {fail_if_no_peer_cert, true},
            {versions, ['tlsv1.2', 'tlsv1.1']}
        ]}
    ]}
].

 建议可以把需要用到的3个文件带目录结构拷贝到  /etc/rabbitmq/ssl 目录下,那么配置文件内容为:

写道
%% 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/www.myrabbit.com.cert.pem"},
            {keyfile,"/etc/rabbitmq/ssl/server/www.myrabbit.com.key.pem"},
            {verify, verify_peer},
            {fail_if_no_peer_cert, true},
            {versions, ['tlsv1.2', 'tlsv1.1']}
        ]}
    ]}
].

 这样我们就能支持普通连接和ssl连接,它们的端口分别为 5672 和 5671

 

设置完成后,重启RabbitMQ以应用新配置;

 

在RabbitMQ重启完成之后,可以在web控制台查看到已经监听 5671 端口:


 
 

 

使用keytool导入证书:

keytool命令格式如下:

 

# keytool -import -alias <server name> -file /path/to/server/cert.pem -keystore /path/to/rabbitstore
 在我的例子中,应该执行的命令为:

 

# keytool -import -alias www.myrabbit.com -file /etc/rabbitmq/ssl/server/www.myrabbit.com.cert.pem -keystore /etc/rabbitmq/ssl/rabbitstore
 指定输出的keystore文件路径为:/etc/rabbitmq/ssl/rabbitstore
命令执行的过程中,会需要输入密码,密码为之前设置的“rabbit”
 

使用SSL从客户端连接RabbitMQ

代码:

 

package test.rabbitmq;

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

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.security.KeyStore;

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

		char[] keyPassphrase = "rabbit".toCharArray();
		KeyStore ks = KeyStore.getInstance("PKCS12");
		ks.load(new FileInputStream("/etc/rabbitmq/ssl/client/rabbit-client.keycert.p12"), keyPassphrase);

		KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
		kmf.init(ks, keyPassphrase);

		char[] trustPassphrase = "rabbit".toCharArray();
		KeyStore tks = KeyStore.getInstance("JKS");
		tks.load(new FileInputStream("/etc/rabbitmq/ssl/keystore"), trustPassphrase);

		TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
		tmf.init(tks);

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

		ConnectionFactory factory = new ConnectionFactory();
		factory.setHost("localhost");
		factory.setPort(5671);
		factory.useSslProtocol(c);

		Connection conn = factory.newConnection();
		Channel channel = conn.createChannel();

		channel.queueDeclare("rabbitmq-java-test", false, true, true, null);
		channel.basicPublish("", "rabbitmq-java-test", null, "Hello, World via SSL".getBytes());

		GetResponse chResponse = channel.basicGet("rabbitmq-java-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();
	}
}
 

 运行之后,应该可以在控制台看到如下输出: