Files
lmxopcua/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Mqtt.IntegrationTests/Docker/mosquitto.conf
T
Joseph Doherty 033b3700c4 test(mqtt): Mosquitto TLS+auth fixture + env-gated plain live suite
Adds the MQTT driver integration-test project: an eclipse-mosquitto fixture running
auth AND TLS (allow_anonymous false on both listeners), a mosquitto_pub-based JSON
publisher emitting retained messages, a cert/password generator script whose output is
gitignored, and a live suite gated on MQTT_FIXTURE_ENDPOINT that skips clean offline.

The fixture is never anonymous by design: an anonymous broker would let the driver's
TLS/CA-pin and auth paths go untested, and those fail silently. The CA-pin leg carries
its own falsifiability control (a foreign CA generated in-process must be rejected).

Live gate on 10.100.0.35: 7/7 passed. It found a driver defect, reported not fixed
here (src/ is out of this task's scope): MqttConnection.ConnectAsync RETURNS NORMALLY
when Mosquitto rejects a CONNECT as not-authorized -- MQTTnet 5 does not throw on an
unsuccessful CONNACK, so a wrong broker password yields DriverState.Healthy from
InitializeAsync. The auth-negative test therefore asserts the invariant that holds
either way (no session is ever established) and documents the finding.

Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
2026-07-24 17:49:14 -04:00

66 lines
3.0 KiB
Plaintext

# Eclipse Mosquitto configuration for the OtOpcUa MQTT driver integration fixture.
#
# SECURITY POSTURE — deliberate, and the whole reason this fixture exists.
# `allow_anonymous false` is set GLOBALLY (with per_listener_settings false), so it
# governs BOTH listeners. An anonymous fixture would let the driver's auth and TLS
# code paths — including the CA-pin logic in MqttConnection.ConfigureTls /
# ValidateAgainstPinnedCa — go completely untested, which is exactly backwards: those
# are the paths whose failure mode is silent (a pin that never rejects anything looks
# identical to a pin that works).
#
# The password file and the TLS material are NOT in git. Generate them first with
# `./gen-fixture-material.sh` (see that script's banner); it writes ./secrets/, which
# .gitignore excludes.
# One global security policy rather than per-listener ones: with
# per_listener_settings true, `allow_anonymous`/`password_file` would have to be
# repeated under EVERY listener block, and a listener that forgot them would silently
# fall back to allowing anonymous connections. Global + fail-closed is the safer shape.
per_listener_settings false
allow_anonymous false
password_file /mosquitto/secrets/passwd
# No persistence: the fixture is throwaway, and a persisted retained-message store
# surviving a `docker compose down` would make the retained-seed test's outcome depend
# on a previous run rather than on this one's publisher.
persistence false
log_dest stdout
log_type error
log_type warning
log_type notice
log_type information
connection_messages true
# ---------------------------------------------------------------------------
# Plain (non-TLS) listener — smoke only.
#
# Still authenticated (allow_anonymous false above applies here too); it is the
# TRANSPORT that is plaintext, not the access policy. It exists so the subscribe /
# retained-seed / unauthored-topic legs can be exercised without dragging the TLS
# handshake into every assertion, and so an operator can `mosquitto_sub` the fixture
# by hand. Never a model for a deployment.
# ---------------------------------------------------------------------------
listener 1883 0.0.0.0
protocol mqtt
# ---------------------------------------------------------------------------
# TLS listener — the real one.
#
# `require_certificate false`: the driver authenticates with username/password over
# TLS (the shape MqttDriverOptions models today); mutual TLS is not a driver feature
# yet, so demanding a client certificate here would make the fixture untestable rather
# than more secure.
#
# tls_version is deliberately NOT pinned: mosquitto's `tls_version` selects exactly
# one version, so pinning 1.2 would refuse a .NET client that negotiated 1.3. Leaving
# it unset lets OpenSSL negotiate the best mutually-supported version.
# ---------------------------------------------------------------------------
listener 8883 0.0.0.0
protocol mqtt
cafile /mosquitto/secrets/ca.crt
certfile /mosquitto/secrets/server.crt
keyfile /mosquitto/secrets/server.key
require_certificate false