feat(S2-a): ingest durable app MQTT points securely
This commit is contained in:
@@ -8,14 +8,16 @@ describes from a usage/dashboard perspective.
|
||||
## Overview
|
||||
|
||||
The broker (`eclipse-mosquitto`, service `mqtt` / container `ul-hub-mqtt`)
|
||||
exposes four listeners, each with a different trust model:
|
||||
exposes three listeners, each with a different trust model:
|
||||
|
||||
| Port | Protocol | Auth | Who it's for |
|
||||
|------|----------|------|---------------|
|
||||
| `1883` | MQTT (plaintext) | username/password | internal services (e.g. the Laravel subscriber, Python publisher) |
|
||||
| `9001` (mapped to host `9005`) | MQTT over WebSocket | none (anonymous) | browser clients (dashboard) |
|
||||
| `8883` | MQTT over TLS | **client certificate** | field devices |
|
||||
| `8884` | MQTT over TLS | username/password (server cert only) | administrators |
|
||||
| `8884` | MQTT over TLS | username/password (server cert only) | scoped app clients and administrators |
|
||||
|
||||
The former anonymous WebSocket listener on `9001` is disabled. The current web portal receives
|
||||
live updates from the backend rather than connecting directly to Mosquitto.
|
||||
|
||||
Device authentication happens on **port 8883**. A device presents a client
|
||||
certificate signed by the app's own Certificate Authority (CA); Mosquitto
|
||||
@@ -123,6 +125,10 @@ since they all share `acl_file /mosquitto/config/devices.acl`:
|
||||
# Certificate CN becomes the MQTT username — restrict each device to its own namespace.
|
||||
pattern readwrite devices/%u/#
|
||||
|
||||
# App username is orgId; app clients may publish durable points and read acks only in that org.
|
||||
pattern write ul/%u/app/+/log/points
|
||||
pattern read ul/%u/app/+/ack
|
||||
|
||||
# Admin: <username>
|
||||
user <username>
|
||||
topic readwrite #
|
||||
@@ -169,9 +175,9 @@ Managed via the same `/certificates` page:
|
||||
| Client | Listener | Auth | Can publish/subscribe |
|
||||
|---|---|---|---|
|
||||
| Field device (cert CN = serial) | 8883 (TLS) | client cert | `devices/<serial>/#` only |
|
||||
| App (username = orgId) | 8884 (TLS) | scoped per-org username/password | publish `ul/<orgId>/app/+/log/points`; read `ul/<orgId>/app/+/ack` |
|
||||
| Internal service (e.g. subscriber) | 1883 | username/password | depends on ACL entry for that username — none defined by default beyond `devices/%u/#`, so a plain username with no matching device row is effectively scoped to `devices/<username>/#` too, unless added as an admin |
|
||||
| Admin | 8884 (TLS) or 1883 | username/password | `#` and `$SYS/#` (everything) |
|
||||
| Browser dashboard | 9001/9005 (WebSocket) | anonymous | no ACL applied — `allow_anonymous true`, so effectively unrestricted; treat this listener as untrusted/read-only in front-end code |
|
||||
|
||||
## Known gaps
|
||||
|
||||
@@ -180,5 +186,5 @@ Managed via the same `/certificates` page:
|
||||
needs to be production-grade.
|
||||
- No automatic reload of `mosquitto.conf`/ACL/passwd changes — every
|
||||
provisioning action requires a manual `docker compose restart mqtt`.
|
||||
- The WebSocket listener (9001) is fully anonymous with no ACL, so anything
|
||||
reachable on port 9005 should be treated as public.
|
||||
- Sprint 2's per-org app credential permits ack visibility across clients in the same org. This
|
||||
accepted interim limitation is removed when OIDC-derived per-client broker identity lands.
|
||||
|
||||
Reference in New Issue
Block a user