catalog / docker.io/library/rabbitmq
docker.io/library/rabbitmq
validated pin current tags: 4.3
rabbitmq — minimum Linux capabilities, derived by drop-test against the default (root-then-drop) invocation. This profile trims the full Docker default cap set 14 -> 2. capabilities: cap_drop:[ALL] + cap_add:[SETGID, SETUID]. The entrypoint starts as root, `find`-chowns /var/lib/rabbitmq (a no-op on the image's pre-owned VOLUME), then re-execs itself as the rabbitmq user via gosu — dropping either cap fails the switch and the container never starts. Both are STARTUP caps, invisible to runtime observation (the mysql/mongo shape). Derivation-harness sharp edges, reproduced on 4.3 and encoded in the workload: never exec a rabbitmq CLI during boot (root Erlang client races the entrypoint for .erlang.cookie -> broker crash), and always exec CLIs as the rabbitmq user (a root probe needs DAC_OVERRIDE/FOWNER of its own and pollutes the minimum — both derived falsely-required before the fix). See criteria/docker.io/library/rabbitmq.md. filesystem: not yet derived. Absence means not tested for this image — not that it cannot run read-only.
Use it
services:
rabbitmq:
image: docker.io/library/rabbitmq:4.3
cap_drop: [ALL]
cap_add: [SETGID, SETUID]
security_opt: ["no-new-privileges:true"]
Dimension: capabilities
cap_drop: ALL + cap_add: SETGID, SETUID
| tool | container-sec-derive 0.7.0 |
|---|---|
| observer | drop-test |
| validated image | docker.io/library/rabbitmq@sha256:345dd3c11d67… |
| validated date | 2026-07-16 |
| confidence | high |
| validated via | drop-test, ci-smoke |
| workload | profiles/workloads/rabbitmq.sh |
| workload sha256 | 30930ad9a33f… |
| ig version | v0.51.0 |
Drop-test evidence
Each candidate removed in turn, the container restarted, and the workload re-verified.
| Removed | Verdict | Observed |
|---|---|---|
CHOWN | removable | correct: publish/consume round-trip ok, beam.smp uid=999 (non-root) |
DAC_OVERRIDE | removable | correct: publish/consume round-trip ok, beam.smp uid=999 (non-root) |
FSETID | removable | correct: publish/consume round-trip ok, beam.smp uid=999 (non-root) |
FOWNER | removable | correct: publish/consume round-trip ok, beam.smp uid=999 (non-root) |
MKNOD | removable | correct: publish/consume round-trip ok, beam.smp uid=999 (non-root) |
NET_RAW | removable | correct: publish/consume round-trip ok, beam.smp uid=999 (non-root) |
SETGID | required | container failed to start: error: failed switching to "rabbitmq": operation not permitted |
SETUID | required | container failed to start: error: failed switching to "rabbitmq": operation not permitted |
SETFCAP | removable | correct: publish/consume round-trip ok, beam.smp uid=999 (non-root) |
SETPCAP | removable | correct: publish/consume round-trip ok, beam.smp uid=999 (non-root) |
NET_BIND_SERVICE | removable | correct: publish/consume round-trip ok, beam.smp uid=999 (non-root) |
SYS_CHROOT | removable | correct: publish/consume round-trip ok, beam.smp uid=999 (non-root) |
KILL | removable | correct: publish/consume round-trip ok, beam.smp uid=999 (non-root) |
AUDIT_WRITE | removable | correct: publish/consume round-trip ok, beam.smp uid=999 (non-root) |
Recorded invocation (run_config)
The minimum is valid for this invocation; a different user:, volume state, or entrypoint can change it.
| security_opt | no-new-privileges:true |
|---|
Workload script (profiles/workloads/rabbitmq.sh)
#!/usr/bin/env bash
# Workload exerciser for the rabbitmq reference image.
#
# Real function = a declare -> publish -> consume round-trip over the
# management API. The plain image ships no AMQP client and no curl, so the
# check enables the bundled rabbitmq_management plugin at runtime (the same
# plugin the -management tag pre-enables) and drives the round-trip from a
# SIDECAR container sharing the target's network namespace — which also
# satisfies the default guest user's loopback-only restriction. Returns 0 on
# success. The non-root privilege-drop (gosu root->rabbitmq) is asserted by
# the drop-test correctness check (see the criteria doc), not here.
#
# TWO SHARP EDGES (both reproduced on rabbitmq:4.3; keep them respected in any
# re-derivation):
# 1. Never exec a rabbitmq CLI during boot — an exec'd root Erlang client
# races the entrypoint for .erlang.cookie creation and crashes the broker.
# Gate on the "Server startup complete" log line first.
# 2. Exec the CLIs as the rabbitmq user (--user rabbitmq), never root — a
# root probe needs DAC_OVERRIDE/FOWNER of its own and pollutes a derived
# minimum.
#
# Required env: RABBITMQCONTAINER (target container name or id).
set -euo pipefail
: "${RABBITMQCONTAINER:?RABBITMQCONTAINER must be set}"
C="${RABBITMQCONTAINER}"
PROBE="${CSD_PROBE_CURL_IMAGE:-curlimages/curl@sha256:c1fe1679c34d9784c1b0d1e5f62ac0a79fca01fb6377cdd33e90473c6f9f9a69}"
sc() { docker run --rm --network "container:${C}" "$PROBE" "$@"; }
deadline=$((SECONDS + 90))
# capture-then-match — `docker logs | grep -q` under pipefail SIGPIPEs the
# producer once the log outgrows the pipe buffer, turning a match into failure.
until grep -q "Server startup complete" <<<"$(docker logs "$C" 2>&1)"; do
(( SECONDS >= deadline )) && { echo "rabbitmq never reached startup complete" >&2; exit 1; }
sleep 2
done
docker exec --user rabbitmq "$C" rabbitmq-plugins enable --online rabbitmq_management >/dev/null 2>&1 \
|| { echo "could not enable rabbitmq_management" >&2; exit 1; }
deadline=$((SECONDS + 30))
until sc -sf -u guest:guest --max-time 5 http://localhost:15672/api/overview >/dev/null 2>&1; do
(( SECONDS >= deadline )) && { echo "management API never came up" >&2; exit 1; }
sleep 1
done
# declare (durable — 4.x rejects transient non-exclusive queues) -> publish -> get.
sc -sf -u guest:guest --max-time 10 -X PUT -H 'content-type: application/json' \
-d '{"durable":true}' http://localhost:15672/api/queues/%2F/csd-probe >/dev/null \
|| { echo "queue declare failed" >&2; exit 1; }
routed="$(sc -s -u guest:guest --max-time 10 -X POST -H 'content-type: application/json' \
-d '{"properties":{},"routing_key":"csd-probe","payload":"csd-42","payload_encoding":"string"}' \
http://localhost:15672/api/exchanges/%2F/amq.default/publish)"
case "$routed" in *'"routed":true'*) ;; *) echo "publish not routed" >&2; exit 1;; esac
got="$(sc -s -u guest:guest --max-time 10 -X POST -H 'content-type: application/json' \
-d '{"count":1,"ackmode":"ack_requeue_false","encoding":"auto"}' \
http://localhost:15672/api/queues/%2F/csd-probe/get)"
case "$got" in *'"payload":"csd-42"'*) ;; *) echo "consume failed" >&2; exit 1;; esac
Dimension: filesystem
Not yet derived — this dimension has not been drop-tested for this image. Absence means not tested, not that a minimum here is infeasible.
Evidence & provenance
- Validation criteria — per-image scenarios and pass criteria
- Profile source in the repository
- Version history — every previously published pin, with the full profile as validated against it
Raw profile YAML
# rabbitmq — minimum Linux capabilities, derived by drop-test against the
# default (root-then-drop) invocation. This profile trims the full Docker
# default cap set 14 -> 2.
#
# capabilities: cap_drop:[ALL] + cap_add:[SETGID, SETUID]. The entrypoint
# starts as root, `find`-chowns /var/lib/rabbitmq (a no-op on the image's
# pre-owned VOLUME), then re-execs itself as the rabbitmq user via gosu —
# dropping either cap fails the switch and the container never starts. Both
# are STARTUP caps, invisible to runtime observation (the mysql/mongo shape).
#
# Derivation-harness sharp edges, reproduced on 4.3 and encoded in the
# workload: never exec a rabbitmq CLI during boot (root Erlang client races
# the entrypoint for .erlang.cookie -> broker crash), and always exec CLIs as
# the rabbitmq user (a root probe needs DAC_OVERRIDE/FOWNER of its own and
# pollutes the minimum — both derived falsely-required before the fix). See
# criteria/docker.io/library/rabbitmq.md.
#
# filesystem: not yet derived. Absence means not tested for this image —
# not that it cannot run read-only.
schema_version: "1.5"
image: docker.io/library/rabbitmq
reference_url: https://tmatens.github.io/container-security-profiles/profiles/docker.io/library/rabbitmq.html
applies_to:
tags: ["4.3"]
status: validated
dimensions:
capabilities:
cap_drop: [ALL]
cap_add: [SETGID, SETUID]
derivation:
tool: container-sec-derive
tool_version: "0.7.0"
sidecar_schema_version: "1.5"
observer: drop-test
validated_image: docker.io/library/rabbitmq@sha256:345dd3c11d67892c7b452fb2237d94f577acb2aa0569c3fd5c9841eb0c1b57fb
validated_date: "2026-07-16"
duration_seconds: 420
confidence: high
workload: profiles/workloads/rabbitmq.sh
workload_sha256: "30930ad9a33f0aaf7426f4091476c844b381388588ca73f841ed067e1d6ada96"
validated_via: [drop-test, ci-smoke]
observation_backend:
ig_version: v0.51.0
gadgets: []
run_config:
user: ""
command: []
entrypoint: ""
network: ""
pid: ""
devices: []
security_opt: ["no-new-privileges:true"]
mounts: []
env: []
drop_test:
checks:
- {removed: CHOWN, required: false, observed: "correct: publish/consume round-trip ok, beam.smp uid=999 (non-root)"}
- {removed: DAC_OVERRIDE, required: false, observed: "correct: publish/consume round-trip ok, beam.smp uid=999 (non-root)"}
- {removed: FSETID, required: false, observed: "correct: publish/consume round-trip ok, beam.smp uid=999 (non-root)"}
- {removed: FOWNER, required: false, observed: "correct: publish/consume round-trip ok, beam.smp uid=999 (non-root)"}
- {removed: MKNOD, required: false, observed: "correct: publish/consume round-trip ok, beam.smp uid=999 (non-root)"}
- {removed: NET_RAW, required: false, observed: "correct: publish/consume round-trip ok, beam.smp uid=999 (non-root)"}
- {removed: SETGID, required: true, observed: "container failed to start: error: failed switching to \"rabbitmq\": operation not permitted"}
- {removed: SETUID, required: true, observed: "container failed to start: error: failed switching to \"rabbitmq\": operation not permitted"}
- {removed: SETFCAP, required: false, observed: "correct: publish/consume round-trip ok, beam.smp uid=999 (non-root)"}
- {removed: SETPCAP, required: false, observed: "correct: publish/consume round-trip ok, beam.smp uid=999 (non-root)"}
- {removed: NET_BIND_SERVICE, required: false, observed: "correct: publish/consume round-trip ok, beam.smp uid=999 (non-root)"}
- {removed: SYS_CHROOT, required: false, observed: "correct: publish/consume round-trip ok, beam.smp uid=999 (non-root)"}
- {removed: KILL, required: false, observed: "correct: publish/consume round-trip ok, beam.smp uid=999 (non-root)"}
- {removed: AUDIT_WRITE, required: false, observed: "correct: publish/consume round-trip ok, beam.smp uid=999 (non-root)"}