为艺术而技术

RabbitMQ的客户端TLS升级

October 06, 2021

最近项目中连接的RabbitMQ升级到TLS登录了,这样就不用设置用户名和密码了,更安全了,下面把升级中的过程记录一下。

背景

当涉及安全性的时候,一般都要聊两个概念: Authentication和Authorization。前者指的是系统需要确认你是你,后者是指系统应该知道的你的权限如何。这里还有另外一环,就是中间的传输加密,一般就是SSL。而这次RabbitMQ的升级就是这两个方面。首先是系统如何知道你是你。 公司内部一般都有一个公告的自签名证书,如果有钱,也可以去买一个证书,基于这个母证书,你可以生成自己的专用证书(密钥)以及相应的密码。应为服务端也是拥有这个专有证书的另一半(公钥)。所以当你带着这个证书登录时,系统就知道你是谁了。SSL也是类似,但是SSL是用客户端公钥加密,服务端用私钥解密,所以TLS一般都是对称加密。具体请看到wiki

步骤

在公司这个系统中,使用的是NodeJs,所以库使用的是amqplib

连接

注意这个连接中的协议已经从amqp变成了amqps

var open = require('amqplib').connect('amqps://localhost', opts);
open.then(function(conn){
    // ...
}).then(null, console.warn)

公钥私钥

这个是定义在options这个连接参数对象里。

options = {
    pfx: fs.readFileSync(pfxFile),
    passphrase: passphrase,
    ca: [fs.readFileSync(uatPemFile), fs.readFileSync(prodPemFile)],
}

SSL

这个也是通过options来实现的,官方例子也有具体解释 Line 54

options = {
    credentials: amqp.credentials.external(),
}

顺便列下C#和Java版本的对应配置

public override ConnectionFactory GetConnectionFactory(){
    return new ConnectionFactory{
        Uri = new Uri(this.GetConnectionString("secureNoCredentials")),
        Ssl = {
            Enabled = true,
            Version = SslProtocols.Tls12,
            ServerName = GetServerName(),
            CertPath = GetCertPath(),
            CertPassphrase = GetCertPassphrase(),
        },
        AuthMechanisms = new AuthMechanismFactory[] {new ExternalMechanismFacotry()}
    };
}
private void SetSaslConfigToExternal(ConnectionFactory connectionFactory){
    CachingConnectionFactory cachingConnectionFactory = (CachingConnectionFactory) connectionFactory;
    if(cachingConnectionFactory != null){
        if(cachingConnectionFactory.getRabbitConnectionFactory().isSSL()){
            cachingConnectionFactory.getRabbitConnectionFactory().setSaslConfig(DefaultSaslConfig.EXTERNAL);
        }
    }
}

如果没有这个设定,就会出现下面的错误:

Error: Handshake terminated by server: 403(ACCESS-REFUSED) with message \"ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.\""}

其他

关于在服务端激活TLS,可以参考官方文档。本质上和客户端是对应的,也是三个key

listeners.ssl.default = 5671

ssl_options.cacertfile = /path/to/ca_certificate.pem
ssl_options.certfile   = /path/to/server_certificate.pem
ssl_options.keyfile    = /path/to/server_key.pem
ssl_options.verify     = verify_peer
ssl_options.fail_if_no_peer_cert = true

© 2019 - 2021 yuanqingfei
Creative Commons License