分享

rabbitmq使用TLS支持SSL加密处理

 三十的狼 2021-04-02

最近在开发过程中, 有收到要求,rabbitmq 不能使用明文传输,常规想法就是TLS加密传输。看到rabbitmq 官网有提供TLS支持的说明。

Rabbitmq 加密传输由2种方式:

  1. 使用TLS加密直连
  2. 通过类似HA代理的方式从https转换成http 比如nginx, TLS_termination_proxy等都可以实现

官网也阐述了其他一些ssl支持的说明,这边就不介绍了。详细内容查阅官网

本文使用的rabbitmq 环境是,依赖docker 构建的rabbitmq 3.7.28版本的试验环境。

这边具体说一下,怎么构建TLS链接。

步骤1:使用TLS工具生成证书(开发测试环境),生产环境建议使用商业的CA机构制作的证书文件

git clone https://github.com/michaelklishin/tls-gen tls-gen
cd tls-gen/basic
# private key password
make PASSWORD=密码
make verify
make info
ls -l ./result

其中make PASSWORD=密码 这一行命名是生成证书的过程,其他几行都是校验检测,可以不执行。

make PASSWORD=rabbit
python3 profile.py regenerate --password "rabbit" --common-name izbp1exs0zcohfndb4w0o5z --client-alt-name izbp1exs0zcohfndb4w0o5z --server-alt-name izbp1exs0zcohfndb4w0o5z --days-of-validity 3650 --key-bits 2048
Removing /mnt/tls-gen/basic/testca
Removing /mnt/tls-gen/basic/result
Removing /mnt/tls-gen/basic/server
Removing /mnt/tls-gen/basic/client
Will generate a root CA and two certificate/key pairs (server and client)
=>[openssl_req]
Generating a 2048 bit RSA private key
...........................................................+++
....................+++
writing new private key to '/mnt/tls-gen/basic/testca/private/cakey.pem'
-----
=>[openssl_x509]
Will generate leaf certificate and key pair for server
Using izbp1exs0zcohfndb4w0o5z for Common Name (CN)
Using parent certificate path at /mnt/tls-gen/basic/testca/cacert.pem
Using parent key path at /mnt/tls-gen/basic/testca/private/cakey.pem
Will use RSA...
=>[openssl_genpkey]
..........................................................+++
...........................................................+++
=>[openssl_req]
=>[openssl_ca]
Using configuration from /tmp/tmpaxii46i1
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'izbp1exs0zcohfndb4w0o5z'
organizationName      :ASN.1 12:'server'
localityName          :ASN.1 12:'$$$$'
Certificate is to be certified until Nov 13 15:01:00 2030 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated
=>[openssl_pkcs12]
Will generate leaf certificate and key pair for client
Using izbp1exs0zcohfndb4w0o5z for Common Name (CN)
Using parent certificate path at /mnt/tls-gen/basic/testca/cacert.pem
Using parent key path at /mnt/tls-gen/basic/testca/private/cakey.pem
Will use RSA...
=>[openssl_genpkey]
....................+++
.......+++
=>[openssl_req]
=>[openssl_ca]
Using configuration from /tmp/tmpaxii46i1
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'izbp1exs0zcohfndb4w0o5z'
organizationName      :ASN.1 12:'client'
localityName          :ASN.1 12:'$$$$'
Certificate is to be certified until Nov 13 15:01:00 2030 GMT (3650 days)

Write out database with 1 new entries
Data Base Updated
=>[openssl_pkcs12]
Done! Find generated certificates and private keys under ./result!
python3 profile.py verify
Will verify generated certificates against the CA...
Will verify client certificate against root CA
/mnt/tls-gen/basic/result/client_certificate.pem: OK
Will verify server certificate against root CA
/mnt/tls-gen/basic/result/server_certificate.pem: OK

上述命令会生成一些目录和证书文件

其中 result 目录,将CA buddle, server ,client 证书信息都汇集了一些,没有说明不同。

步骤2: 使用jdk的keytool 生成Java相关的配置信息, 中间过程,需要输入密码信息

keytool -import -alias server1   -file /mnt/rabbitmq/cert/server_certificate.pem  -keystore /mnt/rabbitmq/cert/rabbitstore

这个过程其实就是想rabbitmq 服务端的证书适配成符合Java规则的rabbitstore文件,注意这个是server端的certificate.

输出结果:

