Whenever the RabbitMQ broker is exposed to the Internet, it is highly advisable to protect the connections by using the SSL library.
RabbitMQ does not implement SSL by itself, but it uses the certificate mechanism of the given language, Erlang for the server and Java, .NET, or whatever for the clients.
Here, we will see how to have a basic protection with SSL, that is, how to encrypt the connections from the RabbitMQ clients to the broker.
This is enough to avoid simple security attacks. With no SSL, usernames and passwords are sent just in clear through the network.
The current example has the following prerequisites:
We have chosen to limit this recipe to just Linux on the server side because on Windows, there are too many version combinations—some with limited or no functionality at all. It is a good idea to run your secured Internet facing RabbitMQ servers on Linux or a Unix OS.
For more information on Windows support, you can go to http://www.rabbitmq.com/ssl.html.
Perform the following steps to set up the Certificate Authority and configure the server:
Chapter03/Recipe03/certificates/01_setup_CA.sh
:mkdir testca cd testca mkdir certs private chmod 700 private echo 01 > serial touch index.txt
openssl
configuration file, which you can already find in Chapter03/Recipe03/certificates/testca/openssl.cnf
.Chapter03/Recipe03/certificates/02_create_CA_certificates.sh
:openssl req -x509 -config openssl.cnf -newkeyrsa:2048 -days 365 -out cacert.pem -outform PEM -subj /CN=MyTestCA/ -nodes openssl x509 -in cacert.pem -out cacert.cer -outform DER
Chapter03/Recipe03/certificates/03_create_server_certificates.sh
:openssl genrsa -out key.pem 2048
openssl req -new -key key.pem -out req.pem -outform PEM -subj /CN=$(hostname)/O=server/ -nodes
openssl ca -config openssl.cnf -in ../server/req.pem –out ../server/cert.pem -notext -batch –extensions server_ca_extensions
Chapter03/Recipe03/certificates
, the CA certificate, the server certificate, and the server private key, which we have just created, to the absolute paths:/usr/local/certificates/testca/cacert.pem /usr/local/certificates/server/cert.pem /usr/local/certificates/server/key.pem
rabbitmq.config
, in the appropriate directory (/etc/rabbitmq
) by copying it from Chapter03/Recipe03/rabbitmq.config
:[ {rabbit, [ {ssl_listeners, [5671]}, {ssl_options, [ {cacertfile,"/usr/local/certificates/testca/cacert.pem"}, {certfile,"/usr/local/certificates/server/cert.pem"}, {keyfile,"/usr/local/certificates/server/key.pem"}, {verify,verify_peer}, {fail_if_no_peer_cert,false}]} ]} ].
rabbitmqctl stop rabbitmq-server–detached.
When you restart a RabbitMQ node, the Erlang Node will also restart.
Chapter03/Recipe03/src/rmqexample/Publish.java
:ConnectionFactory factory = new ConnectionFactory(); factory.setHost(hostname); factory.setPort(5671); factory.useSslProtocol(); Connection connection = factory.newConnection();
We started this recipe by creating a CA with which we will sign the certificates for the server.
We have performed this step on the server, but in the real world, the CA and, in particular, its private key (created in step 3) should be kept separate.
After the CA is ready, we have to prepare the server certificate as shown in steps 4-6.
We are almost done. We just need to copy the CA certificate, the server certificate, and the server public key to the final path (step 7). We have chosen to store them in /usr/local/certificates
, but it is totally arbitrary since they are referenced in the RabbitMQ configuration file, rabbitmq.config
.
This file does not exist by default. It must be placed in the standard configuration directory, usually in /etc/rabbitmq
.
Apart from the security files, we have configured the RabbitMQ SSL port (5671), and a couple of options in rabbitmq.config
:
Verify
: When this is set to verify_peer
, it tells RabbitMQ that if the client presents a certificate, it will be checked and rejected if not valid (because the CA is not the same or because it is expired)fail_if_no_peer_cert
: When this is set to false
, it tells RabbitMQ to accept clients that do not present any certificate at allAfter we have restarted RabbitMQ (you must use rabbitmqctl
stop and restart the service), you can verify whether it has got the options by examining the logfile in /var/log/rabbitmq
. You should be able to find a line as follows:
started SSL Listener on [::]:5671
Furthermore, by opening the management plugin from a browser, you will be able to get similar information (see the Managing RabbitMQ from a browser recipe), as shown in the following screenshot:
At this point it is possible to connect via SSL from a client by just adding these two options to the connection factory:
factory.setPort(5671); factory.useSslProtocol();
Now the connection is encrypted using the keys configured in the server.
Since we are using server certificates only, the communication between the server and the client is encrypted, but we are not protected against MITM (man-in-the-middle) attacks.
If we want to let any client connect to the server and avoid MITM attacks, we can use the same strategy as that used by HTTPS and the browsers, which is signing the certificates with trusted third-party CAs and verifying the domain signed in the certificates. Otherwise, we can just go on and read the next recipe.