New to KubeVault? Please start here.

Manage RabbitMQ credentials using the KubeVault operator

OpenBao’s rabbitmq-database-plugin is a dynamic-credentials database plugin for RabbitMQ. The plugin provisions credentials via the RabbitMQ Management HTTP API (using rabbit-hole/v3). Each issued credential becomes a native RabbitMQ user whose tags, per-vhost permissions, and (optionally) per-topic permissions are taken from the creationStatements JSON role document. On lease revocation the plugin deletes the user with DELETE /api/users/<name>, which is naturally idempotent — so there is no revocation_statements field on the RabbitMQRole.

The same CRD shape is used both for the in-process rabbitmq-database-plugin and for the hub-spoke remote-rabbitmq-plugin; the difference is whether the Vault AppBinding referenced by SecretEngine.spec.vaultRef is marked deploymentMode: RemoteAgent (then the SecretEngine controller rewrites plugin_name to remote-rabbitmq-plugin and attaches spoke_name).

You need to be familiar with the following CRDs:

Before you begin

  • Install KubeVault operator in your cluster from here.
  • Run a RabbitMQ cluster with the management plugin enabled. The official rabbitmq:3-management Docker image exposes the HTTP API at 15672.
  • Have an administrator user on RabbitMQ (the default guest/guest works for localhost-only setups; create a real admin for production). The plugin authenticates against the management API as this user when issuing credential operations.
  • Decide which RabbitMQ tags and per-vhost permissions the dynamic users should receive (e.g. administrator, or per-vhost configure/write/read regex permissions).
$ kubectl create ns demo
namespace/demo created

Vault Server

Deploy a Vault Server using the KubeVault operator: Deploy Vault Server. The KubeVault operator will create an AppBinding wiring up Kubernetes auth.

$ kubectl get appbinding -n demo vault -o yaml

AppBinding for RabbitMQ

