Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can queues be made private/secure in RabbitMQ in a multitenancy system?

I have read the Get Started guide provided by RabbitMQ and have even contributed the sixth example to stormed-amqp, so I have an inkling of knowledge about AMQP.

However, the guide is not comprehensive and avoids things like authentication and authorization.

We're designing a multitenancy system that will use RabbitMQ in an RPC-type of situation. What is perhaps different about this implementation of RPC is that the remote procedures will actually be other tenant programs on the system.

Basically, I want to isolate the data buses, which includes the following assertions:

  1. Our server will not deliver data to the wrong tenant program (this is handled easily and is relevant but not questioned).
  2. Tenant programs are not be able to read data from queues that aren't theirs.
  3. Tenant programs are not be able to write to queues that aren't theirs.

This question is strictly about RabbitMQ security. I know that RabbitMQ supports SSL, which provides end-to-end encryption, and I know RabbitMQ supports username/password authentication. I don't know if these things apply to privatizing queue usage (aka ACL), i.e. the connection may be encrypted, and the user may be verified, but the user can read to / write from all the queues.

Can anybody enlighten me on this more advanced topic? I'm confident that RabbitMQ can support this sort of system but not exactly positive. I know there are things in RabbitMQ that I just don't know about, e.g. what are vhosts and will they help in this situation? I just don't see the solution in my current knowledge limited to routing keys, queue names and exchanges.

like image 368
Brian Avatar asked Oct 20 '11 18:10

Brian


People also ask

How do you create a durable queue in RabbitMQ?

Declared your queue as durable Create a durable queue by specifying durable as true during creation of your queue. You can check in the RabbitMQ Management UI, in the queue tab that the queue is marked with a "D" to ensure that the queue is durable.

How does RabbitMQ queue work?

The user sends a PDF creation request to the web application. The web application (the producer) sends a message to RabbitMQ that includes data from the request such as name and email. An exchange accepts the messages from the producer and routes them to correct message queues for PDF creation.

What is exclusive queue in RabbitMQ?

An exclusive queue can only be used (consumed from, purged, deleted, etc) by its declaring connection. An attempt to use an exclusive queue from a different connection will result in a channel-level exception RESOURCE_LOCKED with an error message that says cannot obtain exclusive access to locked queue.

How many queues can be created in RabbitMQ?

Thousands (or even tens of thousands) of queues should be no problem at all, though each object (e.g., queues, exchanges, bindings, etc) will take up some memory and/or disk space. By default, Erlang will enforce a maximum number of concurrent processes (i.e., lightweight threads) at around 32768 IIRC.


1 Answers

TLDR: The relevant information can be found here: https://www.rabbitmq.com/access-control.html. However, since the rabbitmq documentation is very verbose, below I will describe what seems like the only solution to locking down access to resources.

Summary

Virtual hosts

As Michael Dillon mentions, you should start by making everything happen inside vhosts (virtual hosts) and block the generic vhost entirely. The generic vhost is simply called / and is by default the only vhost when you start a rabbitmq server.

A given resource (i.e. queue or exchange) must live in one vhost and one vhost only. A rabbitmq connection must also specifically connect to a single vhost (this can just be specified by appending the vhost name to the rabbitmq URL e.g. amqp://username:password@myserver:5672/vhost). Therefore a rabbitmq connection can only access queues and exchanges that live in the vhost it has connected to.

Simply create as many vhosts as there are logical groupings in your application. Remember that resources in one vhost are not aware of and cannot communicate with resources in another vhost. Create a vhost by doing:

rabbitmqctl add_vhost vhost-name 

Users

The next step is to create users and remove the default guest user. Each user should have their own username and password which should be used only by them. Needless to say, only the actual administrator should have administrator privileges. This allows them to manage other users, vhosts and their permissions. Create a user by doing:

rabbitmqctl add_user "username" 

Users can use their credentials to create a rabbitmq connection and thereby connect to a vhost. However, the connection is only approved if this is a vhost the user has access to. Only an adminstrator can grant and modify a user's access permissions to a vhost. A user can be granted access to multiple vhosts and use their credentials to connect to multiple vhosts simultaneously (but not different vhosts within the same connection).

User permissions

However, a user's access to a vhost is not simply binary.

RabbitMQ distinguishes between configure, write and read operations on a resource. The configure operations create or destroy resources, or alter their behaviour. The write operations inject messages into a resource. And the read operations retrieve messages from a resource.

There is a nice table in the linked section of the docs which denotes what command counts as what kind of operation e.g. queue.bind is a write operation whereas queue.get is a read operation. However the complexity doesn't end there, permissions are actually granted to each operation type based on a custom regular expression (regex) of the administrator's choosing.

For instance the regex '.*' '.*' '.*' allows the user to configure, write and read respectively on any resource in that vhost. This would be granted like so:

rabbitmqctl set_permissions -p "vhost-name" "username" ".*" ".*" ".*" 

Whereas the regex '^$' '^(hello).*$' '^(hello|world).*$' would not give the user any configuration permissions but would allow them to write to any resource whose name began with hello and read from any resource whose name began with either hello or world.

Takeaways

Use vhosts liberally to group resources together and set permissions on these resources as a whole.

Naming of resources is very important as this is the only way to configure access to that resource within a given vhost.

In the case of the OP's question, each user should be permissioned to only read and write to their own queue based on the queue's unique name. This does not necessarily need to be across multiple vhosts but can be if it makes sense for it to be.

like image 144
amin_nejad Avatar answered Oct 11 '22 22:10

amin_nejad