Scope RabbitMQ virtual hosts and permissions
# A vhost per application, and a user scoped to itrabbitmqctl add_vhost ordersrabbitmqctl add_user orders_app "$(openssl rand -base64 24)"
# configure / write / read — each a regex of resource namesrabbitmqctl set_permissions -p orders orders_app '^orders\.' '^orders\.' '^orders\.'Why it matters
Section titled “Why it matters”By default the replacement for guest is often a single user with .* .* .*
on the default vhost / — full control of everything. That’s guest with a
different name.
A leaked or compromised broker credential with full permissions can read every message on every queue, delete queues, reconfigure exchanges to redirect messages, and set up its own bindings to siphon traffic. Message brokers sit between your services, so control of the broker is control of the data flowing between them.
Scoping cuts that down. A credential limited to one virtual host and one set of resource names can touch only its own application’s messaging — a leak is bounded to that one app, not the whole estate.
Virtual hosts are the isolation boundary
Section titled “Virtual hosts are the isolation boundary”A virtual host is a fully separate namespace: its own exchanges, queues,
bindings and permissions. A user granted access to vhost orders cannot see
anything in vhost billing — not the queues, not the messages, not that it
exists.
That makes vhosts the right separation for multi-application or multi-tenant brokers. One vhost per application, each app’s user granted access only to its own:
rabbitmqctl add_vhost ordersrabbitmqctl add_vhost billingrabbitmqctl set_permissions -p orders orders_app '.*' '.*' '.*'# billing_app has no permissions on orders at allRunning everything in the default / vhost means every credential shares one
namespace, and permission regexes are the only separation — which works, but is
more error-prone than a hard vhost boundary.
The three permissions are not read/write/admin
Section titled “The three permissions are not read/write/admin”This is the part people get wrong, because the names don’t mean what they look like. RabbitMQ permissions are three regular expressions, matched against resource names (queues and exchanges):
| Permission | Grants the right to… | On resources matching |
|---|---|---|
| configure | create and delete queues/exchanges, set policies | the configure regex |
| write | publish to an exchange, bind a queue | the write regex |
| read | consume from a queue, get messages | the read regex |
So set_permissions -p / app '.*' '.*' '.*' grants configure, write and read on
everything — the .* is a name pattern, not an access level. To let an app
publish and consume its own queues but not create or delete anything:
rabbitmqctl set_permissions -p orders orders_app '^$' '^orders\.' '^orders\.''^$' for configure matches nothing — the app cannot create or delete queues,
which is usually correct: queues are created at deploy time by a privileged
account, and the runtime app only publishes and consumes. That separation is the
RabbitMQ equivalent of splitting DDL from runtime in
Postgres.
User tags are separate from permissions
Section titled “User tags are separate from permissions”Tags control management access, not messaging:
| Tag | Grants |
|---|---|
administrator |
full management, all vhosts, user management |
monitoring |
read-only management across all vhosts |
management |
management UI for own vhosts only |
| (none) | AMQP only — no management UI at all |
An application user should have no tag — it needs to publish and consume, not
log into the management UI. Giving an app the
administrator tag so it “just works” hands it the whole broker’s management
surface on top of its messaging.
Related
Section titled “Related”- Replace the guest user — the users these permissions apply to.
- Secure the management UI — where tags take effect.