Rotate the RabbitMQ Password, Erlang Cookie and User in Xray (Self-Hosted)
Rotate RabbitMQ credentials and replace the default user in self-hosted JFrog Xray.
Use this procedure to replace the default RabbitMQ credentials of a self-hosted JFrog Xray installation with your own values:
- RabbitMQ password: the password Xray uses to connect to RabbitMQ.
- Erlang cookie: the shared secret that RabbitMQ nodes and the
rabbitmqctlCLI use to talk to each other. - RabbitMQ user: Xray connects as
guestby default. You replace it with a dedicated user and deleteguest.
By default, these are well-known installer values, and guest can log in from other hosts, so anyone who can reach RabbitMQ's ports can try them. Each platform tab lists its defaults.
Applies to: Xray self-hosted with the RabbitMQ that Xray installs:
- Linux: RPM, Debian and archive (tar.gz), single node, multi-node, and split mode (dedicated RabbitMQ nodes installed with the RabbitMQ RPM/Debian package).
- Docker Compose: single node, multi-node, and split mode.
- Helm: the Xray chart and the JFrog Platform chart.
Not covered:
- An external RabbitMQ broker that you manage yourself. Rotate the credentials on that broker, then update
shared.rabbitMq.*in Xray'ssystem.yaml. - Changing which network interfaces or ports RabbitMQ listens on. See Network Access to RabbitMQ Ports for how to restrict access.
Expected downtime:
| Change | Linux and Docker Compose | Helm |
|---|---|---|
| Password | Short. On a multi-node installation, Xray on a node that has not been restarted yet cannot open new RabbitMQ connections until its restart. | One downtime window for all three changes: Xray and RabbitMQ are scaled to 0, the RabbitMQ secret is changed, RabbitMQ is started, and one helm upgrade switches Xray to the new user. |
| Erlang cookie | RabbitMQ and Xray are stopped on all nodes at the same time. | (same window) |
| User | Short restarts. | (same window) |
All paths, users and values on this page are examples
They show a default installation. Before you run a command, check the value on your own system and change the command where needed.
How this page is organized: Choose your platform tab under Rotate the Credentials: Linux, Docker Compose or Helm. Each tab is complete on its own, from preparation to clean-up, with its own troubleshooting and rollback; follow it from top to bottom. On Linux and Docker Compose you make the three changes in this order, and verify each one before the next: password → cookie → user. On Helm, one helm upgrade makes all three changes in one downtime window.
Why the guest User Must Be Deleted
- By default, Xray connects to RabbitMQ as
guest, a well-known user name. - RabbitMQ normally lets
guestlog in only from localhost. Xray'srabbitmq.confturns that off withloopback_users.guest = false, so anyone who can reach port 5672 or 15672 can try to log in asguest. - Xray's start-up script sets the password of
gueston every RabbitMQ start. After you switch Xray to a dedicated user, a remainingguestuser would get the same password as that user. That is whyguestmust be deleted, not only restricted. - RabbitMQ's own access-control guidance recommends creating a user with generated credentials and deleting
guest. - The order matters: create the new user → point Xray at it → restart Xray and verify → restrict
guest→ deleteguest→ verify. If you restrict or deleteguestwhile Xray still uses it, Xray is locked out: on Docker Compose, Helm, multi-node and split-mode installations, Xray connects over the network, so RabbitMQ treats it as a remote client and refusesguestwithuser 'guest' can only connect via localhost.
When you finish: Xray uses a dedicated user (xray_admin in the examples), guest does not exist, and loopback_users.guest is no longer false.
Rotate the Credentials
Choose your platform.
Step 0 — Prepare (Linux)
Rules
- One cookie and one password per cluster. Generate them once and copy the same values to every node. RabbitMQ shares users and passwords across the whole cluster, so you run
rabbitmqctl change_passwordandadd_useronce, on any node. - Change every copy. The password is stored in
system.yamland in everyrabbitmq.confon the node. Every time RabbitMQ starts, Xray's start-up script sets the password ofdefault_usertodefault_passfromrabbitmq.conf. Because the password is shared across the cluster, one node with an olddefault_passresets the password for the whole cluster the next time it starts. - Do not paste the new values into tickets, chat or source control.
- Make the password, cookie and user changes as separate steps, and verify each one before the next. Deleting
guestis part of the procedure, not optional. - Stop and restart RabbitMQ only through its service, with
shared.rabbitMq.autoStop: true. Without this setting,systemctl stop xrayandsystemctl restart xrayon a node that runs both Xray and RabbitMQ stop or restart only Xray, and RabbitMQ keeps running. The cookie change then fails. Step 0.1 sets it. The RabbitMQ package for split mode (xray-rabbitmq.service) sets it by default.
0.1 Set autoStop. On every node that runs RabbitMQ, add this to system.yaml (for example /opt/jfrog/xray/var/etc/system.yaml):
shared:
rabbitMq:
autoStop: trueWithout it, systemctl stop xray and systemctl restart xray stop or restart only Xray, and RabbitMQ keeps running. RPM, Debian and archive installations where Xray and RabbitMQ run on the same node do not set it by default. On split-mode RabbitMQ nodes, the RabbitMQ package sets it; check that it is there.
Check:
sudo grep -n autoStop /opt/jfrog/xray/var/etc/system.yamlNo restart is needed now; the setting is used the next time the service is stopped or restarted.
0.2 Plan a maintenance window and announce it. Scans and other Xray processing stall during the change.
0.3 Generate the new values once, on a trusted host, with shell history turned off:
set +o history
RMQ_PASSWORD=$(openssl rand -hex 24)
RMQ_COOKIE=$(openssl rand -hex 32)Store both in your secret manager, and use the same two values on every node. The examples use the same $RMQ_PASSWORD for the new xray_admin user.
In the shell on each node, set the new values and the current values (the checks use them):
set +o history
RMQ_PASSWORD='<new password>'
RMQ_COOKIE='<new cookie>'
OLD_PASS='<current password>'
OLD_COOKIE='<current cookie>'The installer default for the password and the cookie is JFXR_RABBITMQ_COOKIE, and the default user is guest. Many installations set their own values during installation, so do not assume the default. Read the current password from default_pass in rabbitmq.conf, and the current cookie from the .erlang.cookie file.
Set the RabbitMQ folder. It is .../rabbitmq on RabbitMQ 3 and .../rabbitmq4 on RabbitMQ 4. Check it, then set it in the same shell:
grep JF_PRODUCT_RABBITMQ_HOME /opt/jfrog/xray/app/bin/xray.default
RMQ_HOME=/opt/jfrog/xray/app/third-party/rabbitmqUse the folder printed by the first command. The commands in this tab use $RMQ_HOME for the server cookie and for rabbitmqctl.
0.4 Record the current settings. The paths are listed in A.0.
- Current RabbitMQ user (
<user>in this tab). Default:guest. Checkshared.rabbitMq.usernameinsystem.yaml. - Active node (multi-node only): the node named in
shared.rabbitMq.active.node.nameinsystem.yaml. - Cluster nodes, users and vhosts:
rabbitmqctl cluster_status,rabbitmqctl list_users,rabbitmqctl list_vhosts.
0.5 Back up. Copy, do not move. The backups contain secrets; keep them readable by root only. On nodes that run RabbitMQ, back up system.yaml, both rabbitmq.conf files, both cookie files and the RabbitMQ data folder. For example:
sudo tar -czpf /var/tmp/xray-rmq-backup.tgz \
/opt/jfrog/xray/var/etc/system.yaml \
/opt/jfrog/xray/var/etc/rabbitmq.conf \
/opt/jfrog/xray/app/bin/rabbitmq/rabbitmq.conf \
/opt/jfrog/xray/.erlang.cookie \
$RMQ_HOME/.erlang.cookie \
/opt/jfrog/xray/var/data/rabbitmq
sudo chmod 600 /var/tmp/xray-rmq-backup.tgzLeave out /opt/jfrog/xray/var/etc/rabbitmq.conf if it does not exist. On split-mode Xray nodes, back up system.yaml.
0.6 Check that the system is healthy before you start, and again after each step:
-
Xray health, on a node that runs Xray. All services must show
"state" : "HEALTHY":curl -s http://localhost:8082/router/api/v1/system/health -
Xray is connected to RabbitMQ:
rabbitmqctl list_connections user -
The current password is correct (prints
Success):rabbitmqctl authenticate_user <user> "$OLD_PASS"
After a restart, the Xray services can take a few minutes to report HEALTHY again.
In this tab, rabbitmqctl <command> means sudo -u xray -i $RMQ_HOME/sbin/rabbitmqctl <command> (see A.0).
A.0 Paths and Users
RPM, Debian and archive installations use the same RabbitMQ scripts and the same folder layout under the installation folder. The RabbitMQ package for split mode installs only RabbitMQ, with the same layout and its own service. The commands in this tab use the default RPM/Debian paths; replace /opt/jfrog/xray with your installation folder.
| RPM / Debian | Split mode: RabbitMQ node | Archive (tar.gz) | How to check | |
|---|---|---|---|---|
| Service user | xray | xray | xray | ps -o user= -C beam.smp |
Installation folder (JF_PRODUCT_HOME) | /opt/jfrog/xray, also the service user's home folder | /opt/jfrog/xray | The extraction folder, for example /opt/jfrog/jfrog-xray-<version>-linux | getent passwd xray | cut -d: -f6 (home folder) |
CLI cookie (used by rabbitmqctl) | /opt/jfrog/xray/.erlang.cookie | same | <service user's home>/.erlang.cookie | — |
RabbitMQ folder (JF_PRODUCT_RABBITMQ_HOME) | /opt/jfrog/xray/app/third-party/rabbitmq (RabbitMQ 3) or .../rabbitmq4 (RabbitMQ 4) | same | same, under the extraction folder | grep JF_PRODUCT_RABBITMQ_HOME /opt/jfrog/xray/app/bin/xray.default |
| Server cookie (used by RabbitMQ) | <RabbitMQ folder>/.erlang.cookie ($RMQ_HOME/.erlang.cookie, set in Step 0.3) | same | same | — |
rabbitmq.conf (read by RabbitMQ) | /opt/jfrog/xray/app/bin/rabbitmq/rabbitmq.conf | same | same | Always present |
rabbitmq.conf (second copy) | /opt/jfrog/xray/var/etc/rabbitmq.conf | same | same | Exists on newer installations only |
system.yaml | /opt/jfrog/xray/var/etc/system.yaml | same | same | — |
| Service | xray | xray-rabbitmq | xray (without a service: app/bin/xrayManage.sh start|stop) | systemctl list-unit-files | grep xray |
autoStop | Not set by default; set it in 0.1 | true by default | Not set by default; set it in 0.1 | grep autoStop system.yaml |
In this tab, "the service" means xray on nodes that run Xray and RabbitMQ, and xray-rabbitmq on split-mode RabbitMQ nodes.
Split mode, Xray nodes. They run xray.service without RabbitMQ and connect to all RabbitMQ nodes through shared.rabbitMq.urls. Only system.yaml matters on these nodes. One user name and password are used for every URL in the list; this works because RabbitMQ users are shared across the cluster.
shared:
rabbitMq:
urls:
- amqp://<rabbitmq-node-1>:5672/
- amqp://<rabbitmq-node-2>:5672/
username: "xray_admin"
password: "<RMQ_PASSWORD>"system.yaml and encryption. On nodes that run Xray, Xray encrypts the password in system.yaml after it starts, so you will not see the new value in plain text afterwards. On split-mode RabbitMQ nodes, the value stays in plain text; make sure only the service user and root can read the file.
How to run rabbitmqctl. Run it as the service user, with a login shell (-i):
sudo -u xray -i $RMQ_HOME/sbin/rabbitmqctl cluster_statusrabbitmqctlreads the cookie from the service user's home folder. As root, or as any other user, it uses a different cookie and cannot connect.- Without
-i, it runs in your current folder. If the service user cannot read that folder, it fails withFile operation error: eacces.
In this tab, rabbitmqctl <command> means sudo -u xray -i $RMQ_HOME/sbin/rabbitmqctl <command>.
What happens on every start. The service starts RabbitMQ as the service user. The start-up script:
- creates a cookie file only if none exists, so the cookie files you write are kept;
- writes the entries of
shared.rabbitMq.node.rabbitmqConffromsystem.yamlintorabbitmq.conf; - sets the password of
default_usertodefault_passfromrabbitmq.conf.
A.1 Password
Where each part runs: system.yaml on every node (split mode: every Xray node and every RabbitMQ node); rabbitmq.conf on every node that runs RabbitMQ; change_password once per cluster.
A.1.1 On every node, edit system.yaml as the service user, so its owner does not change:
sudo -u xray vi /opt/jfrog/xray/var/etc/system.yamlSet the password under shared.rabbitMq:
shared:
rabbitMq:
password: "<RMQ_PASSWORD>"Change only the password: line inside the rabbitMq: block. shared.database also has a password: line, and on split-mode Xray nodes the rabbitMq: block also contains the urls: list; leave both unchanged. Check:
sudo grep -n -A6 'rabbitMq:' /opt/jfrog/xray/var/etc/system.yamlA.1.2 On every node that runs RabbitMQ, set default_pass to the new password in each rabbitmq.conf that exists:
/opt/jfrog/xray/app/bin/rabbitmq/rabbitmq.conf(always present; RabbitMQ reads this one)/opt/jfrog/xray/var/etc/rabbitmq.conf(newer installations only)
default_pass = <RMQ_PASSWORD>Edit the files as the service user, or run, for each file:
sudo -u xray sed -i "s|^default_pass *=.*|default_pass = $RMQ_PASSWORD|" /opt/jfrog/xray/app/bin/rabbitmq/rabbitmq.conf
sudo -u xray sed -i "s|^default_pass *=.*|default_pass = $RMQ_PASSWORD|" /opt/jfrog/xray/var/etc/rabbitmq.confCheck:
sudo grep -n '^default_' /opt/jfrog/xray/app/bin/rabbitmq/rabbitmq.conf /opt/jfrog/xray/var/etc/rabbitmq.confA.1.3 Change the password in RabbitMQ. Run once per cluster, on any RabbitMQ node:
rabbitmqctl change_password <user> "$RMQ_PASSWORD"
rabbitmqctl authenticate_user <user> "$RMQ_PASSWORD"Expect Success. Existing Xray connections keep working, but new connections fail until Xray restarts. Continue with A.1.4 straight away.
A.1.4 Restart the service, one node at a time, active node first:
sudo systemctl restart xray # split-mode RabbitMQ node: sudo systemctl restart xray-rabbitmqAfter each restart, check that the new password still works:
rabbitmqctl authenticate_user <user> "$RMQ_PASSWORD"If it fails, that node still has the old default_pass. Fix its rabbitmq.conf (A.1.2), then run A.1.3 again. Split mode: then restart xray on every Xray node, one at a time.
A.1.5 Verify
-
The new password works and the old one is rejected:
rabbitmqctl authenticate_user <user> "$RMQ_PASSWORD" rabbitmqctl authenticate_user <user> "$OLD_PASS"Expect
Successfor the first, an error for the second. -
The password survives a restart: restart the service once more and repeat the check above.
-
rabbitmqctl cluster_statuslists all nodes. The health check (0.6) showsHEALTHY, and Xray connections are back. -
There are no RabbitMQ authentication errors in the Xray logs. This prints nothing:
sudo grep -l ACCESS_REFUSED /opt/jfrog/xray/var/log/*.log -
A test scan completes.
If a check fails, see Troubleshooting (A.4), or go to Rollback (A.5).
A.2 Erlang Cookie
All nodes must be stopped at the same time. No node may run with the new cookie while another runs with the old one. In split mode, also stop the Xray nodes; they cannot work while RabbitMQ is down.
Start order in a cluster
- Stop the nodes one at a time and note which node stopped last.
- Start that node first, then start all other nodes right away.
A.2.1 Stop everything.
-
Split mode only: on every Xray node, run
sudo systemctl stop xray. -
On every node that runs RabbitMQ, one at a time, stop the service and note which node you stop last:
sudo systemctl stop xray # split-mode RabbitMQ node: sudo systemctl stop xray-rabbitmq -
Check that RabbitMQ is stopped. This must print
RabbitMQ stopped:pgrep -f beam.smp || echo "RabbitMQ stopped"If RabbitMQ is still running,
autoStopis not set on that node (0.1). Do not change the cookie while RabbitMQ is running.
A.2.2 On every node that runs RabbitMQ, write the new cookie to both cookie files. Each file must be owned by the service user, with mode 400.
CLI cookie (used by rabbitmqctl):
F=/opt/jfrog/xray/.erlang.cookie
sudo chmod 600 $F
printf '%s' "$RMQ_COOKIE" | sudo tee $F > /dev/null
sudo chown xray:xray $F
sudo chmod 400 $FServer cookie (used by RabbitMQ):
F=$RMQ_HOME/.erlang.cookie
sudo chmod 600 $F
printf '%s' "$RMQ_COOKIE" | sudo tee $F > /dev/null
sudo chown xray:xray $F
sudo chmod 400 $FCheck:
sudo ls -l /opt/jfrog/xray/.erlang.cookie $RMQ_HOME/.erlang.cookieExpect both files listed as -r-------- and owned by xray. If both paths point to the same file, writing it once is enough. If only the server cookie is changed, RabbitMQ starts but rabbitmqctl cannot connect to it. If a file is owned by root, or unreadable by the service user, RabbitMQ cannot start.
A.2.3 On every node that runs RabbitMQ (split mode: also on Xray nodes where the key is present), set the cookie in system.yaml. The start-up script uses this value when it creates a cookie file, for example on a new node or after a reinstall.
shared:
rabbitMq:
erlangCookie:
value: "<RMQ_COOKIE>"A.2.4 Start the node that stopped last first, then immediately all other RabbitMQ nodes:
sudo systemctl start --no-block xray # split-mode RabbitMQ node: xray-rabbitmqOn a single node, sudo systemctl start xray is enough. Wait until rabbitmqctl cluster_status lists all nodes under Running Nodes. Split mode: then run sudo systemctl start xray on every Xray node.
A.2.5 Verify
-
Both cookie files hold the new value, on every node. Compare checksums, so you never print the value; all three must be the same:
sudo sha256sum /opt/jfrog/xray/.erlang.cookie $RMQ_HOME/.erlang.cookie printf '%s' "$RMQ_COOKIE" | sha256sum -
The old cookie is rejected. This command must fail with
Erlang distribution failed:sudo -u xray -i $RMQ_HOME/sbin/rabbitmq-diagnostics -n rabbit@$(hostname -s) --erlang-cookie "$OLD_COOKIE" status -
rabbitmqctl cluster_statuslists all nodes and shows no network partitions. -
The password from A.1 still works:
rabbitmqctl authenticate_user <user> "$RMQ_PASSWORD". -
rabbitmqctl list_queues -p xray_haq name messages consumersshows the expected queues with consumers, and the health check (0.6) showsHEALTHY. -
A test scan completes, and there are no errors in the Xray or RabbitMQ logs.
If a check fails, see Troubleshooting (A.4), or go to Rollback (A.5).
A.3 User — Replace guest with xray_admin and Delete guest
Before you start: A.1 and A.2 are done and verified, and $RMQ_PASSWORD is set in your shell. Xray restarts in A.3.3 and RabbitMQ restarts in A.3.4.
A.3.1 Create the new user. Run once, on any RabbitMQ node; users are shared across the cluster.
-
List the vhosts. Expect at least
/andxray_haq:rabbitmqctl list_vhosts -
Create the user and give it full permissions on each vhost Xray uses:
rabbitmqctl add_user xray_admin "$RMQ_PASSWORD" rabbitmqctl set_user_tags xray_admin administrator rabbitmqctl set_permissions -p / xray_admin ".*" ".*" ".*" rabbitmqctl set_permissions -p xray_haq xray_admin ".*" ".*" ".*"If
list_vhostsprints another vhost that Xray uses, runset_permissionsfor it too. -
Check:
rabbitmqctl list_user_permissions xray_admin rabbitmqctl authenticate_user xray_admin "$RMQ_PASSWORD"
Permissions are stored in RabbitMQ and survive restarts.
A.3.2 Point Xray at the new user, on every node:
-
In
system.yaml(split mode: every Xray node and every RabbitMQ node):shared: rabbitMq: username: "xray_admin" password: "<RMQ_PASSWORD>" -
On every node that runs RabbitMQ, in each
rabbitmq.confthat exists:default_user = xray_admin default_pass = <RMQ_PASSWORD>For example:
sudo -u xray sed -i "s|^default_user *=.*|default_user = xray_admin|" /opt/jfrog/xray/app/bin/rabbitmq/rabbitmq.conf sudo -u xray sed -i "s|^default_user *=.*|default_user = xray_admin|" /opt/jfrog/xray/var/etc/rabbitmq.conf sudo grep -n '^default_' /opt/jfrog/xray/app/bin/rabbitmq/rabbitmq.conf /opt/jfrog/xray/var/etc/rabbitmq.confThis keeps the password of
xray_adminin line withdefault_passwhen RabbitMQ restarts.
A.3.3 Restart Xray and confirm it uses the new user. Run sudo systemctl restart xray on each node that runs Xray, one at a time, active node first. On nodes that run both Xray and RabbitMQ, this also restarts RabbitMQ (because of autoStop). Then:
rabbitmqctl list_connections userAll Xray connections must show xray_admin; none may show guest. Run a test scan, and check the Xray logs for RabbitMQ authentication errors. Do not continue until no connection uses guest.
A.3.4 Restrict guest to localhost, permanently. On every node that runs RabbitMQ, add this to system.yaml. The start-up script writes it into rabbitmq.conf on every start.
shared:
rabbitMq:
node:
rabbitmqConf:
- name: loopback_users.guest
value: "true"If rabbitmqConf already has entries, add this one to the list. Then restart the service, one node at a time, and check:
rabbitmqctl environment | grep loopback_usersExpect {loopback_users,[<<"guest">>]}.
A.3.5 Delete guest.
rabbitmqctl delete_user guest
rabbitmqctl list_usersguest must not be listed. After this, the RabbitMQ start-up log shows these lines on every start. They are expected and harmless:
Failed to change password for user 'guest'/the user does not existFailed to set permissions for vhost: xray_haq with user: guest
A.3.6 Verify
-
From a different host,
guestis refused. Each command must print401(this works only if port 15672 is reachable from that host):curl -s -o /dev/null -w '%{http_code}\n' -u "guest:$OLD_PASS" http://<rabbitmq-host>:15672/api/whoami curl -s -o /dev/null -w '%{http_code}\n' -u "guest:$RMQ_PASSWORD" http://<rabbitmq-host>:15672/api/whoami curl -s -o /dev/null -w '%{http_code}\n' -u guest:JFXR_RABBITMQ_COOKIE http://<rabbitmq-host>:15672/api/whoami curl -s -o /dev/null -w '%{http_code}\n' -u guest:guest http://<rabbitmq-host>:15672/api/whoami -
rabbitmqctl list_usersdoes not listguest, andrabbitmqctl list_connections usershows onlyxray_admin. -
After one more restart, both checks above still pass.
-
A test scan completes.
A.3.7 After every Xray upgrade or installer re-run, check that the old settings did not come back. An upgrade can rewrite rabbitmq.conf from the installer's defaults.
rabbitmqctl list_users # no guest
sudo grep -n 'loopback_users.guest' /opt/jfrog/xray/app/bin/rabbitmq/rabbitmq.conf # true (or no line)
sudo grep -n '^default_user' /opt/jfrog/xray/app/bin/rabbitmq/rabbitmq.conf # xray_admin
sudo grep -n -A6 'rabbitMq:' /opt/jfrog/xray/var/etc/system.yaml # username: xray_adminIf a value is back to the default, set it again (A.3.2, A.3.4) and restart.
A.4 Troubleshooting
| Symptom | Likely cause | Action |
|---|---|---|
After systemctl stop xray, beam.smp is still running, and the next start times out after 300 seconds | shared.rabbitMq.autoStop is not true, so the service did not stop RabbitMQ, and it still runs with the old cookie | Set autoStop: true (0.1). To recover now, stop RabbitMQ with the old cookie: sudo -u xray -i $RMQ_HOME/sbin/rabbitmqctl --erlang-cookie "$OLD_COOKIE" shutdown, then sudo systemctl restart xray. If the Xray services do not report HEALTHY afterwards, run sudo systemctl restart xray once more. |
rabbitmqctl fails with File operation error: eacces | It was run without a login shell, from a folder the service user cannot read | Run it as sudo -u xray -i ... |
rabbitmqctl reports that it cannot connect, or that cookie authentication failed | It was run as the wrong user; or the CLI cookie (in the service user's home folder) differs from the server cookie; or a node still has the old cookie | Run it as sudo -u xray -i. Compare the checksums and owners of all cookie files on all nodes. |
| RabbitMQ does not start after the cookie change | The cookie file is owned by root, or has the wrong mode | Set the owner to the service user and the mode to 400 |
A node logs Waiting for Mnesia tables, then Timeout contacting cluster nodes or BOOT FAILED | The first node started was not the last one stopped, or the other nodes started more than about 5 minutes later | Start the remaining nodes now (systemctl start --no-block). Next time, start the last-stopped node first. |
| The new password works, then the old one is back after a restart | A rabbitmq.conf on some node still has the old default_pass | Fix every rabbitmq.conf on every node, run change_password again, and restart |
A loop over the vhosts fails with vhost 'name' not found | list_vhosts -q prints a header line on RabbitMQ 4 | Run set_permissions for each vhost by name (A.3.1) |
Xray cannot connect after guest was restricted | Xray still used guest when it was restricted | Point Xray at the new user (A.3.2), then restart Xray |
loopback_users.guest = false is back after an upgrade or a configV2.sh run | The installer wrote a fresh rabbitmq.conf from its template | Add the shared.rabbitMq.node.rabbitmqConf entry (A.3.4) and set the value again |
| A node cannot rejoin the cluster after it was offline | A cluster state problem, not a credentials problem | Contact JFrog Support. Do not run rabbitmqctl reset without a plan for the node's data. |
A.5 Rollback
-
Stop Xray on every node (split mode: the Xray nodes first), then the service on every RabbitMQ node. Note which node you stop last. Check that
pgrep -f beam.smpprints nothing. If RabbitMQ is still running, stop it with the cookie it runs with:sudo -u xray -i $RMQ_HOME/sbin/rabbitmqctl --erlang-cookie <cookie> shutdown. -
From the backup (0.5), restore only
system.yaml, everyrabbitmq.conf, and both cookie files, with the same owner and mode. -
Start the node you stopped last first, then the others immediately (
systemctl start --no-block). The restoreddefault_passis applied on start. -
If
guestwas already deleted, create it again:rabbitmqctl add_user guest "$OLD_PASS" rabbitmqctl set_user_tags guest administrator rabbitmqctl set_permissions -p / guest ".*" ".*" ".*" rabbitmqctl set_permissions -p xray_haq guest ".*" ".*" ".*"Set
username: guestanddefault_user = guestback, and remove theloopback_users.guestentry fromshared.rabbitMq.node.rabbitmqConf. -
Run the checks from A.1.5 and A.2.5 with the old values.
A.6 Clean Up
-
Clear the values from your shell and turn history back on:
unset RMQ_PASSWORD RMQ_COOKIE OLD_PASS OLD_COOKIE set -o history -
When the change is confirmed, delete the backups that contain secrets (for example
sudo rm /var/tmp/xray-rmq-backup.tgz), or move them to secure storage. -
Keep
shared.rabbitMq.autoStop: true. It is the recommended setting. -
Record the change in your change-management system: date, layout (single node, multi-node or split mode), versions, and the result of each check.
Step 0 — Prepare (Docker Compose)
Rules
- One cookie and one password per cluster. Generate them once and copy the same values to every node. RabbitMQ shares users and passwords across the whole cluster, so you run
rabbitmqctl change_passwordandadd_useronce, on any node. - Change every copy. The password is stored in
system.yamland in everyrabbitmq.confon the node. Every time RabbitMQ starts, Xray's start-up script sets the password ofdefault_usertodefault_passfromrabbitmq.conf. Because the password is shared across the cluster, one node with an olddefault_passresets the password for the whole cluster the next time it starts. - Do not paste the new values into tickets, chat or source control.
- Make the password, cookie and user changes as separate steps, and verify each one before the next. Deleting
guestis part of the procedure, not optional.
0.1 Plan a maintenance window and announce it. Scans and other Xray processing stall during the change.
0.2 Generate the new values once, on a trusted host, with shell history turned off:
set +o history
RMQ_PASSWORD=$(openssl rand -hex 24)
RMQ_COOKIE=$(openssl rand -hex 32)Store both in your secret manager, and use the same two values on every node. The examples use the same $RMQ_PASSWORD for the new xray_admin user.
In the shell on each node, set the new values and the current values (the checks use them):
set +o history
RMQ_PASSWORD='<new password>'
RMQ_COOKIE='<new cookie>'
OLD_PASS='<current password>'
OLD_COOKIE='<current cookie>'The installer default for the password and the cookie is JFXR_RABBITMQ_COOKIE, and the default user is guest. Many installations set their own values during installation, so do not assume the default. Read the current password from default_pass in rabbitmq.conf, and the current cookie from the .erlang.cookie file. The paths are listed in B.0.
0.3 Record the current settings.
-
Current RabbitMQ user (
<user>in this tab). Default:guest. Checkshared.rabbitMq.usernameinsystem.yaml. -
Active node (multi-node only): the node named in
shared.rabbitMq.active.node.nameinsystem.yaml. -
Cluster nodes, users and vhosts:
sudo docker exec xray_rabbitmq rabbitmqctl cluster_status sudo docker exec xray_rabbitmq rabbitmqctl list_users sudo docker exec xray_rabbitmq rabbitmqctl list_vhosts
0.4 Back up. Copy, do not move. The backups contain secrets; keep them readable by root only. Back up the whole $ROOT_DATA_DIR folder without var/log, and the .env file. When you restore, restore only the files this procedure changes; the same folder can also hold PostgreSQL data.
0.5 Check that the system is healthy before you start, and again after each step:
-
Xray health, on a node that runs Xray. All services must show
"state" : "HEALTHY":curl -s http://localhost:8082/router/api/v1/system/health -
Xray is connected to RabbitMQ:
sudo docker exec xray_rabbitmq rabbitmqctl list_connections user -
The current password is correct (prints
Success):sudo docker exec xray_rabbitmq rabbitmqctl authenticate_user <user> "$OLD_PASS"
After a restart, the Xray services can take a few minutes to report HEALTHY again.
B.0 Projects and Paths
-
Data folder (
ROOT_DATA_DIR). It is set in the.envfile next to thedocker-compose*.yamlfiles. Go to the Compose installation folder and set it in your shell:cd <compose-install-folder> export ROOT_DATA_DIR=$(grep ^ROOT_DATA_DIR= .env | cut -d= -f2) echo $ROOT_DATA_DIR -
Files, under
$ROOT_DATA_DIR:File Path Notes system.yaml$ROOT_DATA_DIR/var/etc/system.yamlXray encrypts the password in it after it starts. rabbitmq.conf$ROOT_DATA_DIR/app/third-party/rabbitmq/rabbitmq.confMounted into the container as /etc/rabbitmq/rabbitmq.conf.rabbitmq.conf(second copy)$ROOT_DATA_DIR/var/etc/rabbitmq.confExists on newer installations only. Erlang cookie $ROOT_DATA_DIR/var/data/rabbitmq/.erlang.cookieThe only cookie file. The folder is mounted as /var/lib/rabbitmq.The RabbitMQ container is named
xray_rabbitmq. -
Root or
sudo. The data folder and the Docker socket belong to root. Run the commands withsudo, or as root. The cookie file is hidden; list it withsudo ls -la. -
Compose projects. By default, RabbitMQ and Xray run as two separate Compose projects. Check with
sudo docker compose ls. Run the commands from the Compose installation folder:Action Command RabbitMQ project sudo docker compose -p xray-rabbitmq -f docker-compose-rabbitmq.yaml <command>Xray project sudo docker compose -p xray <command>rabbitmqctlsudo docker exec xray_rabbitmq rabbitmqctl <command>A plain
docker compose restartrestarts only one of the projects. Stop order: Xray, then RabbitMQ. Start order: RabbitMQ, then Xray. If PostgreSQL also runs from this folder, leave it running. -
Split mode. RabbitMQ nodes run only the RabbitMQ project. Xray nodes run only the Xray project and list every RabbitMQ node under
shared.rabbitMq.urls, with one user name and password for all of them; RabbitMQ users are shared across the cluster. On Xray nodes, onlysystem.yamlmatters. -
One merged project (
docker-compose-all.yaml). If Xray, RabbitMQ and PostgreSQL run from one file, usesudo docker compose -p <project> -f docker-compose-all.yaml <command>with the project name fromdocker compose ls. Where a step restarts only RabbitMQ, restart only the RabbitMQ service:sudo docker compose -p <project> -f docker-compose-all.yaml restart rabbitmq(check the service name in the file). -
Restarts and
configV2.sh. A plain restart does not runconfigV2.sh, so the cookie andrabbitmq.confstay as you wrote them. Do not runconfigV2.shduring this procedure; it copies a freshrabbitmq.conffrom the installer's template.
Edit
rabbitmq.confin place
rabbitmq.confis mounted into the container as a single file.sed -iand most editors write a new file in its place, and the container keeps reading the old one until it is recreated. Edit a copy, then write the copy's content back into the same file, as below. This also keeps the file's owner unchanged.
To edit rabbitmq.conf (repeat for the second copy, if it exists):
sudo cp $ROOT_DATA_DIR/app/third-party/rabbitmq/rabbitmq.conf $ROOT_DATA_DIR/app/third-party/rabbitmq/rabbitmq.conf.edit
sudo vi $ROOT_DATA_DIR/app/third-party/rabbitmq/rabbitmq.conf.edit
sudo sh -c "cat $ROOT_DATA_DIR/app/third-party/rabbitmq/rabbitmq.conf.edit > $ROOT_DATA_DIR/app/third-party/rabbitmq/rabbitmq.conf"
sudo rm $ROOT_DATA_DIR/app/third-party/rabbitmq/rabbitmq.conf.editThen check that the container sees the change:
sudo docker exec xray_rabbitmq grep -n '^default_' /etc/rabbitmq/rabbitmq.confB.1 Password
B.1.1 On every node (split mode: Xray nodes and RabbitMQ nodes), set the password in $ROOT_DATA_DIR/var/etc/system.yaml:
shared:
rabbitMq:
password: "<RMQ_PASSWORD>"Change only the password: line inside the rabbitMq: block. Check with sudo grep -n -A6 'rabbitMq:' $ROOT_DATA_DIR/var/etc/system.yaml. Xray encrypts the value when it next starts.
B.1.2 On every node that runs RabbitMQ, set the password in both rabbitmq.conf files, in place (see B.0):
default_pass = <RMQ_PASSWORD>Then check that the container sees the new value.
B.1.3 Change the password in RabbitMQ, once per cluster:
sudo docker exec xray_rabbitmq rabbitmqctl change_password <user> "$RMQ_PASSWORD"
sudo docker exec xray_rabbitmq rabbitmqctl authenticate_user <user> "$RMQ_PASSWORD"Expect Success.
B.1.4 Restart RabbitMQ and then Xray straight away, active node first, then the other nodes without delay:
sudo docker compose -p xray-rabbitmq -f docker-compose-rabbitmq.yaml restart
sudo docker exec xray_rabbitmq rabbitmqctl await_startup
sudo docker exec xray_rabbitmq rabbitmqctl authenticate_user <user> "$RMQ_PASSWORD"
sudo docker compose -p xray restartIf await_startup fails because the container is still starting, wait a few seconds and run it again.
B.1.5 Verify
-
The new password works and the old one is rejected:
sudo docker exec xray_rabbitmq rabbitmqctl authenticate_user <user> "$RMQ_PASSWORD" sudo docker exec xray_rabbitmq rabbitmqctl authenticate_user <user> "$OLD_PASS"Expect
Successfor the first, an error for the second. -
The password survives a restart: restart the RabbitMQ project once more and repeat the check above.
-
The health check (0.5) shows
HEALTHY, Xray connections are back, there are no RabbitMQ authentication errors in the Xray logs, and a test scan completes.
If a check fails, go to Rollback (B.5).
B.2 Erlang Cookie
All nodes must be stopped at the same time. No node may run with the new cookie while another runs with the old one. In a cluster, the node that stopped last starts first, then all others immediately. The other nodes wait for a peer for about 5 minutes and then fail to start, so do not wait between starts.
B.2.1 On every node, one at a time, stop Xray, then RabbitMQ, and note which node you stop last:
sudo docker compose -p xray down
sudo docker compose -p xray-rabbitmq -f docker-compose-rabbitmq.yaml down
sudo docker ps --filter name=xray_rabbitmqThe last command must list no container. With docker-compose-all.yaml: sudo docker compose -p <project> -f docker-compose-all.yaml down.
B.2.2 On every RabbitMQ node, write the new cookie. The file must keep the owner of the RabbitMQ data folder (the rabbitmq user inside the container, UID 999 by default), with mode 400:
F=$ROOT_DATA_DIR/var/data/rabbitmq/.erlang.cookie
sudo chmod 600 $F
printf '%s' "$RMQ_COOKIE" | sudo tee $F > /dev/null
sudo chown --reference=$ROOT_DATA_DIR/var/data/rabbitmq $F
sudo chmod 400 $F
sudo ls -ln $FThe owner must match the other files in $ROOT_DATA_DIR/var/data/rabbitmq. RabbitMQ does not start if it cannot read the file.
B.2.3 On every RabbitMQ node (split mode: also on Xray nodes where the key is present), set the cookie in $ROOT_DATA_DIR/var/etc/system.yaml. The installer uses this value when it creates a cookie file, for example when you add a node or reinstall.
shared:
rabbitMq:
erlangCookie:
value: "<RMQ_COOKIE>"B.2.4 Start RabbitMQ on the node that stopped last first, then immediately on all other nodes (up -d returns at once):
sudo docker compose -p xray-rabbitmq -f docker-compose-rabbitmq.yaml up -dWhen RabbitMQ runs on all nodes, check the cluster, then start Xray on each node:
sudo docker exec xray_rabbitmq rabbitmqctl await_startup
sudo docker exec xray_rabbitmq rabbitmqctl cluster_status
sudo docker compose -p xray up -dWith docker-compose-all.yaml: sudo docker compose -p <project> -f docker-compose-all.yaml up -d.
B.2.5 Verify
-
The cookie holds the new value on every node. Both checksums must be the same:
sudo sha256sum $ROOT_DATA_DIR/var/data/rabbitmq/.erlang.cookie printf '%s' "$RMQ_COOKIE" | sha256sum -
The old cookie is rejected. This command must fail with
Erlang distribution failed:sudo docker exec xray_rabbitmq rabbitmq-diagnostics -n rabbit@<node> --erlang-cookie "$OLD_COOKIE" statusUse the node name that
cluster_statusprints. -
cluster_statuslists all nodes with no network partitions, and the password from B.1 still works. -
sudo docker exec xray_rabbitmq rabbitmqctl list_queues -p xray_haq name messages consumersshows the expected queues with consumers, and the health check (0.5) showsHEALTHY. -
A test scan completes, and there are no errors in the Xray or RabbitMQ logs.
If a check fails, see Troubleshooting (B.4), or go to Rollback (B.5).
B.3 User — Replace guest with xray_admin and Delete guest
Before you start: B.1 and B.2 are done and verified, and $RMQ_PASSWORD is set in your shell. Xray restarts in B.3.3 and RabbitMQ restarts in B.3.4.
B.3.1 Create the new user, once, in the RabbitMQ container; users are shared across the cluster.
sudo docker exec xray_rabbitmq rabbitmqctl list_vhosts
sudo docker exec xray_rabbitmq rabbitmqctl add_user xray_admin "$RMQ_PASSWORD"
sudo docker exec xray_rabbitmq rabbitmqctl set_user_tags xray_admin administrator
sudo docker exec xray_rabbitmq rabbitmqctl set_permissions -p / xray_admin ".*" ".*" ".*"
sudo docker exec xray_rabbitmq rabbitmqctl set_permissions -p xray_haq xray_admin ".*" ".*" ".*"
sudo docker exec xray_rabbitmq rabbitmqctl list_user_permissions xray_admin
sudo docker exec xray_rabbitmq rabbitmqctl authenticate_user xray_admin "$RMQ_PASSWORD"list_vhosts must show at least / and xray_haq. If it prints another vhost that Xray uses, run set_permissions for it too.
B.3.2 Point Xray at the new user, on every node:
-
In
$ROOT_DATA_DIR/var/etc/system.yaml:shared: rabbitMq: username: "xray_admin" password: "<RMQ_PASSWORD>" -
On RabbitMQ nodes, in both
rabbitmq.conffiles, in place (see B.0):default_user = xray_admin default_pass = <RMQ_PASSWORD>This keeps the password of
xray_adminin line withdefault_passwhen RabbitMQ restarts.
B.3.3 Restart Xray and confirm it uses the new user. Restart only Xray, on each node, active node first; RabbitMQ keeps running:
sudo docker compose -p xray restart
sudo docker exec xray_rabbitmq rabbitmqctl list_connections userAll connections must show xray_admin; none may show guest. Run a test scan, and check the Xray logs for RabbitMQ authentication errors. Do not continue until no connection uses guest.
B.3.4 Restrict guest to localhost, permanently. Set the value in two places:
- in
system.yaml, so the installer writes it intorabbitmq.confevery timeconfigV2.shruns, for example during an upgrade; - in the current
rabbitmq.conffiles, because a plain restart does not re-readsystem.yaml.
-
On every RabbitMQ node, add this to
$ROOT_DATA_DIR/var/etc/system.yaml:shared: rabbitMq: node: rabbitmqConf: - name: loopback_users.guest value: "true"If
rabbitmqConfalready has entries, add this one to the list. -
On every RabbitMQ node, change this line in both
rabbitmq.conffiles, in place (see B.0):loopback_users.guest = true -
Restart RabbitMQ, one node at a time, and check:
sudo docker compose -p xray-rabbitmq -f docker-compose-rabbitmq.yaml restart sudo docker exec xray_rabbitmq rabbitmqctl await_startup sudo docker exec xray_rabbitmq rabbitmqctl environment | grep loopback_usersExpect
{loopback_users,[<<"guest">>]}.
B.3.5 Delete guest.
sudo docker exec xray_rabbitmq rabbitmqctl delete_user guest
sudo docker exec xray_rabbitmq rabbitmqctl list_usersguest must not be listed. After this, the RabbitMQ container log shows these lines on every start. They are expected and harmless: Failed to change password for user 'guest' / the user does not exist, and Failed to set permissions for vhost: xray_haq with user: guest.
B.3.6 Verify
-
From a different host,
guestis refused. Each command must print401:curl -s -o /dev/null -w '%{http_code}\n' -u "guest:$OLD_PASS" http://<rabbitmq-host>:15672/api/whoami curl -s -o /dev/null -w '%{http_code}\n' -u "guest:$RMQ_PASSWORD" http://<rabbitmq-host>:15672/api/whoami curl -s -o /dev/null -w '%{http_code}\n' -u guest:JFXR_RABBITMQ_COOKIE http://<rabbitmq-host>:15672/api/whoami curl -s -o /dev/null -w '%{http_code}\n' -u guest:guest http://<rabbitmq-host>:15672/api/whoami -
list_usersdoes not listguest, andlist_connections usershows onlyxray_admin. -
After one more restart of both projects, both checks above still pass.
-
A test scan completes.
B.3.7 After every upgrade or configV2.sh run, check that guest is still absent, loopback_users.guest is not false, rabbitmq.conf has default_user = xray_admin, and system.yaml has username: xray_admin. If a value is back to the default, set it again (B.3.2, B.3.4) and restart.
B.4 Troubleshooting
| Symptom | Likely cause | Action |
|---|---|---|
| RabbitMQ does not start after the cookie change | The cookie file is owned by root, or has the wrong mode | Set the owner to the owner of the RabbitMQ data folder (UID 999 by default) and the mode to 400 |
A node logs Waiting for Mnesia tables, then Timeout contacting cluster nodes or BOOT FAILED | The first node started was not the last one stopped, or the other nodes started more than about 5 minutes later | Start the remaining nodes now. Next time, start the last-stopped node first. |
| The new password works, then the old one is back after a restart | A rabbitmq.conf on some node still has the old default_pass | Fix every rabbitmq.conf on every node, run change_password again, and restart |
The new value is in rabbitmq.conf on the host, but not in /etc/rabbitmq/rabbitmq.conf in the container | The file was replaced (for example with sed -i or an editor) instead of edited in place | Edit the file in place (see B.0), or recreate the container with sudo docker compose -p xray-rabbitmq -f docker-compose-rabbitmq.yaml up -d --force-recreate |
Xray cannot connect after guest was restricted | Xray still used guest when it was restricted | Point Xray at the new user (B.3.2), then restart Xray |
loopback_users.guest = false is back after an upgrade or a configV2.sh run | The installer wrote a fresh rabbitmq.conf from its template | Add the shared.rabbitMq.node.rabbitmqConf entry (B.3.4) and set the value again |
| A node cannot rejoin the cluster after it was offline | A cluster state problem, not a credentials problem | Contact JFrog Support. Do not run rabbitmqctl reset without a plan for the node's data. |
B.5 Rollback
- On every node, stop Xray, then RabbitMQ (
docker compose ... down, as in B.2.1). Note which node you stop last. - From the backup (0.4), restore only
system.yaml, bothrabbitmq.conffiles, the cookie file (with the same owner and mode) and.env. Do not restore the whole folder over PostgreSQL data. Writerabbitmq.confback in place. - Start RabbitMQ on the node you stopped last first, then on the others, then Xray (
docker compose ... up -d, as in B.2.4). The restoreddefault_passis applied on start. - If
guestwas already deleted, create it again, withsudo docker exec xray_rabbitmq rabbitmqctl ...:add_user guest "$OLD_PASS",set_user_tags guest administrator, andset_permissionson/andxray_haq. - Run the checks from B.1.5 and B.2.5 with the old values.
B.6 Clean Up
-
Clear the values from your shell and turn history back on:
unset RMQ_PASSWORD RMQ_COOKIE OLD_PASS OLD_COOKIE set -o history -
When the change is confirmed, delete the backups that contain secrets (the copy of
$ROOT_DATA_DIRand.env), or move them to secure storage. -
Record the change in your change-management system: date, layout (single node, multi-node or split mode), versions, and the result of each check.
Installed with the JFrog Platform chart (
jfrog/jfrog-platform)?Follow the same steps, but read C.8 JFrog Platform Chart first. The default user, vhosts, resource names and secrets differ.
Step 0 — Prepare (Helm)
Rules
- One cookie and one password per cluster. All RabbitMQ pods use the same cookie and password from the RabbitMQ secret. RabbitMQ shares users and passwords across the whole cluster, so you run
rabbitmqctl add_useronce, in pod 0. - Change every copy. The password is stored in the RabbitMQ secret and in your Helm values, and the two must match.
- Do not paste the new values into tickets, chat or source control.
- All three changes are made in one downtime window. Deleting
guestis part of the procedure, not optional.
0.1 Plan a maintenance window and announce it. Scans and other Xray processing stall during the change.
0.2 Generate the new values once, on a trusted host, with shell history turned off:
set +o history
RMQ_PASSWORD=$(openssl rand -hex 24)
RMQ_COOKIE=$(openssl rand -hex 32)Store both in your secret manager. The examples use the same $RMQ_PASSWORD for the new xray_admin user.
In the shell where you run kubectl and helm, set the new values and the current values (the checks use them):
set +o history
RMQ_PASSWORD='<new password>'
RMQ_COOKIE='<new cookie>'
OLD_PASS='<current password>'
OLD_COOKIE='<current cookie>'The installer defaults are:
| User | Password | Cookie | |
|---|---|---|---|
| Xray Helm chart | guest | password | XRAYRABBITMQCLUSTER |
| JFrog Platform Helm chart | admin | password | secretcookie |
Many installations set their own values during installation, so do not assume the default. Read the current password and cookie from the secret <release>-rabbitmq:
kubectl -n <ns> get secret <release>-rabbitmq -o jsonpath='{.data.rabbitmq-password}' | base64 -d
kubectl -n <ns> get secret <release>-rabbitmq -o jsonpath='{.data.rabbitmq-erlang-cookie}' | base64 -d0.3 Record the current settings, back up, and check that the system is healthy: see C.0.
On Helm, you make all three changes in one downtime window. Xray and RabbitMQ are stopped, you write the new password and cookie into the RabbitMQ secret, start RabbitMQ, and then one helm upgrade switches Xray to the new user.
C.0 to C.7 use the names of the Xray chart (jfrog/xray). For the JFrog Platform chart (jfrog/jfrog-platform), the steps are the same, but some names and defaults differ; see C.8 JFrog Platform Chart.
In the commands, replace <ns> with your namespace and <release> with your release name.
C.0 Before You Begin
How the chart handles the RabbitMQ credentials. Read this first; it explains each step.
| What | Where it comes from | What it means for this procedure |
|---|---|---|
| Password and Erlang cookie used by the RabbitMQ and Xray pods | The secret <release>-rabbitmq, keys rabbitmq-password and rabbitmq-erlang-cookie | The chart creates this secret at installation. On later upgrades, the Xray chart keeps the existing values, even if you change rabbitmq.auth.password or rabbitmq.auth.erlangCookie in your values. (The JFrog Platform chart writes the new values.) In both cases you change the secret directly while RabbitMQ is scaled to 0 (C.3), because the cookie must not change while RabbitMQ runs. |
| RabbitMQ user and its password inside RabbitMQ | load_definition.json (secret <release>-load-definition), rendered from rabbitmq.auth.username and rabbitmq.auth.password in your values | RabbitMQ imports this file every time it starts and sets that user's password and permissions from it. The password in your values must therefore equal the password in the secret. Otherwise, the next RabbitMQ start sets a password that Xray does not use. |
| User name used by RabbitMQ and Xray | rabbitmq.auth.username in your values | Changing it with helm upgrade restarts the RabbitMQ and Xray pods. |
| Pre-upgrade hook | Runs before every helm upgrade | If rabbitmq.migration.removeHaPolicyOnMigrationToHaQuorum.enabled is true, the hook waits for RabbitMQ pod 0 to be ready and fails the upgrade otherwise. Do not run helm upgrade while RabbitMQ is scaled to 0. |
| Cookie file in the RabbitMQ pods | Written from the secret at every pod start | All RabbitMQ pods must start with the same cookie, so the cookie is only changed while RabbitMQ is scaled to 0. |
Record your settings:
-
Release name, namespace and chart version:
helm list -n <ns>. -
Current values:
helm get values <release> -n <ns>. Noterabbitmq.auth.username(defaultguest),rabbitmq.replicaCount, whetherrabbitmq.auth.existingPasswordSecretorexistingErlangSecretis set, and whether autoscaling (KEDA or HPA) is enabled for any Xray workload. -
The workloads and their replica counts:
kubectl -n <ns> get sts,deployThe RabbitMQ StatefulSet is
<release>-rabbitmq. The Xray workloads are the StatefulSet<release>and, depending on the chart version and your values, Deployments such as<release>-serverand<release>-ipa. Every Xray workload that connects to RabbitMQ is stopped in C.2. -
The cluster and the vhosts. Expect
/andxray_haq:kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl cluster_status kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl list_vhosts
Back up the values and the RabbitMQ secret:
helm get values <release> -n <ns> > values-backup.yaml
kubectl -n <ns> get secret <release>-rabbitmq -o yaml > rabbitmq-secret-backup.yamlPrepare the values file. Put the new user name, password and cookie in a separate values file, rabbitmq-auth.yaml. Store it in your secret manager, do not commit it, and pass it on every helm upgrade from now on:
# rabbitmq-auth.yaml
rabbitmq:
auth:
username: xray_admin
password: "<RMQ_PASSWORD>"
erlangCookie: "<RMQ_COOKIE>"The password and cookie in this file must be the same values you write into the secret in C.3. The values are used for the RabbitMQ definitions and when the secret is created again, for example on a new installation.
Health check. Run it before you start and after each step. All services must show "state" : "HEALTHY":
kubectl -n <ns> exec <release>-0 -c router -- curl -s http://localhost:8082/router/api/v1/system/healthC.1 Create the New User
RabbitMQ is still running. Create the new user once, in pod 0; users are shared across the cluster.
kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl add_user xray_admin "$RMQ_PASSWORD"
kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl set_user_tags xray_admin administrator
kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl set_permissions -p / xray_admin ".*" ".*" ".*"
kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl set_permissions -p xray_haq xray_admin ".*" ".*" ".*"
kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl authenticate_user xray_admin "$RMQ_PASSWORD"Expect Success. If list_vhosts printed another vhost that Xray uses, run set_permissions for it too. Leave guest in place for now: Xray still uses it, and it is your fallback if you roll back.
C.2 Stop Xray
This starts the downtime window.
-
If KEDA autoscaling is enabled for an Xray workload, pause it so it does not scale the workload up again:
kubectl -n <ns> annotate scaledobject <scaledobject> autoscaling.keda.sh/paused-replicas="0" --overwrite -
Scale every Xray workload that connects to RabbitMQ to 0, and wait until its pods are gone. For example:
kubectl -n <ns> scale sts/<release> --replicas=0 kubectl -n <ns> get pods -wDo the same for each Xray Deployment, for example
kubectl -n <ns> scale deploy/<release>-server --replicas=0.
C.3 Stop RabbitMQ, Change the Secret, Start RabbitMQ
-
Note the RabbitMQ replica count (for example
3), then scale RabbitMQ to 0 and wait until all its pods are gone:kubectl -n <ns> get sts <release>-rabbitmq kubectl -n <ns> scale sts/<release>-rabbitmq --replicas=0 kubectl -n <ns> get pods -w -
Write the new password and cookie into the secret:
kubectl -n <ns> patch secret <release>-rabbitmq --type merge -p "{\"stringData\":{\"rabbitmq-password\":\"$RMQ_PASSWORD\",\"rabbitmq-erlang-cookie\":\"$RMQ_COOKIE\"}}" -
Check the secret. Compare checksums, so the values are never printed; the first two lines must match, and so must the last two:
kubectl -n <ns> get secret <release>-rabbitmq -o jsonpath='{.data.rabbitmq-password}' | base64 -d | sha256sum printf '%s' "$RMQ_PASSWORD" | sha256sum kubectl -n <ns> get secret <release>-rabbitmq -o jsonpath='{.data.rabbitmq-erlang-cookie}' | base64 -d | sha256sum printf '%s' "$RMQ_COOKIE" | sha256sum -
Start RabbitMQ with
kubectl, not withhelm upgrade, with the replica count from step 1, and wait until all pods are ready:kubectl -n <ns> scale sts/<release>-rabbitmq --replicas=<replica count from step 1> kubectl -n <ns> rollout status sts/<release>-rabbitmqWith
podManagementPolicy: Parallel, all pods start together. WithOrderedReady, pod 1 starts only after pod 0 is ready; if pod 0 waits for its peers, see Troubleshooting (C.9). -
Check RabbitMQ:
-
kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl cluster_statuslists all nodes and shows no network partitions. -
kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl authenticate_user xray_admin "$RMQ_PASSWORD"printsSuccess. -
The cookie is the same on every pod and matches the new value. Run the first command for each pod (
-0,-1,-2, ...). The cookie file ends with a newline, so the second command uses'%s\n':kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- sha256sum /opt/bitnami/rabbitmq/.rabbitmq/.erlang.cookie printf '%s\n' "$RMQ_COOKIE" | sha256sum
-
If the release uses
rabbitmq.auth.existingPasswordSecretorexistingErlangSecretPatch those secrets in step 2 instead of, or as well as,
<release>-rabbitmq, with the same keys (rabbitmq-password,rabbitmq-erlang-cookie). WithexistingPasswordSecret, the chart reads the password for the RabbitMQ definitions from that secret, so it must hold the new password before you runhelm upgrade.
C.4 Switch Xray to the New User with helm upgrade
RabbitMQ is running, so the pre-upgrade hook can reach it. Run the upgrade with the same chart version, your values, and rabbitmq-auth.yaml:
helm upgrade <release> jfrog/xray --version <chart version> -n <ns> --reuse-values -f rabbitmq-auth.yamlIf you manage your values in a file, use -f <your-values.yaml> -f rabbitmq-auth.yaml instead of --reuse-values.
The upgrade:
- changes the user name in the RabbitMQ and Xray pods to
xray_admin; - renders the RabbitMQ definitions with
xray_adminand the new password; - restarts the RabbitMQ pods one at a time (the cluster stays up, with the same cookie);
- sets the Xray workloads back to their configured replica counts, so Xray starts with the new user and the password from the secret.
Then:
-
Wait for the rollouts, and the same for each Xray Deployment:
kubectl -n <ns> rollout status sts/<release>-rabbitmq kubectl -n <ns> rollout status sts/<release> -
If an Xray workload is still at 0 (for example, because autoscaling manages its replicas), scale it back to the count you recorded in C.0.
-
If you paused KEDA, remove the annotation:
kubectl -n <ns> annotate scaledobject <scaledobject> autoscaling.keda.sh/paused-replicas-.
C.5 Verify
All checks must pass before you delete guest.
-
The secret still holds the new values (repeat the check from C.3 step 3).
-
xray_adminworks on every RabbitMQ pod (-0,-1,-2, ...):kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl authenticate_user xray_admin "$RMQ_PASSWORD" -
The cookie is the same on every pod (C.3 step 5), and the old cookie is rejected. This command must fail with
Erlang distribution failed. Use a node name thatcluster_statusprints:kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmq-diagnostics -n rabbit@<release>-rabbitmq-1.<release>-rabbitmq-headless.<ns>.svc.cluster.local --erlang-cookie "$OLD_COOKIE" statusIf you never changed the cookie before, the old value is
XRAYRABBITMQCLUSTER. -
cluster_statuslists all nodes, with no network partitions. -
Xray uses the new user. All connections must show
xray_admin. Do not continue until no connection usesguest.kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl list_connections user -
kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl list_queues -p xray_haq name consumersshows the expected queues with consumers. -
The health check shows all services
HEALTHY, and a test scan completes.
If a check fails, see Troubleshooting (C.9), or go to Rollback (C.10).
C.6 Delete guest
-
Delete the user.
guestmust not be listed afterwards:kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl delete_user guest kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl list_usersOn Helm, delete
guestrather than restricting it. After C.4 the RabbitMQ definitions contain onlyxray_admin, soguestis not created again when RabbitMQ restarts. -
Restart RabbitMQ once, and check that only
xray_adminis listed and connected:kubectl -n <ns> rollout restart sts/<release>-rabbitmq kubectl -n <ns> rollout status sts/<release>-rabbitmq kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl list_users kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl list_connections user -
Check that
guestis refused. Run it from a pod that can reach the RabbitMQ service, for example the Xrayroutercontainer. It must print401; repeat it with the old password and withpassword:kubectl -n <ns> exec <release>-0 -c router -- curl -s -o /dev/null -w '%{http_code}\n' -u "guest:$OLD_PASS" http://<release>-rabbitmq:15672/api/whoami -
Run a test scan.
C.7 After Every Future helm upgrade
- Always pass
rabbitmq-auth.yaml(or keep its keys in your values file). Without it, the user name and the RabbitMQ definitions go back toguestand the old password, and Xray can no longer connect. - After the upgrade, check that
helm get values <release> -n <ns>showsusername: xray_admin, that the secret still matches the new values (C.3 step 3), thatlist_usersdoes not listguest, and thatlist_connections usershows onlyxray_admin. - To rotate the password or cookie again later, repeat C.2 to C.5 with the new values in both the secret and
rabbitmq-auth.yaml. Do not change only the values file: the Xray chart keeps the old values in the secret.
C.8 JFrog Platform Chart
If Xray is installed with the JFrog Platform chart (jfrog/jfrog-platform), the procedure is the same as C.0 to C.7. The RabbitMQ settings are still under the top-level rabbitmq: key, so rabbitmq-auth.yaml has the same format. What differs are the resource names, the default user, the vhosts, and one extra secret:
| Xray chart | JFrog Platform chart | |
|---|---|---|
| Chart | jfrog/xray | jfrog/jfrog-platform |
| RabbitMQ StatefulSet and secret | <release>-rabbitmq | <release>-rabbitmq |
| Xray StatefulSet | <release> | <release>-xray |
| Default user, password and cookie | guest, password, XRAYRABBITMQCLUSTER | admin, password, secretcookie |
| Default user that you replace and delete | guest | admin (there is no guest user) |
| Vhosts used by Xray | / and xray_haq | xray and xray_haq |
| Where Xray reads the RabbitMQ user name, password and URL | User name from the values; password from <release>-rabbitmq | The secret <release>-xray-rabbitmq-creds. The platform chart renders it from rabbitmq.auth.username and rabbitmq.auth.password on every helm upgrade, so you do not patch it. |
What helm upgrade does with rabbitmq.auth.password and erlangCookie | Keeps the existing values in <release>-rabbitmq | Writes the values into <release>-rabbitmq |
You still change <release>-rabbitmq directly while RabbitMQ is scaled to 0 (C.3). A helm upgrade with a new cookie while RabbitMQ is running would restart the RabbitMQ pods one at a time with different cookies, and the pre-upgrade hook does not allow helm upgrade while RabbitMQ is scaled to 0.
Steps for the JFrog Platform chart. $RMQ_PASSWORD, $RMQ_COOKIE, $OLD_PASS and $OLD_COOKIE are set as in Step 0.
-
Back up and record (C.0):
helm get values <release> -n <ns> > values-backup.yaml kubectl -n <ns> get secret <release>-rabbitmq <release>-xray-rabbitmq-creds <release>-load-definition -o yaml > rabbitmq-secrets-backup.yaml kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl list_users kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl list_vhostsExpect the user
admin, and the vhostsxrayandxray_haq. Writerabbitmq-auth.yamlas in C.0. -
Create the new user (C.1):
kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl add_user xray_admin "$RMQ_PASSWORD" kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl set_user_tags xray_admin administrator kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl set_permissions -p xray xray_admin ".*" ".*" ".*" kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl set_permissions -p xray_haq xray_admin ".*" ".*" ".*" kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl authenticate_user xray_admin "$RMQ_PASSWORD" -
Stop Xray (C.2):
kubectl -n <ns> scale sts/<release>-xray --replicas=0 -
Stop RabbitMQ, change the secret, start RabbitMQ (C.3). Run these as separate steps.
a. Note the RabbitMQ replica count (for example
3), then scale RabbitMQ to 0 and wait until all its pods are gone:kubectl -n <ns> get sts <release>-rabbitmq kubectl -n <ns> scale sts/<release>-rabbitmq --replicas=0 kubectl -n <ns> get pods -wb. Only when no RabbitMQ pod is left, write the new password and cookie into the secret, and run the secret check from C.3 step 3:
kubectl -n <ns> patch secret <release>-rabbitmq --type merge -p "{\"stringData\":{\"rabbitmq-password\":\"$RMQ_PASSWORD\",\"rabbitmq-erlang-cookie\":\"$RMQ_COOKIE\"}}"c. Start RabbitMQ with the replica count from step a, then run the RabbitMQ checks from C.3 step 5:
kubectl -n <ns> scale sts/<release>-rabbitmq --replicas=<replica count from step a> kubectl -n <ns> rollout status sts/<release>-rabbitmq -
Run
helm upgrade(C.4):helm upgrade <release> jfrog/jfrog-platform --version <chart version> -n <ns> --reuse-values -f rabbitmq-auth.yaml kubectl -n <ns> rollout status sts/<release>-rabbitmq kubectl -n <ns> rollout status sts/<release>-xrayThe upgrade renders
<release>-xray-rabbitmq-credswithxray_adminand the new password, renders the definitions, restarts the RabbitMQ pods one at a time, and starts Xray again. -
Verify (C.5). In addition to the C.5 checks, confirm that Xray's secret has the new user and password. Expect
xray_admin, then two matching checksums:kubectl -n <ns> get secret <release>-xray-rabbitmq-creds -o jsonpath='{.data.username}' | base64 -d kubectl -n <ns> get secret <release>-xray-rabbitmq-creds -o jsonpath='{.data.password}' | base64 -d | sha256sum printf '%s' "$RMQ_PASSWORD" | sha256sumRun the health check in
<release>-xray-0, containerrouter. The old cookie to test with issecretcookieif you never changed it. -
Delete
admin(C.6). It is the platform chart's default user, with the well-known passwordpassword, andrabbitmq.confallows it to log in from other hosts.kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl delete_user admin kubectl -n <ns> rollout restart sts/<release>-rabbitmq kubectl -n <ns> rollout status sts/<release>-rabbitmq kubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl list_usersExpect only
xray_admin. Then check thatadminis refused. It must print401; repeat it with the new password and withpassword:kubectl -n <ns> exec <release>-xray-0 -c router -- curl -s -o /dev/null -w '%{http_code}\n' -u "admin:$OLD_PASS" http://<release>-rabbitmq:15672/api/whoami -
After every future
helm upgrade, follow C.7 with these names.
Rollback follows Rollback (C.10), with these changes: create admin again instead of guest, with permissions on xray and xray_haq, and run helm upgrade with jfrog/jfrog-platform.
C.9 Troubleshooting
| Symptom | Likely cause | Action |
|---|---|---|
You changed rabbitmq.auth.password or erlangCookie in your values and ran helm upgrade, but RabbitMQ and Xray still use the old values | The chart keeps the existing values of the <release>-rabbitmq secret on upgrades | Change the secret directly while RabbitMQ is scaled to 0 (C.2 to C.4) |
helm upgrade fails in the pre-upgrade hook with Rabbitmq zero pod ... is not in Ready state | RabbitMQ was scaled to 0 when you ran the upgrade | Start RabbitMQ with kubectl scale (C.3 step 4), wait until it is ready, and run helm upgrade again |
Xray cannot connect after helm upgrade or after RabbitMQ restarts; authenticate_user with the secret's password fails | rabbitmq.auth.password in your values differs from the secret, and RabbitMQ set the values' password when it imported its definitions on start; or rabbitmq-auth.yaml was not passed, so the user went back to guest | Make the password in rabbitmq-auth.yaml equal to the secret's, run helm upgrade with -f rabbitmq-auth.yaml, and restart RabbitMQ (kubectl rollout restart sts/<release>-rabbitmq) |
| RabbitMQ pods cannot form a cluster after the secret was changed | The cookie in the secret was changed while RabbitMQ was running, so pods with different cookies ran at the same time | Scale RabbitMQ to 0 and back (C.3 steps 1 and 4) |
RabbitMQ pod 0 waits with Waiting for Mnesia tables, and the other pods do not start | With podManagementPolicy: OrderedReady, pod 1 starts only after pod 0 is ready, while pod 0 waits for its peers | Wait for the retry window to pass, or switch to podManagementPolicy: Parallel. Changing the policy requires recreating the StatefulSet; the chart's rabbitmq.migration.deleteStatefulSetToAllowFieldUpdate setting does this during helm upgrade. Try it in a non-production environment first. |
C.10 Rollback
- Stop Xray and RabbitMQ as in C.2 and C.3 step 1.
- Write the old password and cookie back into the secret, as in C.3 step 2, with
$OLD_PASSand$OLD_COOKIE.helm upgradealone does not change the secret. - Start RabbitMQ with
kubectl scale(C.3 step 4) and wait until it is ready. - If
guestwas already deleted (C.6), create it again, withkubectl -n <ns> exec <release>-rabbitmq-0 -c rabbitmq -- rabbitmqctl ...:add_user guest "$OLD_PASS",set_user_tags guest administrator, andset_permissionson/andxray_haq. - Run
helm upgradewith your values from before the change (values-backup.yamlfrom C.0), withoutrabbitmq-auth.yaml. This sets the user name back toguest, renders the definitions with the old password, and starts Xray again. - Check that
authenticate_user guest "$OLD_PASS"printsSuccess, that the connections showguest, and that Xray isHEALTHY.
C.11 Clean Up
-
Clear the values from your shell and turn history back on:
unset RMQ_PASSWORD RMQ_COOKIE OLD_PASS OLD_COOKIE set -o history -
When the change is confirmed, delete the backups that contain secrets (
values-backup.yamlandrabbitmq-secret-backup.yaml), or move them to secure storage. -
Record the change in your change-management system: date, layout (single node, multi-node or split mode), versions, and the result of each check.
Network Access to RabbitMQ Ports (All Platforms)
A new cookie and password reduce the risk, but the RabbitMQ ports must not be reachable from outside networks. Allow them only from the hosts that need them, with a firewall, security groups or Kubernetes network policies:
| Port | Used for | Who may reach it |
|---|---|---|
| 4369 | epmd (Erlang node discovery) | Other RabbitMQ nodes of the same cluster only. Single node: no other host. |
| 25672 | Erlang distribution (node-to-node, protected only by the cookie) | Other RabbitMQ nodes of the same cluster only. Single node: no other host. |
| 35672-35682 | CLI tools (rabbitmqctl) | Other RabbitMQ nodes of the same cluster only. Single node: no other host. |
| 5672 (5671 with TLS) | AMQP | Xray nodes and services only (split mode: the Xray nodes). |
| 15672 | Management UI and API | Administrators only, from a trusted network. |
Notes:
- Docker Compose publishes these ports on the host. Docker's published ports can bypass host firewalls such as
ufworfirewalld, so check that your rules apply to Docker traffic. - Check what is listening:
ss -tlnp | grep -E '4369|25672|35672|5672|15672'. On Helm, usekubectl get svc -n <ns>; RabbitMQ services should not be of typeLoadBalancerorNodePortunless you need it. - Make sure no other software on the host uses these ports, for example containers left over from an earlier Docker Compose installation.
Related Topics
Updated about 1 hour ago
