2026-09-19 13:05:38 +02:00
2026-09-19 12:34:37 +02:00
🚧 WIP
2026-09-19 09:40:24 +02:00
2026-09-19 12:34:37 +02:00
🚧 WIP
2026-09-19 09:40:24 +02:00
🚧 WIP
2026-09-16 06:08:37 +02:00
🚧 WIP
2026-09-16 06:08:37 +02:00
2026-09-19 12:34:37 +02:00
🚧 WIP
2026-09-16 06:08:37 +02:00
2026-09-19 13:05:38 +02:00
🚧 WIP
2026-09-16 06:08:37 +02:00

MQTT Management Platform — Release 1

Web-based administration for an Eclipse Mosquitto 2.1 broker: management login/RBAC, MQTT client/group/role management with ACL editing via the Dynamic Security plugin, and generated + validated broker configuration.

Architecture and scope follow specification.md (Release 1, §68.1).

Stack

mqtt-frontend   React (Vite build) served by nginx, proxies /api → backend
mqtt-backend    FastAPI: management auth, RBAC, dynsec client, config engine
mosquitto       Eclipse Mosquitto 2.1.2 (pinned), dynsec enabled
mosquitto-control  control sidecar: validate/activate/reload configs
mqtt-db         PostgreSQL (management data only; NOT host-exposed)

Networks: frontend-net (frontend↔backend) and backend-net (backend↔db↔mosquitto↔control). Only the frontend HTTP port is published.

Quick start

cp .env.example .env        # then EDIT the change-me values!
docker compose up -d --build

Open http://localhost:8080 and sign in with ADMIN_INITIAL_USERNAME / ADMIN_INITIAL_PASSWORD from your .env.

Bootstrap sequence on first start:

  1. PostgreSQL starts; backend creates its schema (or run migrations explicitly, see below) and seeds the management admin.
  2. Mosquitto starts with mosquitto/bootstrap/mosquitto.conf on the internal network; the dynsec plugin seeds its admin client from MOSQUITTO_DYNSEC_PASSWORD.
  3. Backend connects to dynsec as that admin client — the management channel is alive.
  4. Configuration changes made in the UI are generated from the PostgreSQL model, validated with mosquitto --test-config (via the control sidecar), deployed atomically, and recorded as a revision.

Note for Windows users: the compose healthcheck for mosquitto and the control sidecar rely on Unix facilities (pid: service:, POSIX shell commands); run the stack with Docker Desktop + WSL2 as usual — nothing here assumes a Linux host beyond Docker itself.

Configuration channels (why this design)

  • Dynamic Security (runtime) — clients/groups/roles/ACLs change via the MQTT $CONTROL/dynamic-security/v1 API. No files involved.
  • Generated mosquitto.conf (rare) — listeners/global settings are generated from the DB model and deployed through mosquitto-control, which shares the broker's PID namespace (pid: "service:mosquitto") to signal reloads. No Docker socket is mounted anywhere (spec §29).
  • Mosquitto 2.1's HTTP API is not used as a management channel: it has no authentication and (currently) exposes read-only plugin info.

Development

Backend (in container):

docker compose exec mqtt-backend pytest -q          # API + generator tests
docker compose exec mqtt-backend ruff check app tests
docker compose exec mqtt-backend alembic upgrade head   # explicit migrations

Frontend (local dev server with proxy to backend):

cd frontend && npm install && npm run dev    # http://localhost:5173

Repository layout

compose.yaml            stack definition (5 services, 2 networks)
.env.example            environment template (secrets: edit before use)
mosquitto/bootstrap/    the one file that ships with the deployment
broker-control/         validate / atomic-activate / reload sidecar
backend/                FastAPI app, models, dynsec client, configgen
frontend/               React + Vite SPA served by nginx

Status & TODO — per release plan (specification.md §68)

Progress against the MVP release plan. Checked items are implemented and covered by the test suite / running stack.

