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

toolcontainer-sec-derive 0.7.0
observerdrop-test
validated imagedocker.io/library/rabbitmq@sha256:345dd3c11d67…
validated date2026-07-16
confidencehigh
validated viadrop-test, ci-smoke
workloadprofiles/workloads/rabbitmq.sh
workload sha25630930ad9a33f…
ig versionv0.51.0

Drop-test evidence

Each candidate removed in turn, the container restarted, and the workload re-verified.

RemovedVerdictObserved
CHOWNremovablecorrect: publish/consume round-trip ok, beam.smp uid=999 (non-root)
DAC_OVERRIDEremovablecorrect: publish/consume round-trip ok, beam.smp uid=999 (non-root)
FSETIDremovablecorrect: publish/consume round-trip ok, beam.smp uid=999 (non-root)
FOWNERremovablecorrect: publish/consume round-trip ok, beam.smp uid=999 (non-root)
MKNODremovablecorrect: publish/consume round-trip ok, beam.smp uid=999 (non-root)
NET_RAWremovablecorrect: publish/consume round-trip ok, beam.smp uid=999 (non-root)
SETGIDrequiredcontainer failed to start: error: failed switching to "rabbitmq": operation not permitted
SETUIDrequiredcontainer failed to start: error: failed switching to "rabbitmq": operation not permitted
SETFCAPremovablecorrect: publish/consume round-trip ok, beam.smp uid=999 (non-root)
SETPCAPremovablecorrect: publish/consume round-trip ok, beam.smp uid=999 (non-root)
NET_BIND_SERVICEremovablecorrect: publish/consume round-trip ok, beam.smp uid=999 (non-root)
SYS_CHROOTremovablecorrect: publish/consume round-trip ok, beam.smp uid=999 (non-root)
KILLremovablecorrect: publish/consume round-trip ok, beam.smp uid=999 (non-root)
AUDIT_WRITEremovablecorrect: 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_optno-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

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)"}