Security: Users, Permissions, vhosts and TLS
Authentication and authorization, per-vhost permissions, connection encryption with TLS and mTLS, and safe secrets handling for Spring Boot clients.
Prerequisite:AMQP and the RabbitMQ ModelYou’ll need: A running broker and the Spring AMQP setup from earlier modules.
The default broker ships with a guest user that only works over localhost, which is fine for learning and dangerous in production. This module covers the four layers that make a broker safe: who can connect, what they can touch, whether the wire is encrypted, and how clients hold their secrets.
What you’ll be able to do after this module
- Create least-privilege users scoped to a vhost.
- Read and write RabbitMQ permission rules.
- Isolate environments and services with vhosts.
- Enable TLS and mutual TLS from a Spring Boot client.
- Keep credentials out of source control.
1. The authentication and authorization model
RabbitMQ checks two things on every operation: authentication (are you who you claim to be) and authorization (are you allowed to do this here). Authorization is always scoped to a vhost, a logical namespace that isolates exchanges, queues, and users.
flowchart LR
App["Spring Boot client"]
Auth["Authenticate<br/>(username / password or cert)"]
Vhost["Select vhost"]
Perm["Check permissions<br/>(configure / write / read)"]
Res["Exchanges & queues"]
App --> Auth --> Vhost --> Perm --> Res
A user is authenticated once per connection, then every channel operation is authorized against that user’s permissions in the chosen vhost.
2. Users and least privilege
Never let applications connect as guest or as an administrator. Create a dedicated user per service with only the tags it needs.
# Create a service account
rabbitmqctl add_user order-service 's3cr3t-from-vault'
# Tags control Management UI access, not queue permissions.
# monitoring = read-only metrics; leave app users with no tag.
rabbitmqctl set_user_tags order-service
# Delete the default guest user in production
rabbitmqctl delete_user guest
User tags (administrator, monitoring, management, policymaker) grant Management UI and HTTP API scope. Application accounts should have no tag, so they can move messages but cannot administer the broker.
3. Permissions: configure, write, read
Each permission is a regular expression matched against resource names (exchanges and queues) within a vhost. The three columns are:
| Permission | Grants the right to |
|---|---|
configure | Declare or delete exchanges and queues |
write | Publish to exchanges and bind queues |
read | Consume from queues and bind for reading |
Grant the narrowest pattern that works. The Order Service only needs to publish to its exchange and read nothing, while the Inventory Service reads its own queue.
# Order Service: declare + publish to orders.* only, no read
rabbitmqctl set_permissions -p /prod order-service \
'^orders\..*' '^orders\..*' '^$'
# Inventory Service: read its own queue, declare its DLQ
rabbitmqctl set_permissions -p /prod inventory-service \
'^inventory\..*' '^orders\..*' '^inventory\..*'
An empty pattern (^$) matches nothing and is the correct way to deny a whole category. Prefer explicit prefixes (^orders\.) over .*, which grants everything.
4. vhosts for isolation
A vhost is a self-contained broker namespace. Resources and permissions in one vhost are invisible to another, so a user granted access to /staging cannot see /prod.
flowchart TD
Broker["RabbitMQ broker"]
subgraph prod ["/prod vhost"]
PE["orders.topic"] --> PQ["inventory.queue"]
end
subgraph staging ["/staging vhost"]
SE["orders.topic"] --> SQ["inventory.queue"]
end
Broker --> prod
Broker --> staging
rabbitmqctl add_vhost /prod
rabbitmqctl add_vhost /staging
Use vhosts to separate environments on a shared broker, or to isolate tenants and teams. The same exchange and queue names can safely coexist across vhosts. Spring selects one with spring.rabbitmq.virtual-host.
5. Encrypting the connection with TLS
By default, credentials and message bodies travel in plaintext on port 5672. In production, enable TLS on port 5671 so traffic is encrypted and clients can verify the broker’s identity.
sequenceDiagram
participant C as Spring client
participant B as RabbitMQ (5671)
C->>B: TLS ClientHello
B->>C: Server certificate
C->>C: Verify cert against trusted CA
C->>B: Encrypted AMQP over TLS
Note over C,B: Credentials never sent in plaintext
On the client, point Spring at the TLS port and enable SSL. Verifying the host and full certificate chain is what actually protects you against man-in-the-middle attacks.
spring:
rabbitmq:
host: rabbit.internal
port: 5671
username: order-service
ssl:
enabled: true
algorithm: TLSv1.2
validate-server-certificate: true
verify-hostname: true
trust-store: file:/etc/rabbit/truststore.p12
trust-store-password: ${TRUSTSTORE_PASSWORD}
Caution: Disabling
validate-server-certificateorverify-hostnamemakes TLS encrypt the pipe while leaving you open to impersonation. Keep both on in every environment.
6. Mutual TLS (mTLS)
With plain TLS the client verifies the broker. With mutual TLS the broker also verifies the client by requiring a client certificate, replacing or reinforcing password auth. The client presents a key store; the broker checks it against its trusted CA and maps the certificate to a user.
spring:
rabbitmq:
port: 5671
ssl:
enabled: true
key-store: file:/etc/rabbit/order-service.p12
key-store-password: ${KEYSTORE_PASSWORD}
trust-store: file:/etc/rabbit/truststore.p12
trust-store-password: ${TRUSTSTORE_PASSWORD}
verify-hostname: true
On the broker, the rabbitmq_auth_mechanism_ssl plugin lets a verified certificate’s Common Name become the username, so no password is stored at all. mTLS suits service-to-service traffic where you can manage a certificate lifecycle.
7. Handling secrets safely
Credentials and key-store passwords must never live in application.yml in source control. Inject them at runtime instead.
- Environment variables or a secrets manager: Vault, AWS Secrets Manager, or Kubernetes Secrets deliver values as env vars that Spring resolves with
${...}. - Rotate on a schedule. Rotation is a routine event, so make it non-disruptive. See the operations view in Auth Failures After Rotation.
- Scope tightly. A leaked least-privilege credential can only touch its own vhost and resources, which limits the blast radius.
Checkpoint
You should now be able to:
- Create a least-privilege service user with no admin tags.
- Write configure/write/read permission patterns for a service.
- Use vhosts to isolate environments or tenants.
- Configure TLS with server verification from Spring.
- Explain when mutual TLS is worth the operational cost.
- Keep credentials out of source control.