catalog / docker.io/library/eclipse-mosquitto

docker.io/library/eclipse-mosquitto

validated  pin current  tags: 2.0

eclipse-mosquitto — minimum capabilities AND read-only filesystem, derived
by drop-test against the default invocation (the image's bundled config:
listener 1883, anonymous local use). Capabilities trim 14 -> 2; the
filesystem locks read_only with no tmpfs.

capabilities: cap_drop:[ALL] + cap_add:[SETGID, SETUID] — the catalog's
third privilege-drop shape: the BROKER ITSELF setuid/setgids to its
mosquitto user in-process when started as root (not a gosu re-exec, not a
master/worker fork). Dropping either cap fails startup with mosquitto's own
"Error setting uid/groups whilst dropping privileges". The listener is the
unprivileged :1883 — no NET_BIND_SERVICE under any sysctl posture.

filesystem: read_only:true, tmpfs:[] — /mosquitto/data and /mosquitto/log
are declared VOLUMEs (persistent in real deployments, never tmpfs; docker
mounts them writable under read_only); /tmp derived not required.

Both dimensions validated together; they apply as a unit. See
criteria/docker.io/library/eclipse-mosquitto.md.

Use it

services:
  eclipse-mosquitto:
    image: docker.io/library/eclipse-mosquitto:2.0
    cap_drop: [ALL]
    cap_add: [SETGID, SETUID]
    security_opt: ["no-new-privileges:true"]
    read_only: true

This profile has multiple dimensions and is applied as a unit. Dimensions can interact — a capability can be required only because of a sibling read-only/tmpfs recommendation — so where they do, the minimum was derived under the sibling dimension's context. See the criteria doc and each dimension's recorded invocation below before applying them separately.

Dimension: capabilities

cap_drop: ALL + cap_add: SETGID, SETUID

toolcontainer-sec-derive 0.7.0
observerdrop-test
validated imagedocker.io/library/eclipse-mosquitto@sha256:212f89e1eaeb…
validated date2026-07-16
confidencehigh
validated viadrop-test, ci-smoke
workloadprofiles/workloads/mosquitto.sh
workload sha256f82b6e4cc300…
ig versionv0.51.0

Drop-test evidence

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

RemovedVerdictObserved
CHOWNremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (non-root)
DAC_OVERRIDEremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (non-root)
FSETIDremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (non-root)
FOWNERremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (non-root)
MKNODremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (non-root)
NET_RAWremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (non-root)
SETGIDrequiredcontainer failed to start: Error setting groups whilst dropping privilege
SETUIDrequiredcontainer failed to start: Error setting uid whilst dropping privileges: Operation not permitted.
SETFCAPremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (non-root)
SETPCAPremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (non-root)
NET_BIND_SERVICEremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (non-root)
SYS_CHROOTremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (non-root)
KILLremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (non-root)
AUDIT_WRITEremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (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/mosquitto.sh)
#!/usr/bin/env bash
# Workload exerciser for the eclipse-mosquitto reference image.
#
# A real publish/subscribe round-trip via the in-image mosquitto_sub /
# mosquitto_pub clients: the subscriber runs in the foreground printing the
# one expected message to stdout, the publisher fires after a beat from the
# background. Probes exec as --user mosquitto so they cannot pollute a caps
# minimum, and NOTHING is written inside the container — a probe temp file
# under /tmp would derive the filesystem dimension's /tmp candidate
# falsely-required. The broker's own in-process privilege drop is asserted by
# the drop-test correctness check (see the criteria doc).
#
# Required env: MOSQUITTOCONTAINER (target container name or id).
set -euo pipefail

: "${MOSQUITTOCONTAINER:?MOSQUITTOCONTAINER must be set}"
C="${MOSQUITTOCONTAINER}"

deadline=$((SECONDS + 20))
# 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 "mosquitto version .* running" <<<"$(docker logs "$C" 2>&1)"; do
    (( SECONDS >= deadline )) && { echo "broker never reported running" >&2; exit 1; }
    sleep 1
done

got="$(docker exec --user mosquitto "$C" sh -c '
  (sleep 1; mosquitto_pub -h 127.0.0.1 -t csd/probe -m csd-42 2>/dev/null) &
  mosquitto_sub -h 127.0.0.1 -t csd/probe -C 1 -W 10 2>/dev/null' 2>/dev/null)"
if [ "$got" != "csd-42" ]; then
    echo "pub/sub round-trip failed (got: ${got:-nothing})" >&2
    exit 1
fi

Dimension: filesystem

read_only: true, no tmpfs

toolcontainer-sec-derive 0.7.0
observerdrop-test
validated imagedocker.io/library/eclipse-mosquitto@sha256:212f89e1eaeb…
validated date2026-07-16
confidencehigh
validated viadrop-test, ci-smoke
workloadprofiles/workloads/mosquitto.sh
workload sha256f82b6e4cc300…
ig versionv0.51.0

Drop-test evidence

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

