mosquitto: add DoS/resource guards (broker hardening) #128

Merged
k.renner merged 1 commits from feat/mosquitto-dos-guards into master 2026-07-08 08:14:42 +00:00
Owner

Continuing the MQTT security work. The broker had no resource limits at all, and it's now load-bearing + reachable by ~30 untrusted IoT devices (the Shelly fleet) + the edge host on a single 256Mi replica — so a misbehaving/compromised client is a real DoS vector against a critical service.

Adds three guards, all set well above real usage:

  • message_size_limit 1048576 — MQTT permits up to 256 MB per publish; one such message would OOM the broker. Every legit payload here (HA discovery, Shelly/open3e/evcc telemetry) is <10 KB.
  • persistent_client_expiration 1d — reap abandoned persistent sessions (the edge bridges reconnect within seconds, so they never hit this).
  • max_connections 200 per listener — bound a connection flood (~40 clients today; generous headroom vs the previous unlimited).

kubectl kustomize builds clean.

Context / status of the MQTT security work

  • ✅ #sec-1 (plaintext on the untrusted IoT VLAN): edge-1 + all 28 Gen2+ Shellies now on TLS; netpol scoped (#125), ACLs least-privilege (#126).
  • ⚠️ 5 Gen1 Shellies remain plaintext — firmware-locked, pending hardware replacement (list provided separately). This blocks fully closing LB-:1883.
  • ⏹️ HA/evcc → TLS: not pursued — verified in-cluster mqtt.k.renner.uno resolves to the public proxy, so in-cluster TLS needs CoreDNS+cert plumbing for marginal benefit (they're pod-to-pod, never on the untrusted VLAN).

Apply

The ConfigMap has no checksum annotation, so Flux won't roll the pod on config change — after reconcile it needs kubectl -n home-assistant rollout restart deploy/mosquitto (brief reconnect; clients auto-reconnect).

Continuing the MQTT security work. The broker had **no resource limits at all**, and it's now load-bearing + reachable by ~30 untrusted IoT devices (the Shelly fleet) + the edge host on a single 256Mi replica — so a misbehaving/compromised client is a real DoS vector against a critical service. Adds three guards, all set well above real usage: - **`message_size_limit 1048576`** — MQTT permits up to **256 MB** per publish; one such message would OOM the broker. Every legit payload here (HA discovery, Shelly/open3e/evcc telemetry) is <10 KB. - **`persistent_client_expiration 1d`** — reap abandoned persistent sessions (the edge bridges reconnect within seconds, so they never hit this). - **`max_connections 200`** per listener — bound a connection flood (~40 clients today; generous headroom vs the previous *unlimited*). `kubectl kustomize` builds clean. ## Context / status of the MQTT security work - ✅ #sec-1 (plaintext on the untrusted IoT VLAN): **edge-1 + all 28 Gen2+ Shellies now on TLS**; netpol scoped (#125), ACLs least-privilege (#126). - ⚠️ **5 Gen1 Shellies** remain plaintext — firmware-locked, pending hardware replacement (list provided separately). This blocks fully closing LB-`:1883`. - ⏹️ **HA/evcc → TLS: not pursued** — verified in-cluster `mqtt.k.renner.uno` resolves to the public proxy, so in-cluster TLS needs CoreDNS+cert plumbing for marginal benefit (they're pod-to-pod, never on the untrusted VLAN). ## Apply The ConfigMap has no checksum annotation, so Flux won't roll the pod on config change — after reconcile it needs `kubectl -n home-assistant rollout restart deploy/mosquitto` (brief reconnect; clients auto-reconnect).
k.renner added 1 commit 2026-07-08 08:11:37 +00:00
The broker had no resource limits at all. It's now load-bearing and reachable
by ~30 untrusted IoT devices (the Shelly fleet) + the edge host on a single
256Mi replica, so a misbehaving/compromised client is a real DoS vector.

Add:
- message_size_limit 1048576 — MQTT permits up to 256 MB per publish; one such
  message would OOM the broker. Every legit payload here (HA discovery,
  Shelly/open3e/evcc telemetry) is <10 KB.
- persistent_client_expiration 1d — reap abandoned persistent sessions (the
  edge bridges reconnect within seconds, so they never hit this).
- max_connections 200 per listener — bound a connection flood (~40 clients
  today; generous headroom, not the previous unlimited).

All values chosen well above real usage, so no legit client is affected.

Apply: the ConfigMap has no checksum annotation, so Flux won't restart the pod
on its own — needs `kubectl -n home-assistant rollout restart deploy/mosquitto`
(brief reconnect; clients auto-reconnect) after reconcile.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
k.renner merged commit 88871f6315 into master 2026-07-08 08:14:42 +00:00
Sign in to join this conversation.