参考文献

运维侧配置

使用TSL工具生成证书

1
2
3
4
5
6
7
git clone https://github.com/rabbitmq/tls-gen tls-gen
cd tls-gen/basic
# private key password
make PASSWORD=bunnies
make verify
make info
ls -l ./result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
[root@iZuf6ib0sh7w9cc92x0h4qZ basic]# make PASSWORD=holelin
python3 profile.py regenerate --password "holelin" \
--common-name 'iZuf6ib0sh7w9cc92x0h4qZ' \
--client-alt-name iZuf6ib0sh7w9cc92x0h4qZ \
--server-alt-name iZuf6ib0sh7w9cc92x0h4qZ \
--days-of-validity 3650 \
--key-bits 2048
Removing /root/tls-gen-main/basic/testca
Removing /root/tls-gen-main/basic/result
Removing /root/tls-gen-main/basic/server
Removing /root/tls-gen-main/basic/client
Will generate a root CA and two certificate/key pairs (server and client)
=> [openssl_req]
Generating a RSA private key
..............+++++
....................................+++++
writing new private key to '/root/tls-gen-main/basic/testca/private/cakey.pem'
-----
=> [openssl_x509]
Will generate leaf certificate and key pair for server
Using iZuf6ib0sh7w9cc92x0h4qZ for Common Name (CN)
Using parent certificate path at /root/tls-gen-main/basic/testca/cacert.pem
Using parent key path at /root/tls-gen-main/basic/testca/private/cakey.pem
Will use RSA...
=> [openssl_genpkey]
..............................................................................+++++
..........+++++
=> [openssl_req]
=> [openssl_ca]
Using configuration from /tmp/tmpgpay6k2e
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName :ASN.1 12:'iZuf6ib0sh7w9cc92x0h4qZ'
organizationName :ASN.1 12:'server'
localityName :ASN.1 12:'$$$$'
Certificate is to be certified until Nov 18 03:40:18 2032 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 iZuf6ib0sh7w9cc92x0h4qZ for Common Name (CN)
Using parent certificate path at /root/tls-gen-main/basic/testca/cacert.pem
Using parent key path at /root/tls-gen-main/basic/testca/private/cakey.pem
Will use RSA...
=> [openssl_genpkey]
..........................................+++++
...........................................................................................+++++
=> [openssl_req]
=> [openssl_ca]
Using configuration from /tmp/tmpgpay6k2e
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName :ASN.1 12:'iZuf6ib0sh7w9cc92x0h4qZ'
organizationName :ASN.1 12:'client'
localityName :ASN.1 12:'$$$$'
Certificate is to be certified until Nov 18 03:40:18 2032 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 --common-name 'iZuf6ib0sh7w9cc92x0h4qZ'
Will verify generated certificates against the CA...
Will verify client_iZuf6ib0sh7w9cc92x0h4qZ certificate against root CA
/root/tls-gen-main/basic/result/client_iZuf6ib0sh7w9cc92x0h4qZ_certificate.pem: OK
Will verify server_iZuf6ib0sh7w9cc92x0h4qZ certificate against root CA
/root/tls-gen-main/basic/result/server_iZuf6ib0sh7w9cc92x0h4qZ_certificate.pem: OK
1
2
3
4
5
6
7
[root@iZuf6ib0sh7w9cc92x0h4qZ basic]# make verify
python3 profile.py verify --common-name 'iZuf6ib0sh7w9cc92x0h4qZ'
Will verify generated certificates against the CA...
Will verify client_iZuf6ib0sh7w9cc92x0h4qZ certificate against root CA
/root/tls-gen-main/basic/result/client_iZuf6ib0sh7w9cc92x0h4qZ_certificate.pem: OK
Will verify server_iZuf6ib0sh7w9cc92x0h4qZ certificate against root CA
/root/tls-gen-main/basic/result/server_iZuf6ib0sh7w9cc92x0h4qZ_certificate.pem: OK
1
2
3
4
5
6
7
8
9
10
[root@iZuf6ib0sh7w9cc92x0h4qZ basic]# ls -l result/
总用量 32
-rw-r--r-- 1 root root 1281 11月 21 11:40 ca_certificate.pem
-rw------- 1 root root 1854 11月 21 11:40 ca_key.pem
-rw-r--r-- 1 root root 1326 11月 21 11:40 client_iZuf6ib0sh7w9cc92x0h4qZ_certificate.pem
-rw------- 1 root root 2541 11月 21 11:40 client_iZuf6ib0sh7w9cc92x0h4qZ_key.p12
-rw------- 1 root root 1874 11月 21 11:40 client_iZuf6ib0sh7w9cc92x0h4qZ_key.pem
-rw-r--r-- 1 root root 1411 11月 21 11:40 server_iZuf6ib0sh7w9cc92x0h4qZ_certificate.pem
-rw------- 1 root root 2605 11月 21 11:40 server_iZuf6ib0sh7w9cc92x0h4qZ_key.p12
-rw------- 1 root root 1874 11月 21 11:40 server_iZuf6ib0sh7w9cc92x0h4qZ_key.pem
1
[root@iZuf6ib0sh7w9cc92x0h4qZ ~]# keytool -import -alias server -file ./tls-gen-main/basic/result/server_iZuf6ib0sh7w9cc92x0h4qZ_certificate.pem  -keystore ./tls-gen-main/basic/result/keystore
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
###授权方式
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 = ~/tls-gen-main/basic/result/ca_certificate.pem
ssl_options.certfile = ~/tls-gen-main/basic/result/server_iZuf6ib0sh7w9cc92x0h4qZ_certificate.pem
ssl_options.keyfile = ~/tls-gen-main/basic/result/server_iZuf6ib0sh7w9cc92x0h4qZ_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

