Kannisto.org

Petri Kannisto's homepage – about software systems and research

Secure RabbitMQ broker in virtualized Ubuntu Server

(updated ) – Petri Kannisto

DISCLAIMER. This guide comes "as is". This means that the author does not have any liability. You must consider carefully before exposing any server to the public Internet, because this is always risky. It is up to you to estimate if you know what you are doing.

Introduction

This guide provides you step-by-step instructions to install RabbitMQ in a virtualized Ubuntu Linux that:

I originally wrote this guide in 2017-2018 for RabbitMQ 3.6 in Ubuntu Server 16.04.6 LTS. However, the content is likely still valid, although some sections have been updated without trying if they truly work.

Instead of installing RabbitMQ from the bottom, you could run a Docker container ( https://hub.docker.com/_/rabbitmq ). This is straigthforward if Docker is familiar to you. However, follow this guide if you want to set up your own server.

Prerequisites

This guide assumes that you know the following. If you don't, the Internet is full of guides anyway.

Furthermore, your server must have a domain name. Otherwise, you cannot get yourself a certificate.

Known shortcomings

This guide could improve at least the following.

Ubuntu setup

This guide assumes that you install RabbitMQ on top of Ubuntu Server following this blog post: Virtualized Ubuntu Server for Internet services. If your system differs from this, be ready to adapt.

Firewall

By default, RabbitMQ exposes port 5671 for encrypted client connections. Assuming you use UFW as the firewall, you can open this port as follows.

sudo ufw allow 5671

The risk of the above is that the connections may come from any IP address. Therefore, if you can, you should limit this to a subset of IPs. For instance:

sudo ufw allow proto tcp from 192.168.144.1/24 to any port 5671

Disable automatic updates for Erlang

This section assumes you have enabled the tool Unattended-Upgrades.

There's one automatic update you want to avoid, namely Erlang, which is the runtime of RabbitMQ. You want this because an update may handicap RabbitMQ.

To blacklist Erlang from automatic updates, you must edit a file. I believe the file exists by default:

sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

If an entry called "Unattended-Upgrade::Package-Blacklist" is there, add the following line:

"erlang";

If the blacklist entry is missing, add it as follows:

Unattended-Upgrade::Package-Blacklist {
      "erlang";
};

Install RabbitMQ

This part has been updated from the previous installation, but it has not been tried with a fresh machine.

Add Erlang repository to Ubuntu software sources (execute this in a directory under /home):

wget https://packages.erlang-solutions.com/erlang-solutions_2.0_all.deb
sudo dpkg -i erlang-solutions_2.0_all.deb

Install/update Erlang:

sudo apt-get install erlang

Add RabbitMQ signing key as a trusted key:

curl -fsSL https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc | sudo apt-key add -

Enable HTTPS transport with Apt:

sudo apt-get install apt-transport-https

Add RabbitMQ repository to Ubuntu software sources. This will create the file "bintray.rabbitmq.list". In deb command, "bionic" is for Ubuntu 20.04. For other versions, see https://www.rabbitmq.com/install-debian.html

echo "deb https://dl.bintray.com/rabbitmq/debian bionic main" | sudo tee /etc/apt/sources.list.d/bintray.rabbitmq.list

Install RabbitMQ server:

sudo apt-get install rabbitmq-server

Next, it is advisable to try that RabbitMQ works. Create a simple piece of software that both publishes messages and subscribes for messages. If you fail, the logs may help. See /var/log/rabbitmq.

Configure RabbitMQ users

Change username of "guest"

By default, RabbitMQ has a user called "guest". This has a default password "guest", which is nice for quick experiments but a risk in actual use.

To change the password (replace "PWD" with an actual password):

rabbitmqctl change_password guest PWD

Create RabbitMQ admin user

To manage RabbitMQ, you should have a dedicated admin user. This is user is different from the user accounts of Ubuntu and works only in the context of RabbitMQ. Furthermore, you aren't supposed to authenticate any RabbitMQ clients with this user.

This guide assumes you pick "localrmqadmin" as the username, because this is descriptive. Create the user as follows; replace "PWD" with a good password:

sudo rabbmitmqctl add_user localrmqadmin PWD

Set the permissions of user "localrmqadmin" to configure/read/write any RabbitMQ resource (this applies to at least queues and exchanges):

sudo rabbitmqctl set_permissions localrmqadmin ".*" ".*" ".*"

Set the user tag of "localrmqadmin" to "administrator":

sudo rabbitmqctl set_user_tags localrmqadmin administrator

Create client users and set permissions

Next, you need the user accounts that communicate via RabbitMQ. These can be as many as you want and have any permissions you want (or are able to set). However, these users are for communication instead of administration.

To create a user account (make sure to replace PWD with a strong password):

sudo rabbmitmqctl add_user exampleuser PWD

If you have multiple users, you may want to restrict their access. You could, for instance, specify that a user can only use a particular exchange or only exchanges that start with a certain prefix. Honestly, the permission management of RabbitMQ sucks, because you must use regular expressions and because each rule affects both exchanges and queues. However, it is doable.

With RabbitMQ, I have always used topic-based communication with randomly generated topic names. Because autogenerated queue names have the common "amq" prefix, the permissions work nicely if you allow a certain exchange name and the prefix.

For example, this allows any item that matches "myexample" or starts with "amq":

sudo rabbitmqctl set_permissions exampleuser myexample|^amq.* myexample|^amq.* myexample|^amq.*

In the example, the regex is repeated three times for different items: "configure", "write" and "read". Write and read are for messaging, but you need configure to create something. My use cases have always been happy with an identical value in each of the three.

Once you have created a rule, it's best to try if it works. Regexes are sometimes painful.

Once you have created all the beautiful regexes, you can view the result with:

sudo rabbitmqctl list_permissions

For reference, see: https://www.rabbitmq.com/rabbitmqctl.8.html

Install rabbitmqadmin tool

To enable more powerful administration, you should install the tool Rabbitmqadmin. This enables you to manage queues and exchanges. You could use the RabbitMQ browser interface instead, but the operating system has no graphical user interface and we don't want to expose the browser interface to the outside due to security risks.

In you home folder, download the "rabbitmqadmin" tool:

wget http://localhost:15672/cli/rabbitmqadmin

To make this tool accessible from any folder, move it as follows:

sudo mv rabbitmqadmin /usr/local/bin

To manage queues and exchanges with this tool, you use the RabbitMQ user "localrmqadmin" you created earlier. Example command (please note you must assign the password):

rabbitmqadmin -u localrmqadmin -p PWD delete queue name=my-fancy-queue

For more information, see https://www.rabbitmq.com/management-cli.html

Get certificates

You need a certificate and keys to set up an encrypted connection. For more information, see this blog post.

Configure RabbitMQ

Update! The config format suggested here has been deprecated since RabbitMQ 3.7. It still works as of version 3.10, but you should use the more convenient format along with the filename rabbitmq.conf. See https://www.rabbitmq.com/configure.html

This section explains how to enable and enforce encrypted connections as well as prevent the remote usage of admin users.

You can create/edit the config file as follows:

sudo nano /etc/rabbitmq/rabbitmq.config

Use the following in the file content. Make sure the filepath to certificates and key is correct as well as the format of the certificates. The keys and certificates are expected to be located at /home/hostadmin/certs. The config file does, for instance:

[
  {ssl, [{versions, ['tlsv1.2']}]},
  {rabbit, [
    {loopback_users, [<<"guest">>, <<"localrmqadmin">>]},
    {tcp_listeners, []},
    {ssl_listeners, [5671]},
    {ssl_options, [
      {cacertfile,"/home/hostadmin/certs/rootca.pem"},
      {certfile,"/home/hostadmin/certs/server.pem"},
      {keyfile,"/home/hostadmin/certs/server.key"},
      {verify,verify_none},
      {fail_if_no_peer_cert,false},
      {versions, ['tlsv1.2']}
    ]}
  ]}
].

Next, re-start RabbitMQ to apply the configuration:

sudo service rabbitmq-server restart

Next, try with a client program if you can access RabbitMQ. If problems occur (which is probable), see RabbitMQ logs. These reside in /var/log/rabbitmq.