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:
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.
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.
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.
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.
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.
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.
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
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).
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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With