Release 1 — Core broker administration (§68.1) — COMPLETE

  • Docker Compose stack (5 services, 2 networks, no Docker socket)
  • Mosquitto 2.1.2 (pinned) + PostgreSQL
  • FastAPI backend + React (Vite) frontend
  • Management authentication (HttpOnly session cookies, Argon2id, ADMIN_INITIAL_* bootstrap, must-change-password flagging; the backend exposes the change-password API — UI enforcement of the forced change is still pending, see Release 3)
  • Management RBAC (super_admin / broker_admin / operator / auditor)
  • Dynamic Security integration (backend as the dynsec admin client)
  • MQTT clients: create / disable / enable / delete, password reset, random passwords (returned exactly once)
  • Groups: create / delete, member + role assignment with priorities
  • Roles: create / delete, ACL editor (all six ACL types, %u/%c substitution, priorities, draft-then-save)
  • Broker configuration editor, basic mode (structured forms + read-only preview of the generated mosquitto.conf)
  • Listener management (port, bind address, protocol, anonymous, max-connections; enable/disable, edit, delete)
  • Configuration validation (mosquitto --test-config via sidecar)
  • Configuration generation from the PostgreSQL model

Hardening done beyond the plan:

  • Management identity protection: the dynsec admin client is hidden from Clients and refuses reset/disable/delete (resetting it kicks every connection using it — including the backend's own control channel)
  • Dynsec channel resilience: disconnects are detected immediately and the MQTT client is rebuilt instead of failing silently
  • Login flow returns to the originally requested page; mid-session expiry redirects to login with a return target
  • Navigation follows spec §57; unimplemented pages are greyed out with the planned release as tooltip

Release 2 — PKI, versioning, and controlled change (§68.2) — PARTIAL

  • Configuration revisions (immutable history; list + detail API and UI)
  • Configuration deployment with health check (dynsec roundtrip probe)
  • Broker reload (mosquitto_signal config-reload via sidecar)
  • mosquitto-control service (validate / atomic activate / signal / broker health)
  • Configuration diff view (revision N-1 → N)
  • Configuration rollback (creates a new revision, §62)
  • Reload-vs-restart classification (§28) — only a restart warning on listener port/bind edits so far, no general classification
  • CA creation (internal CA, import CA)
  • Server certificate generation (CN, SANs, key algorithm)
  • Client certificates (managed-key mode, one-time download)
  • CSR signing
  • Certificate revocation + CRL generation/publishing
  • mTLS listeners (model fields + config generation exist; blocked on PKI — certfile/keyfile cannot be emitted yet)

Release 3 — Operations, safety, and visibility (§68.3) — PARTIAL

  • Audit logging (backend records every privileged action: LOGIN, LOGOUT, CLIENT_, GROUP_, ROLE_, ACL_CHANGED, LISTENER_, BROKER_CONFIG_DEPLOYED, USER_*, …)
  • Client metadata/tags (owner / purpose / tags in PostgreSQL; API accepts them on create)
  • Audit browsing UI (events are recorded; no viewer page yet)
  • Forced password-change UI (backend flag + API exist; the frontend does not enforce must_change_password yet)
  • Client metadata editing in the UI
  • ACL simulator (§15)
  • Dashboard ($SYS monitoring, broker status, §33)
  • Certificate expiry monitoring
  • Backup and restore (logical, encrypted, §45)
  • Configuration drift detection (§48)
  • Last-known-connection tracking + connected-client view (§34)

Post-MVP (§68.4 / §69 / §70) — NOT STARTED

  • Topic explorer / MQTT test client
  • Connection tester + client provisioning wizard
  • Bridge configuration
  • Retained-message administration
  • Certificate expiry alerts
  • Prometheus metrics + external notifications
  • Change approval (four-eyes) workflow
  • Topic namespace / JSON-schema registries, and later Phase-3 items
S
Description
No description provided
Readme
198 KiB
Languages
Python 63.8%
TypeScript 32.5%
CSS 1.8%
Dockerfile 1.2%
Makefile 0.4%
Other 0.2%