Enter keystore password:
Re-enter new password:
Owner: O=server, CN=izbp1exs0zcohfndb4w0o5z
Issuer: L=$$$$, CN=TLSGenSelfSignedtRootCA
Serial number: 1
Valid from: Sun Nov 15 21:54:44 CST 2020 until: Wed Nov 13 21:54:44 CST 2030
Certificate fingerprints:
 MD5:  E0:84:44:70:74:27:5D:CE:09:CF:02:63:8E:65:01:1B
 SHA1: F4:42:AF:0A:6E:B7:C9:D6:44:04:DB:E0:61:88:AD:BD:46:B4:3B:EE
 SHA256: C0:C9:79:27:05:B9:09:7C:F0:8B:3A:FD:14:C0:21:16:B6:58:F9:12:89:11:5C:08:F1:EC:53:55:86:DA:6F:7D
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions:

#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 3B B1 04 9E D9 66 1A 5C   7A B6 F8 38 11 79 17 A2  ;....f.\z..8.y..
0010: 7C 44 6F 9C                                        .Do.
]
]

#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:false
  PathLen: undefined
]

#3: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
  serverAuth
]

#4: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
  DigitalSignature
  Key_Encipherment
]

#5: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  DNSName: izbp1exs0zcohfndb4w0o5z
  DNSName: izbp1exs0zcohfndb4w0o5z
  DNSName: localhost
]

#6: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 65 45 D5 3F C8 13 F1 C4   F8 DD A8 28 14 61 0E 7E  eE.?.......(.a..
0010: 19 54 AB AA                                        .T..
]
]

Trust this certificate? [no]:
Certificate was not added to keystore
[root@izbp1exs0zcohfndb4w0o5z cert]# keytool -import -alias server1   -file /mnt/rabbitmq/cert/server_certificate.pem  -keystore /mnt/rabbitmq/cert/rabbitstore
Enter keystore password:
Re-enter new password:
Owner: O=server, CN=izbp1exs0zcohfndb4w0o5z
Issuer: L=$$$$, CN=TLSGenSelfSignedtRootCA
Serial number: 1
Valid from: Sun Nov 15 21:54:44 CST 2020 until: Wed Nov 13 21:54:44 CST 2030
Certificate fingerprints:
 MD5:  E0:84:44:70:74:27:5D:CE:09:CF:02:63:8E:65:01:1B
 SHA1: F4:42:AF:0A:6E:B7:C9:D6:44:04:DB:E0:61:88:AD:BD:46:B4:3B:EE
 SHA256: C0:C9:79:27:05:B9:09:7C:F0:8B:3A:FD:14:C0:21:16:B6:58:F9:12:89:11:5C:08:F1:EC:53:55:86:DA:6F:7D
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions:

#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 3B B1 04 9E D9 66 1A 5C   7A B6 F8 38 11 79 17 A2  ;....f.\z..8.y..
0010: 7C 44 6F 9C                                        .Do.
]
]

#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:false
  PathLen: undefined
]

#3: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
  serverAuth
]

#4: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
  DigitalSignature
  Key_Encipherment
]

#5: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  DNSName: izbp1exs0zcohfndb4w0o5z
  DNSName: izbp1exs0zcohfndb4w0o5z
  DNSName: localhost
]

#6: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 65 45 D5 3F C8 13 F1 C4   F8 DD A8 28 14 61 0E 7E  eE.?.......(.a..
0010: 19 54 AB AA                                        .T..
]
]

#####这边要求输入yes
Trust this certificate? [no]:  yes
Certificate was added to keystore

步骤3 配置rabbit MQ 配置文件

###授权方式, 其实就是再默认的基础上加一个EXTERNAL, 如果单独配置EXTERNAL, java 客户端会出现无法找不到auth_mechanisms的问题, 这个具体还不知道原因
auth_mechanisms.1 = PLAIN
auth_mechanisms.2 = AMQPLAIN
auth_mechanisms.3 = EXTERNAL

management_agent.disable_metrics_collector = true

ssl_options.client_renegotiation = false
ssl_options.secure_renegotiate = true


###禁止 明文tcp 连接
listeners.tcp = none

##管理端只允许本地连接
management.tcp.ip = 127.0.0.1
management.tcp.port = 15672
ssl_options.password=rabbit
###tls 端口
listeners.ssl.default = 5671
###tls工具,将需要的文件存放再result 目录中
ssl_options.cacertfile = /mnt/tls-gen/basic/result/ca_certificate.pem
ssl_options.certfile   = /mnt/tls-gen/basic/result/server_certificate.pem
ssl_options.keyfile    = /mnt/tls-gen/basic/result/server_key.pem


ssl_options.verify     = verify_peer
ssl_options.fail_if_no_peer_cert = true
ssl_cert_login_from = common_name

###支持TLS协议,
ssl_options.versions.1 = tlsv1
ssl_options.versions.2 = tlsv1.1
ssl_options.versions.3 = tlsv1.2

