Linux Mosquitto MQTT Clients 與 公用Broker 驗証 這篇文章裡有提到如何用官方的 Server 來做憑証的連線測試,那時為求方便快速,直接使用官方的。最近測試的時候,發線常常會斷線,只好來認真研究一下怎麼自己架設了,也是以憑証的方式來連線。
伺服器
由於我做的是 LTE 的 MQTT Client, 所以沒辦法做 local 的測試,一定要找台有實際 IP 的機器才行。立馬就想到用 Google Cloud Platform (GCP),價格便宜,最低價方案用整個月約5 USD/M而且還可以有獨立 IP,它是以小時計費的,所以短期用一下費用不貴。剛申請的話還可以試用一陣子,不過之前已試用過了…就只好花點錢了。最後我只用了一天做完了所有的測試,只花了 0.8 USD。
安裝環境
本文安裝/測試的環境,有一些假設,基本上是為了測試方便。
- MQTT Server (Broker) / Client (Publisher, Subscriber) 都是在同一台機器上執行。
- 使用 Ubuntu 16.04 x64
- MQTT Server 安裝操作都是用 root 身份執行,這樣命令貼起來簡潔些。Client 則用一般 user 即可
- 有2個預設的環境變數,方便貼命令也可以客制化。
export PASS=1234 #rootCA 的密碼
export SERVER=35.201.211.5 #MQTT Server 的IP或domain name, 憑証 Common Name 會用到
套件安裝
安裝完 Ubuntu 16.04 x64 後,需要安裝 mosquitto 套件,另外順便也把 ssh-server 安裝好,方便操作 (假設已用root登入)
1 2 3 |
# with root apt-get update apt-get install mosquitto mosquitto-clients openssh-server |
Mosquitto Broker 設定指令
Broker 的指令,已經把它整理到最精簡了,只需貼上命令即可。這邊記住前面提到的 export PASS SERVER 的部份要設定好。產生出來的 CA 憑証 (ca.crt),會複製一份到 /tmp 去。再稍後的 Client 安裝,會用到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# with root cd;mkdir server; cd server openssl genrsa -des3 -out ca.key -passout pass:${PASS} 2048 openssl req -new -x509 -days 1826 -key ca.key -out ca.crt -passin pass:${PASS} -subj "/CN=rootCA/O=example.com" openssl genrsa -out server.key 2048 openssl req -new -out server.csr -key server.key -subj "/CN=${SERVER}" openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 360 -passin pass:${PASS} cp ca.crt server.crt server.key /etc/mosquitto/certs/ echo "pid_file /var/run/mosquitto.pid" > /etc/mosquitto/mosquitto.conf echo "persistence true" >> /etc/mosquitto/mosquitto.conf echo "persistence_location /var/lib/mosquitto/" >> /etc/mosquitto/mosquitto.conf echo "log_dest file /var/log/mosquitto/mosquitto.log" >> /etc/mosquitto/mosquitto.conf echo "include_dir /etc/mosquitto/conf.d" >> /etc/mosquitto/mosquitto.conf echo "port 8883" >> /etc/mosquitto/mosquitto.conf echo "cafile /etc/mosquitto/certs/ca.crt" >> /etc/mosquitto/mosquitto.conf echo "keyfile /etc/mosquitto/certs/server.key" >> /etc/mosquitto/mosquitto.conf echo "certfile /etc/mosquitto/certs/server.crt" >> /etc/mosquitto/mosquitto.conf echo "require_certificate true" >> /etc/mosquitto/mosquitto.conf echo "log_type debug" >> /etc/mosquitto/mosquitto.conf /etc/init.d/mosquitto restart cp ca.crt /tmp # for client |
Mosquitto Client 產生憑証和 CSR
Client 產生憑証後,會需要給 Server (Broker) 簽署,所以會產生一個 CSR (Cert Sign Reuqest) 檔案。我們會將其複製到 /tmp/ ,再由憑 Broker 簽署。
1 2 3 4 5 |
# with normal user cd ; mkdir client;cd client openssl genrsa -out client.key 2048 openssl req -new -out client.csr -key client.key -subj "/CN=client/O=example.com" cp client.csr /tmp |
Mosquitto Broker 簽署 CSR
Broker 簽署在/tmp下的 CSR 後,會產生一個 /tmp/client.crt,稍後再由 Client 取回去,就算完成流程了。
1 2 3 |
# with root cd; cd server openssl x509 -req -in /tmp/client.csr -CA ca.crt -CAkey ca.key -CAserial ./ca.srl -out /tmp/client.crt -days 3650 -passin pass:${PASS} |
Mosquitto Client 取回 CA & Client Cert
1 2 3 |
# with normal user cd;cd client cp /tmp/client.crt /tmp/ca.crt . |
經過以上命令,所需的雙方憑証就都已經產生完成,下面就是示範 Publish 和 Subscribe 的命令。Subscriber 和 Publisher 最好是分成兩個 terminal 來執行,這樣會比較容易觀察結果。
Client Subscribe
1 2 3 |
# with normal user cd ; cd client mosquitto_sub -h ${SERVER} -p 8883 -t topic --cafile ca.crt --cert client.crt --key client.key |
Client Publish
這邊 publish 後,上面的 subscriber 應該就會看到訊息 “abc” 了
1 2 3 |
# with normal user cd ; cd client mosquitto_pub -h ${SERVER} -t topic -m abc --cafile ca.crt -p 8883 --cert client.crt --key client.key |
觀察 Broker Log
Client 的連線、斷線、 PING/PINGRSP 都可以透過 Log 來觀察
1 2 |
# with root tail -f /var/log/mosquitto/mosquitto.log |
其它
在產生憑証的過程中 -subj “/CN=XXX” 的名字最好都不同,至少 rootCA 和 client 要不同。不然在連線時會發生失敗,因為 Log 不多,其實也不太好查,也是上網找才發現解法的。
參考資料
Google Compute Engine 建立 VM 及使用 putty 登入
http://rockingdlabs.dunmire.org/exercises-experiments/ssl-client-certs-to-secure-mqtt
http://www.steves-internet-guide.com/mosquitto-tls/
https://mosquitto.org/man/mosquitto-conf-5.html
看這個樣子 都是本地簽屬 根本地測試 可是我用 另外一端client產生憑證 給server簽過後
把生出來的憑證 用http的方式傳給client client卻無法跟server溝通耶 請問這是為甚麼 OAO
歐歐歐 我找到原因了 我忘記複製ca.crt 了 QAQ