Create an AppBinding pointing at the RabbitMQ management HTTP API base URL (e.g. http://rabbitmq.demo.svc:15672). Unlike most database engines, the URL here is not an AMQP URI — it is the management plugin’s HTTP base URL, which rabbit-hole/v3 uses to call the REST endpoints. The referenced Secret carries HTTP Basic Auth credentials (username + password) used by the plugin to authenticate against the management API. If the management API is served over TLS with a certificate signed by a private CA, set spec.clientConfig.caBundle to the PEM-encoded CA certificate — the operator forwards it to the plugin as tls_ca for server-certificate verification.

apiVersion: appcatalog.appscode.com/v1alpha1
kind: AppBinding
metadata:
  name: rabbitmq
  namespace: demo
spec:
  clientConfig:
    url: http://rabbitmq.demo.svc:15672
  secret:
    kind: Secret
    name: rabbitmq-cred
---
apiVersion: v1
kind: Secret
metadata:
  name: rabbitmq-cred
  namespace: demo
type: kubernetes.io/basic-auth
stringData:
  username: admin
  password: admin-password

If your RabbitMQ management endpoint uses a self-signed TLS certificate (https://...:15671), either set the AppBinding’s spec.clientConfig.caBundle to the CA that signed it (preferred — verifies the certificate), or set SecretEngine.spec.rabbitmq.insecure: true below to skip verification entirely. Drop insecure once you front the management API with a CA-issued (or CA-bundle-verified) certificate. If the management API requires mutual TLS, set SecretEngine.spec.rabbitmq.clientCert/clientKey to a PEM-encoded client certificate and private key.

Enable and Configure RabbitMQ Secret Engine

When a SecretEngine crd object is created, the KubeVault operator will enable a secret engine on a specified path and configure the secret engine with the given configuration.

A sample SecretEngine for RabbitMQ:

apiVersion: engine.kubevault.com/v1alpha1
kind: SecretEngine
metadata:
  name: rabbitmq-engine
  namespace: demo
spec:
  vaultRef:
    name: vault
  rabbitmq:
    databaseRef:
      name: rabbitmq
      namespace: demo
    pluginName: rabbitmq-database-plugin   # optional; this is the default
    allowedRoles:
      - "*"
    # passwordPolicy: my-policy            # optional; name of a Vault password policy
    # clientCert: |                        # optional; PEM-encoded client cert for mutual TLS
    #   -----BEGIN CERTIFICATE-----
    #   ...
    #   -----END CERTIFICATE-----
    # clientKey: |                         # optional; PEM-encoded private key for clientCert
    #   -----BEGIN PRIVATE KEY-----
    #   ...
    #   -----END PRIVATE KEY-----
    insecure: false                        # set true only for self-signed dev clusters

Apply it and wait for STATUS=Success:

$ kubectl apply -f rabbitmq-engine.yaml
secretengine.engine.kubevault.com/rabbitmq-engine created

$ kubectl get secretengines -n demo
NAME              STATUS    AGE
rabbitmq-engine   Success   10s

Use kubectl describe secretengine -n demo rabbitmq-engine to inspect error events, if any.

Create a RabbitMQRole

A RabbitMQRole describes how the plugin should mint a dynamic credential. creationStatements is a single-element string slice holding a JSON role document with any combination of tags, vhosts, and vhost_topics. At least one of tags or vhosts must be set. The vhosts map keys are RabbitMQ vhost names (/ is the default vhost) and each value is the standard RabbitMQ permission triple (configure / write / read regular expressions). See Access Control for the full RabbitMQ authorization model.

apiVersion: engine.kubevault.com/v1alpha1
kind: RabbitMQRole
metadata:
  name: rabbitmq-admin
  namespace: demo
spec:
  secretEngineRef:
    name: rabbitmq-engine
  creationStatements:
    - '{"tags":"administrator","vhosts":{"/":{"configure":".*","write":".*","read":".*"}}}'
  defaultTTL: 1h
  maxTTL: 24h

A more scoped example that grants only publish/consume on a single vhost (no broker administration):

spec:
  creationStatements:
    - '{"vhosts":{"/app":{"configure":"^$","write":"^events\\.","read":"^events\\."}}}'

Apply and verify:

$ kubectl apply -f rabbitmq-role.yaml
rabbitmqrole.engine.kubevault.com/rabbitmq-admin created

$ kubectl get rabbitmqrole -n demo
NAME             STATUS    AGE
rabbitmq-admin   Success   12s

The role name in Vault follows the format k8s.{clusterName}.{metadata.namespace}.{metadata.name}, so you can verify directly with the Vault CLI:

$ vault read your-database-path/roles/k8s.-.demo.rabbitmq-admin
Key                      Value
---                      -----
creation_statements      [{"tags":"administrator","vhosts":{"/":{"configure":".*","write":".*","read":".*"}}}]
db_name                  k8s.-.demo.rabbitmq
default_ttl              1h
max_ttl                  24h

Deleting the RabbitMQRole removes the role from Vault.

Issue RabbitMQ credentials

Request a dynamic credential by creating a SecretAccessRequest:

apiVersion: engine.kubevault.com/v1alpha1
kind: SecretAccessRequest
metadata:
  name: rabbitmq-cred-rqst
  namespace: demo
spec:
  roleRef:
    kind: RabbitMQRole
    name: rabbitmq-admin
  subjects:
    - kind: ServiceAccount
      name: demo-sa
      namespace: demo

Approve it through the KubeVault CLI:

$ kubectl vault approve secretaccessrequest rabbitmq-cred-rqst -n demo
approved

Once approved, the operator issues the credential, stores it in a Secret, and binds the listed subjects via a Role/RoleBinding. Internally the plugin calls PUT /api/users/<name> to create the user with the generated password, then PUT /api/users/<name>/... to apply tags and per-vhost permissions exactly as listed in the creationStatements JSON. The credential lives on the lease until you delete the SecretAccessRequest or it expires; on lease revocation the plugin calls DELETE /api/users/<name> (idempotent — so revocation works even if the user has already been removed out-of-band, and no revocation_statements are required on the RabbitMQRole).

$ kubectl get secretaccessrequest rabbitmq-cred-rqst -n demo -o json | jq '.status'
{
  "lease": {
    "duration": "1h0m0s",
    "id": "your-database-path/creds/k8s.-.demo.rabbitmq-admin/abc...",
    "renewable": true
  },
  "secret": {
    "name": "rabbitmq-cred-rqst-xxxxxx"
  }
}

$ kubectl get secret -n demo rabbitmq-cred-rqst-xxxxxx -o jsonpath='{.data.username}' | base64 -d
v-kubernetes-demo-XXXXXXXX

$ kubectl get secret -n demo rabbitmq-cred-rqst-xxxxxx -o jsonpath='{.data.password}' | base64 -d
xxxxxxxxxxxxxxxxxx

Use the issued username / password to open an AMQP connection against your RabbitMQ cluster (or hit the management API). The credential is revoked when the SecretAccessRequest is deleted.

Further reading