The service receives a dedicated RabbitMQ user from Stronghold with permissions only on its own virtual host and on resources with a given name prefix. Stronghold creates the user through the RabbitMQ management HTTP API and deletes it on revocation or when the lease expires.
Goal
Configure issuing dynamic RabbitMQ credentials to the orders service: on the orders virtual host, the user gets configure, write, and read permissions only on queues and exchanges whose names start with orders., and lives for 1 hour with renewal up to 24 hours.
Prerequisites
To follow this example, you need:
- Stronghold and a token with permissions to configure secrets engines and policies.
- RabbitMQ with the
rabbitmq_managementplugin enabled; the management HTTP API is reachable from Stronghold. - An existing
ordersvirtual host, created for example withrabbitmqctl add_vhost orders. - Access to
rabbitmqctlfor verification: withd8 k execin a broker pod or on a RabbitMQ node.
Step 1. Prepare an account for Stronghold
Create a dedicated RabbitMQ user with the administrator tag. Stronghold uses it to create and delete users:
rabbitmqctl add_user stronghold-admin '<STRONGHOLD_ADMIN_PASSWORD>'
rabbitmqctl set_user_tags stronghold-admin administrator<STRONGHOLD_ADMIN_PASSWORD> is the password of the stronghold-admin user.
Do not use this account for anything else.
Step 2. Configure the secrets engine
Enable the RabbitMQ secrets engine and connect it to the management HTTP API:
Enable the RabbitMQ secrets engine:
d8 stronghold secrets enable rabbitmqConfigure the connection to the management HTTP API:
d8 stronghold write rabbitmq/config/connection connection_uri="https://rabbitmq.example.com:15672" username="stronghold-admin" password="<STRONGHOLD_ADMIN_PASSWORD>"Set the lease parameters in seconds. They apply to all roles of this secrets engine:
d8 stronghold write rabbitmq/config/lease ttl=3600 max_ttl=86400To use different lease durations for different services, mount separate instances of the secrets engine with the
-pathargument.
Step 3. Create a role
Create a role that grants permissions on the orders virtual host:
d8 stronghold write rabbitmq/roles/orders vhosts='{"orders":{"configure":"^orders\\..*","write":"^orders\\..*","read":"^orders\\..*"}}'vhosts: a JSON map of virtual hosts and permissions. Theconfigure,write, andreadvalues are RabbitMQ regular expressions for queue and exchange names.tagsis not set, so the user has no access to the management web UI and HTTP API.
If the service publishes to a topic exchange, restrict the allowed routing keys with vhost_topics:
d8 stronghold write rabbitmq/roles/orders vhosts='{"orders":{"configure":"^orders\\..*","write":"^orders\\..*","read":"^orders\\..*"}}' vhost_topics='{"orders":{"orders.events":{"write":"^order\\.(created|paid)$","read":".*"}}}'Step 4. Create a policy
Create a policy that allows reading credentials of the orders role:
d8 stronghold policy write orders-rabbitmq - <<'POLICY'
path "rabbitmq/creds/orders" {
capabilities = ["read"]
}
POLICYAssign the policy to the auth method role the service logs in with, for example a Kubernetes auth role as in Dynamic PostgreSQL credentials. Renewing and revoking your own leases is allowed by the built-in default policy.
Step 5. Get credentials
Request credentials of the orders role and manage their lease:
Request credentials:
d8 stronghold read rabbitmq/creds/ordersExample output:
Key Value --- ----- lease_id rabbitmq/creds/orders/I39Hu8XXOombof4wiK5bKMn9 lease_duration 1h lease_renewable true password 3yNDBikgQvrkx2VA2zhq5IdSM7IWk1RyMYJr username token-39669250-3894-8032-c420-3d58483ebfc4Renew the lease before
lease_durationexpires:d8 stronghold lease renew rabbitmq/creds/orders/I39Hu8XXOombof4wiK5bKMn9When the credentials are no longer needed, revoke the lease. Stronghold deletes the user in RabbitMQ:
d8 stronghold lease revoke rabbitmq/creds/orders/I39Hu8XXOombof4wiK5bKMn9
Step 6. Deliver credentials to the service
Stronghold Agent renews the lease and re-renders the file when it receives new credentials. Example template that builds an AMQP connection URI:
{{ with secret "rabbitmq/creds/orders" }}
AMQP_URL=amqps://{{ .Data.username }}:{{ .Data.password }}@rabbitmq.example.com:5671/orders
{{ end }}The Agent sidecar configuration is in Delivering secrets to Kubernetes pods. When max_ttl is reached, the service receives a new user and the old one is deleted, so the service must reconnect to the broker with the new credentials.
Verification
Check the result:
Request credentials and store the username and password:
creds="$(d8 stronghold read -format=json rabbitmq/creds/orders)" MQ_USER="$(echo "$creds" | jq -r '.data.username')" MQ_PASSWORD="$(echo "$creds" | jq -r '.data.password')" LEASE_ID="$(echo "$creds" | jq -r '.lease_id')"Check that the user exists and can authenticate. The commands run
rabbitmqctlin therabbitmq-0broker pod from your workstation, so theMQ_USERandMQ_PASSWORDvariables of the current shell are passed torabbitmqctl:d8 k -n rabbitmq exec rabbitmq-0 -- rabbitmqctl list_users d8 k -n rabbitmq exec rabbitmq-0 -- rabbitmqctl authenticate_user "$MQ_USER" "$MQ_PASSWORD"Check the user’s virtual host permissions:
d8 k -n rabbitmq exec rabbitmq-0 -- rabbitmqctl list_user_permissions "$MQ_USER"The output must contain only the
ordersvirtual host with the^orders\..*regular expressions.Revoke the lease and make sure the user is deleted:
d8 stronghold lease revoke "$LEASE_ID" d8 k -n rabbitmq exec rabbitmq-0 -- rabbitmqctl list_users
The commands assume that RabbitMQ runs in a DP cluster in the rabbitmq namespace. If RabbitMQ runs outside Kubernetes, run rabbitmqctl with the same arguments on a RabbitMQ node, and set the MQ_USER and MQ_PASSWORD variables on that node to the values from the first step.
Cleanup
Delete the objects created in this example:
Revoke all credentials issued for the role:
d8 stronghold lease revoke -prefix rabbitmq/creds/orders/Delete the role and the policy, and disable the secrets engine if needed:
d8 stronghold delete rabbitmq/roles/orders d8 stronghold policy delete orders-rabbitmq d8 stronghold secrets disable rabbitmqDelete the Stronghold account in RabbitMQ:
rabbitmqctl delete_user stronghold-admin.