RemovedVerdictObserved
/tmpremovablecorrect: pub/sub round-trip ok, mosquitto uid=1883 (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/mosquitto.sh)
#!/usr/bin/env bash
# Workload exerciser for the eclipse-mosquitto reference image.
#
# A real publish/subscribe round-trip via the in-image mosquitto_sub /
# mosquitto_pub clients: the subscriber runs in the foreground printing the
# one expected message to stdout, the publisher fires after a beat from the
# background. Probes exec as --user mosquitto so they cannot pollute a caps
# minimum, and NOTHING is written inside the container — a probe temp file
# under /tmp would derive the filesystem dimension's /tmp candidate
# falsely-required. The broker's own in-process privilege drop is asserted by
# the drop-test correctness check (see the criteria doc).
#
# Required env: MOSQUITTOCONTAINER (target container name or id).
set -euo pipefail

: "${MOSQUITTOCONTAINER:?MOSQUITTOCONTAINER must be set}"
C="${MOSQUITTOCONTAINER}"

deadline=$((SECONDS + 20))
# 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 "mosquitto version .* running" <<<"$(docker logs "$C" 2>&1)"; do
    (( SECONDS >= deadline )) && { echo "broker never reported running" >&2; exit 1; }
    sleep 1
done

got="$(docker exec --user mosquitto "$C" sh -c '
  (sleep 1; mosquitto_pub -h 127.0.0.1 -t csd/probe -m csd-42 2>/dev/null) &
  mosquitto_sub -h 127.0.0.1 -t csd/probe -C 1 -W 10 2>/dev/null' 2>/dev/null)"
if [ "$got" != "csd-42" ]; then
    echo "pub/sub round-trip failed (got: ${got:-nothing})" >&2
    exit 1
fi

Evidence & provenance

Raw profile YAML
# eclipse-mosquitto — minimum capabilities AND read-only filesystem, derived
# by drop-test against the default invocation (the image's bundled config:
# listener 1883, anonymous local use). Capabilities trim 14 -> 2; the
# filesystem locks read_only with no tmpfs.
#
# capabilities: cap_drop:[ALL] + cap_add:[SETGID, SETUID] — the catalog's
# third privilege-drop shape: the BROKER ITSELF setuid/setgids to its
# mosquitto user in-process when started as root (not a gosu re-exec, not a
# master/worker fork). Dropping either cap fails startup with mosquitto's own
# "Error setting uid/groups whilst dropping privileges". The listener is the
# unprivileged :1883 — no NET_BIND_SERVICE under any sysctl posture.
#
# filesystem: read_only:true, tmpfs:[] — /mosquitto/data and /mosquitto/log
# are declared VOLUMEs (persistent in real deployments, never tmpfs; docker
# mounts them writable under read_only); /tmp derived not required.
#
# Both dimensions validated together; they apply as a unit. See
# criteria/docker.io/library/eclipse-mosquitto.md.
schema_version: "1.5"
image: docker.io/library/eclipse-mosquitto
reference_url: https://tmatens.github.io/container-security-profiles/profiles/docker.io/library/eclipse-mosquitto.html
applies_to:
  tags: ["2.0"]
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/eclipse-mosquitto@sha256:212f89e1eaeb2c322d6441b64396e3346026674db8fa9c27beac293405c32b3c
      validated_date: "2026-07-16"
      duration_seconds: 180
      confidence: high
      workload: profiles/workloads/mosquitto.sh
      workload_sha256: "f82b6e4cc300fb546dc0d741f91c41f1267af7f58386e4bf35007d85ffab235b"
      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: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
          - {removed: DAC_OVERRIDE, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
          - {removed: FSETID, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
          - {removed: FOWNER, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
          - {removed: MKNOD, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
          - {removed: NET_RAW, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
          - {removed: SETGID, required: true, observed: "container failed to start: Error setting groups whilst dropping privilege"}
          - {removed: SETUID, required: true, observed: "container failed to start: Error setting uid whilst dropping privileges: Operation not permitted."}
          - {removed: SETFCAP, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
          - {removed: SETPCAP, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
          - {removed: NET_BIND_SERVICE, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
          - {removed: SYS_CHROOT, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
          - {removed: KILL, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
          - {removed: AUDIT_WRITE, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}
  filesystem:
    read_only: true
    tmpfs: []
    derivation:
      tool: container-sec-derive
      tool_version: "0.7.0"
      sidecar_schema_version: "1.5"
      observer: drop-test
      validated_image: docker.io/library/eclipse-mosquitto@sha256:212f89e1eaeb2c322d6441b64396e3346026674db8fa9c27beac293405c32b3c
      validated_date: "2026-07-16"
      duration_seconds: 60
      confidence: high
      workload: profiles/workloads/mosquitto.sh
      workload_sha256: "f82b6e4cc300fb546dc0d741f91c41f1267af7f58386e4bf35007d85ffab235b"
      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: /tmp, required: false, observed: "correct: pub/sub round-trip ok, mosquitto uid=1883 (non-root)"}