应用侧配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package com.holelin.sundry;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import java.util.concurrent.TimeoutException;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

/**
* To use client site authentication via SSL you need to provide a keyfile in PKCS#12 Format, initialize the Keymanager,
* Keystore, and TrustManager.
* <p>
* A short explanation can be found here (https://www.rabbitmq.com/ssl.html#trust-levels) For a more in-depth discussion
* please refer https://www.digitalocean.com/community/tutorials/java-keytool-essentials-working-with-java-keystores
* https://docs.oracle.com/cd/E19509-01/820-3503/ggfen/index.html https://lmgtfy.com/?q=java+keystore
* <p>
* Unfortunately, all these Exceptions are necessary. Handle them properly.
*
* @throws KeyManagementException
* @throws NoSuchAlgorithmException
* @throws IOException
* @throws UnrecoverableKeyException
* @throws KeyStoreException
* @throws CertificateException
*/
public class VerifyClient {

//Change to match your config
private static String HOST_IP = "192.168.40.10";
private static int HOST_PORT = 5671;

private static String USERNAME = "test";
private static String PASSWORD = "test";

private static String QUEUE_NAME = "hello";

public VerifyClient()
throws KeyManagementException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, KeyStoreException, CertificateException, TimeoutException {

char[] keyPassphrase = "rabbit".toCharArray();
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream("/path/to/clientcert.p12"), keyPassphrase);

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

/**
* You need to create a keystore beforehand.
*
* To import an exsisting keyfile, you can use the keytool:
* $~> keytool -import -alias server1 -file /path/to/server/cert.pem -keystore /path/to/keystore
*/
char[] trustPassphrase = "rabbit".toCharArray();
KeyStore tks = KeyStore.getInstance("JKS");
tks.load(new FileInputStream("/path/to/keystore"), trustPassphrase);

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

//Like in the server site ssl example, you define the used SSL version here.
SSLContext c = SSLContext.getInstance("TLSv1.2");
c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

//Setting up the Connection
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(HOST_IP);
factory.setPort(HOST_PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);

//All SSL configuration gets passed via a "SSLContext"-Parameter, which is defined above.
factory.useSslProtocol(c);

//Establish a connection
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();

//Publish
channel.queueDeclare(QUEUE_NAME, false, true, true, null);
String message = "Hello World!";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println(" [x] Sent '" + message + "'");

//Consume it. Must be a second connection to
//Catch the previous message
Channel second = connection.createChannel();
Consumer consumer = new DefaultConsumer(second) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" [x] Received '" + message + "'");
}
};
second.basicConsume(QUEUE_NAME, true, consumer);

//Clean up
channel.close();
second.close();
connection.close();
}

}