Security review — findings #sec-3 (MED) + #sec-4 (LOW). PR 2 of the series.
Per your question about per-device Shelly passwords: rejected as overkill — Mosquitto's static passwd/acl model can't scope per-device credentials without a dynamic-auth plugin (mosquitto-go-auth), which isn't worth it at this device count. The real risk is the shared user's ACL, fixed here.
Changes (in the ACL generated by the deployment shim)
shellies: readwrite homeassistant/# → write homeassistant/#. Shelly Gen2 firmwares self-publish HA MQTT-discovery configs, so the grant must stay — but a publish-only client never needs to read the entire discovery/state tree. Write-only keeps discovery working while removing device-inventory recon for a compromised Shelly. (readwrite shellies/# stays — devices publish state and subscribe to command topics.)
sml2mqtt: readwrite sml2mqtt/# → write sml2mqtt/#. Verified publish-only (its config has no subscribe/command topics — only LWT + value publishes).
Deliberately unchanged
open3e keeps readwrite open3e/# — it subscribes to open3e/cmnd (listener mode).
homeassistant/admin keep full access; evcc is already least-privilege.
kustomize build clean. Apply note: the broker is single-replica Recreate, so Flux rolling this = a brief MQTT reconnect (clients auto-reconnect). Post-merge watch: confirm Shelly entities still appear/update in HA (discovery write still works) and the power meter keeps publishing.
Next: #3 TLS cutover to :8883 — bigger and staged (edge-1 first), so I'll outline the sequence before touching live clients.
**Security review — findings #sec-3 (MED) + #sec-4 (LOW).** PR 2 of the series.
Per your question about per-device Shelly passwords: **rejected as overkill** — Mosquitto's static `passwd`/`acl` model can't scope per-device credentials without a dynamic-auth plugin (mosquitto-go-auth), which isn't worth it at this device count. The real risk is the shared user's ACL, fixed here.
## Changes (in the ACL generated by the deployment shim)
- **shellies: `readwrite homeassistant/#` → `write homeassistant/#`.** Shelly Gen2 firmwares self-publish HA MQTT-discovery configs, so the grant must stay — but a publish-only client never needs to *read* the entire discovery/state tree. Write-only keeps discovery working while removing device-inventory **recon** for a compromised Shelly. (`readwrite shellies/#` stays — devices publish state and subscribe to command topics.)
- **sml2mqtt: `readwrite sml2mqtt/#` → `write sml2mqtt/#`.** Verified publish-only (its config has no subscribe/command topics — only LWT + value publishes).
## Deliberately unchanged
- `open3e` keeps `readwrite open3e/#` — it subscribes to `open3e/cmnd` (listener mode).
- `homeassistant`/`admin` keep full access; `evcc` is already least-privilege.
`kustomize build` clean. **Apply note:** the broker is single-replica `Recreate`, so Flux rolling this = a brief MQTT reconnect (clients auto-reconnect). **Post-merge watch:** confirm Shelly entities still appear/update in HA (discovery write still works) and the power meter keeps publishing.
Next: **#3 TLS cutover to :8883** — bigger and staged (edge-1 first), so I'll outline the sequence before touching live clients.
Security review finding #sec-3/#sec-4.
- shellies: `readwrite homeassistant/#` -> `write homeassistant/#`. Shelly Gen2
firmwares self-publish HA MQTT-discovery configs (so the grant must stay),
but a publish-only client never needs to READ the whole discovery/state
tree. Write-only removes device-inventory recon for a compromised Shelly
while keeping discovery working. (`readwrite shellies/#` stays — devices
publish state and subscribe to their command topics.)
- sml2mqtt: `readwrite sml2mqtt/#` -> `write sml2mqtt/#`. The bridge is
publish-only (verified: its config has no subscribe/command topics, only
LWT + value publishes), so it needs write only.
Left as-is deliberately: open3e keeps `readwrite open3e/#` (it subscribes to
open3e/cmnd in listener mode); homeassistant/admin keep full access; evcc is
already least-privilege. Per-device Shelly credentials were considered and
rejected — Mosquitto's static passwd/acl model can't scope them without a
dynamic-auth plugin, which isn't worth it at this device count.
Applying rolls the (single-replica, Recreate) broker -> a brief MQTT
reconnect. kustomize build clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Security review — findings #sec-3 (MED) + #sec-4 (LOW). PR 2 of the series.
Per your question about per-device Shelly passwords: rejected as overkill — Mosquitto's static
passwd/aclmodel can't scope per-device credentials without a dynamic-auth plugin (mosquitto-go-auth), which isn't worth it at this device count. The real risk is the shared user's ACL, fixed here.Changes (in the ACL generated by the deployment shim)
readwrite homeassistant/#→write homeassistant/#. Shelly Gen2 firmwares self-publish HA MQTT-discovery configs, so the grant must stay — but a publish-only client never needs to read the entire discovery/state tree. Write-only keeps discovery working while removing device-inventory recon for a compromised Shelly. (readwrite shellies/#stays — devices publish state and subscribe to command topics.)readwrite sml2mqtt/#→write sml2mqtt/#. Verified publish-only (its config has no subscribe/command topics — only LWT + value publishes).Deliberately unchanged
open3ekeepsreadwrite open3e/#— it subscribes toopen3e/cmnd(listener mode).homeassistant/adminkeep full access;evccis already least-privilege.kustomize buildclean. Apply note: the broker is single-replicaRecreate, so Flux rolling this = a brief MQTT reconnect (clients auto-reconnect). Post-merge watch: confirm Shelly entities still appear/update in HA (discovery write still works) and the power meter keeps publishing.Next: #3 TLS cutover to :8883 — bigger and staged (edge-1 first), so I'll outline the sequence before touching live clients.