###TLS加密cipher 顺序
ssl_options.honor_cipher_order = true
ssl_options.honor_ecc_order    = true
###TLS加密cipher
ssl_options.ciphers.1=ECDHE-ECDSA-AES256-GCM-SHA384
ssl_options.ciphers.2=ECDHE-RSA-AES256-GCM-SHA384
ssl_options.ciphers.3=ECDH-ECDSA-AES256-GCM-SHA384
ssl_options.ciphers.4=ECDH-RSA-AES256-GCM-SHA384
ssl_options.ciphers.5=DHE-RSA-AES256-GCM-SHA384
ssl_options.ciphers.6=DHE-DSS-AES256-GCM-SHA384
ssl_options.ciphers.7=ECDHE-ECDSA-AES128-GCM-SHA256
ssl_options.ciphers.8=ECDHE-RSA-AES128-GCM-SHA256
ssl_options.ciphers.9=ECDH-ECDSA-AES128-GCM-SHA256
ssl_options.ciphers.10=ECDH-RSA-AES128-GCM-SHA256
ssl_options.ciphers.11=DHE-RSA-AES128-GCM-SHA256
ssl_options.ciphers.12=DHE-DSS-AES128-GCM-SHA256
ssl_options.ciphers.13=ECDHE-ECDSA-AES256-SHA384
ssl_options.ciphers.14=ECDHE-RSA-AES256-SHA384
ssl_options.ciphers.15=ECDHE-ECDSA-DES-CBC3-SHA
ssl_options.ciphers.16=ECDH-ECDSA-AES256-SHA384
ssl_options.ciphers.17=ECDH-RSA-AES256-SHA384
ssl_options.ciphers.18=DHE-DSS-AES256-SHA256
ssl_options.ciphers.19=AES256-GCM-SHA384
ssl_options.ciphers.20=AES256-SHA256
ssl_options.ciphers.21=ECDHE-ECDSA-AES128-SHA256
ssl_options.ciphers.22=ECDHE-RSA-AES128-SHA256
ssl_options.ciphers.23=ECDH-ECDSA-AES128-SHA256
ssl_options.ciphers.24=ECDH-RSA-AES128-SHA256
ssl_options.ciphers.25=DHE-DSS-AES128-SHA256
ssl_options.ciphers.26=AES128-GCM-SHA256
ssl_options.ciphers.27=AES128-SHA256
ssl_options.ciphers.28=ECDHE-ECDSA-AES256-SHA
ssl_options.ciphers.29=ECDHE-RSA-AES256-SHA
ssl_options.ciphers.30=DHE-DSS-AES256-SHA
ssl_options.ciphers.31=ECDH-ECDSA-AES256-SHA
ssl_options.ciphers.32=ECDH-RSA-AES256-SHA
ssl_options.ciphers.33=AES256-SHA
ssl_options.ciphers.34=ECDHE-ECDSA-AES128-SHA
ssl_options.ciphers.35=ECDHE-RSA-AES128-SHA
ssl_options.ciphers.36=DHE-DSS-AES128-SHA
ssl_options.ciphers.37=ECDH-ECDSA-AES128-SHA
ssl_options.ciphers.38=ECDH-RSA-AES128-SHA
ssl_options.ciphers.39=AES128-SHA

步骤4 Java 客户端连接测试

这边说明一下,官网的demo,大部分都是对的,但是会有些小问题
比如: 需要将factory.enableHostnameVerification(); 取消。

    public static void main(String[] args) throws Exception {
       // tls 执行命令中设置的密码 make PASSWORD=rabbit
        char[] passphrase = "rabbit".toCharArray();
        KeyStore ks = KeyStore.getInstance("PKCS12");
        //tls生成的result目录下的client_key.p12
        ks.load(new FileInputStream("D:\\work\\client_key.p12"), passphrase);

        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(ks, passphrase);
  //keytools 生成过程中,设置的密码
        char[] trustPassphrase = "rabbit".toCharArray();
        KeyStore tks = KeyStore.getInstance("JKS");
        //keytools 生成的rabbitstore
        tks.load(new FileInputStream("D:\\work\\rabbitstore"), trustPassphrase);

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

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

        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("IP地址");
        factory.setPort(5671);
        factory.useSslProtocol(c);
        factory.setUsername("admin");
        factory.setPassword("admin");
//        factory.enableHostnameVerification();

        Connection conn = factory.newConnection();
        Channel channel = conn.createChannel();
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        DeliverCallback deliverCallback = (consumerTag, delivery) -> {
            String message = new String(delivery.getBody(), "UTF-8");
            System.out.println(" [x] Received '" + message + "'");
        };
        channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> {
        });
    }
  

上面就是基本的rabbitmq tls 的基础支持。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多