|
|
MQTT 是很多智慧家庭系統的中樞,而它預設沒有任何安全機制。
更麻煩的是:設錯的時候它不會報錯。權限開太大不會有警告,權限開太小也不會有明顯的錯誤訊息 —— 只是某個服務安靜地收不到某些訊息。
這篇從一份完整可貼的 mosquitto.conf 開始,做到「你能自己證明權限確實生效」。中間有三個地方跟網路上流傳的做法不一樣,那三個都是實際跑過才發現的。

做完這篇你會有什麼
- 一份完整的 mosquitto.conf、一份完整的 ACL 檔,直接複製就能用
- 每個服務一個帳號,各自只碰得到自己那塊
- 一套真的能證明 ACL 生效的驗證方法(而不是看起來像生效)
- 需要跨網段時的 TLS 設定,含自簽憑證的完整產生指令
需要準備的東西
- 一台能跑 Docker 的機器。下面用 192.168.1.20 當它的 IP
- 這台機器上裝好 mosquitto 的命令列工具(下面第四步會用)
---
第一步:先看清楚沒有防護會發生什麼
MQTT 協定本身的設計是「誰都可以訂閱、誰都可以發布」。broker 不解讀內容,也不知道誰該看什麼。
所以一台開放匿名連線的 broker,等於把這三件事一起送出去:
- 訂閱 # 就看得到全部 —— 門窗感測器、人體感測器、門鎖狀態、每一盞燈的開關。連續看幾天就知道你家作息
- 發布指令就能控制 —— 開燈、關警報、開車庫門。HA 那邊看起來就像是你自己按的
- 發一則空訊息就能刪裝置 —— 往 homeassistant/sensor/xxx/config 發空的 retain 訊息,HA 裡那個實體立刻消失
而且這三件事在 HA 的日誌裡都長得跟正常操作一模一樣。
先確認你現在是哪一種狀態
在任何一台同網段的電腦上,不帶帳號密碼試連一次:
- mosquitto_sub -h 192.168.1.20 -p 1883 -t '#' -v
複製代碼
你會看到什麼
- Connection error: Connection Refused: not authorised. → 匿名連線已經關掉了,很好。繼續往下把 ACL 做完
- 游標停住,接著開始刷出訊息 → 你的 broker 現在是完全開放的。往下走第二步
- Error: Connection refused → 1883 沒人聽,broker 沒跑起來
---
第二步:完整的 mosquitto.conf
存成 /opt/mosquitto/config/mosquitto.conf。這份是可以直接用的完整檔,不是片段。
- # ========== 監聽 ==========
- # Mosquitto 2.0 起,沒有這一行的話 broker 只綁 127.0.0.1,
- # 外面完全連不進來,而且啟動日誌看起來一切正常。
- listener 1883
- protocol mqtt
- # ========== 驗證 ==========
- # 2.0 起只要寫了 listener,這個預設就是 false。
- # 明寫出來是為了讓讀設定檔的人不必去記預設值。
- allow_anonymous false
- password_file /mosquitto/config/passwd
- # ========== 授權 ==========
- # 注意:Mosquitto 2.1 起這個選項被標示為棄用(功能搬進 acl-file 外掛),
- # 但選項本身仍然可用,只是啟動時多一行警告。第八步有 2.1 的新做法。
- acl_file /mosquitto/config/acl
- # ========== 持久化 ==========
- # HA 的 MQTT Discovery 完全靠 retain 訊息,這一段不能省,
- # 不然 broker 重開之後 HA 裡的 MQTT 裝置會全部消失。
- persistence true
- persistence_location /mosquitto/data/
- autosave_interval 1800
- # ========== 日誌 ==========
- # log_dest stdout 是給 Docker 用的(docker logs 就看得到)。
- # 不跑容器的話改成 log_dest file /mosquitto/log/mosquitto.log
- log_dest stdout
- log_type error
- log_type warning
- log_type notice
- log_type information
- connection_messages true
- log_timestamp true
- # ========== 限制 ==========
- # 家用環境這三行通常不用動,寫出來是讓你知道有這些旋鈕。
- max_connections -1
- max_queued_messages 1000
- max_keepalive 300
複製代碼
docker-compose.yml(整份)
存成 /opt/mosquitto/docker-compose.yml:
- services:
- mosquitto:
- image: eclipse-mosquitto:2.0.22
- container_name: mosquitto
- restart: unless-stopped
- ports:
- - "1883:1883"
- volumes:
- - ./config:/mosquitto/config
- - ./data:/mosquitto/data
- - ./log:/mosquitto/log
- environment:
- - TZ=Asia/Taipei
複製代碼
⚠ 版號寫死,不要用 latest
目前 eclipse-mosquitto:latest 和 eclipse-mosquitto:2 指向的都是 2.1.2,而 2.0 指向 2.0.22。2.1 改了幾個預設值(單一封包上限從 256MB 降到 2,000,000 位元組),也把 acl_file 標示為棄用。
兩個版本都能用,問題在於「哪天它自己換了」。家用系統最難查的故障就是這種 —— 你什麼都沒改,但行為變了。版號寫死,升級由你決定時機。
---
第三步:建立帳號,一個服務一個
先想好你要幾個帳號。原則很簡單:每一個會連上 broker 的程式,一個帳號。共用帳號的話,其中一個被拿走等於全部被拿走,而且你從日誌看不出是哪一個出問題。
典型的家庭配置:
- homeassistant —— HA 本體,需要全部權限
- zigbee2mqtt —— Zigbee 協調器
- frigate —— 影像辨識
- espdev —— 你自己做的裝置(如果有好幾台,可以再拆細)
- monitor —— 唯讀帳號,給監控用
建立:
|
|