I am trying to understand permissions on RabbitMQ; therefore, I am reading this article:
https://www.rabbitmq.com/access-control.html#authorisation
I first created my user as
rabbitmqctl add_user MyUser MyPassword
Then I give that user permisions as
rabbitmqctl set_permissions -p / MyUser ".*" ".*" ".*"
That works great that user is able to do everything. Now I want to restrict permissions.
What I am trying to build (you may skip this part):
I need to build an application where it can publish messages to multiple subscribers. For this I am using RabbitMQ and it works great. In other words lets say I have computers A,B,C and D. I need that when server A publishes a message for B,C and D to receive it. The way I achieve that is by creating one producer that publishes via the FanoutExchange. Then each subscriber (Consumer) creates a queue and binds that to the FanoutExchange. After doing that every time computer A publish a message each subscriber gets the same message. That works great but now I want to prevent computers B,C and D from being able to publish messages
How can I create a user that will only be able to queue.declare
, queue.bind
, queue.unbind
and basic.consume
?
This is what I have tried:
# this does not work because MyUser is able to publish messages to a queue
rabbitmqctl set_permissions -p / MyUser "(queue*)" ".*" ".*"
# this does not work. MyUser is not able to bind or declare the queue
rabbitmqctl set_permissions -p / MyUser "(queue.bind*|queue.declare*)" ".*" ".*"
# error message I get when trying to bind the queue on my code is:
# operation queue.declare caused a channel exception access_refused: access to queue 'test-fanout-queue-a' in vhost '/' refused for user 'MyUser'
# tried giving the user readonly permissions but that does not work because a queue has to be created
rabbitmqctl set_permissions -p / MyUser ".*" "^$" ".*"
Can someone help me on creating the correct permissions using the command line? Or can someone help me find a nice tutorial. The documentation is hard to understand and does not provider helpful examples.
Finally found a solution. If someone has a better one please post it since I do not like this solution lol.
In this example user_a has permissions to do everything. And user_b, user_c etc will only have readonly permissions.
Create the user that will publish messages and has permission to everything (user_a)
# this is bash script
rabbitmqctl add_user user_a password_a
# give it permissions to do everything
rabbitmqctl set_permissions -p / user_a ".*" ".*" ".*"
Have that user (user_a) create the queues and bindings in advance because other user will not have permissions to do so. (You can probably create this exchange and queues via the command line but this is how I did it)
// This is created in dotnet c#. Hopefully you can get the idea
string exchangeName = "my-exchange";
var factory = new ConnectionFactory()
{
HostName = "localhost",
UserName = "user_a",
Password = "password_a"
};
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();
// create the exchange that will persist.
channel.ExchangeDeclare(exchangeName, ExchangeType.Fanout, durable: true, autoDelete: false);
// create 4 queues with this settings because user_b will not have access to create these
channel.QueueDeclare("queue-1", durable: true, exclusive: false, autoDelete: false);
channel.QueueDeclare("queue-2", durable: true, exclusive: false, autoDelete: false);
channel.QueueDeclare("queue-3", durable: true, exclusive: false, autoDelete: false);
channel.QueueDeclare("queue-4", durable: true, exclusive: false, autoDelete: false);
// bind this 4 queues to that exchange (maybe this is not needed)
channel.QueueBind("queue-1", exchangeName, string.Empty);
channel.QueueBind("queue-2", exchangeName, string.Empty);
channel.QueueBind("queue-3", exchangeName, string.Empty);
channel.QueueBind("queue-4", exchangeName, string.Empty);
Create user that will only be able to read from these queues (user_b).
# this is bash script
# create user
rabbitmqctl add_user user_b password_b
# set its permissions
rabbitmqctl set_permissions -p / c "queue.*" "(queue.*)" "(my-exchange.*|queue.*)"
Now here is the c# code of the user (user_a) that publishes the messages:
string exchangeName = "my-exchange";
var factory = new ConnectionFactory()
{
HostName = "localhost",
UserName = "user_a",
Password = "password_a"
};
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();
// publish one thousand messages
for (int i = 1; i < 1000; i++)
{
var message = new { Name = "Producer", Message = $"Hello Fanout {i}" };
var json = System.Text.Json.JsonSerializer.Serialize(message);
var bodyBinary = Encoding.UTF8.GetBytes(json);
channel.BasicPublish(exchangeName, string.Empty, null, bodyBinary);
Thread.Sleep(1000);
}
Here is the code of the consumer (user_b) that receives those messages
string exchangeName = "my-exchange";
string queueName = "queue-1";
var factory = new ConnectionFactory()
{
// connection string if using an uri
// amqp://lh:guiest@localhost:5672
HostName = "localhost",
UserName = "user_b",
Password = "password_b"
// TODO in the future use SSL because connection is remote
// Port = 5671,
//Ssl = new SslOption() { ... }
};
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();
// bind to queue
channel.QueueBind(queueName, exchangeName, string.Empty);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (sender, args) =>
{
var body = args.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
Console.WriteLine(message);
};