Read time: ~

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:

PermissionGrants the right to
configureDeclare or delete exchanges and queues
writePublish to exchanges and bind queues
readConsume 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-certificate or verify-hostname makes 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.