練習 - 部署私人 MQTT 訊息代理程式

已完成

在此練習中,您將瞭解如何安裝自己的 Mosquitto MQTT 訊息代理程式。 本單元是進階主題,假設您已熟悉 Linux。

您可以在 Azure 虛擬機器上執行私人 Mosquitto MQTT 訊息代理程式。 執行私人 MQTT 訊息代理程式可協助您從任何位置安全地連線到 Azure Sphere。

網路終端機與 Altair 模擬器之間的 MQTT 訊息必須使用用戶端憑證簽署和加密。 建立 TLS 憑證最簡單的免費方式,就是建立自我簽署憑證授權單位 (CA) 憑證。 您可以使用自我簽署 CA 憑證來建立用戶端金鑰和憑證。

在 Linux 上安裝 Mosquitto MQTT 訊息代理程式是最簡單的選項,因為大部分的套件管理員都包含最新組建。 使用此練習中的程序來設定執行 Ubuntu 20.04 LTS 的 Azure 虛擬機器。

注意

若要將成本降至最低,MQTT 訊息代理程式可以在一般用途 B1 SKU 虛擬機器上執行,而該虛擬機器在未使用時可以停止。

K21 Academy 的下列部落格文章是在 Azure 上安裝 Ubuntu 伺服器的絕佳指南:在 Azure 中建立和連線 Ubuntu 虛擬機器

建立 Ubuntu 虛擬伺服器

  1. 開啟 Azure 入口網站。 從主要功能表選取 [建立資源]
  2. 搜尋虛擬機器,然後選取 [建立]
  3. 建立資源群組、為您的虛擬機器命名,然後選取位置。 將映像命名為 Ubuntu Server 20.04 LTS Gen 1,並將大小設定為 Standard_B1ls - 1 個 vcpu、0.5 GIB 記憶體。 選取 [SSH 公開金鑰],然後將金鑰組命名為和您的虛擬機器名稱相同。
  4. 選取 [下一步:磁片>],然後選取 [標準 HDD] 或 [標準 SSD LRS]
  5. 選取 [檢閱 + 建立]。
  6. 選取 建立
  7. 下載 SSH 私密金鑰,並將其儲存在您的 ~/.shh 資料夾中。

部署虛擬機器大約需要一分鐘的時間。

設定虛擬機器

  1. 選取 [前往資源] 。

  2. 選取 [未設定 DNS 名稱]。 然後設定 DNS 名稱,並設定所需的閒置逾時值。 建議您增加閒置逾時。

  3. 選取 [儲存]。

  4. 選取瀏覽器的 [上一頁] 按鈕,以返回虛擬機器的 [概觀] 窗格。

  5. 將 DNS 名稱複製到記事本,因為您在設定憑證時需要該名稱。

  6. 選取 [網路] 窗格,以使用 [新增輸入連接埠規則] 按鈕來設定輸入連接埠規則。 新增下列規則:

    目的地連接埠 通訊協定 名稱 優先順序 描述
    80 TCP Port_80 310 Let's Encrypt 憑證續約
    8884 TCP Port_8884 311 需要 MQTT、加密、用戶端憑證
    8091 TCP Port_8091 312 透過 WebSocket 的 MQTT、已加密、已驗證

啟用 Just-In-Time 存取

  1. 選取 [設定] 窗格。
  2. 選取 [啟用 Just-In-Time]

從桌面連線至虛擬機器

  1. 選取 [連線] 窗格。

  2. 將 [來源 IP] 設定為 [我的 IP]

  3. 選取 [要求存取]

  4. 從您的桌面,透過 SSH 連線到虛擬機器:

    ssh -i <private key path> <username>@<host dns name>
    

    第一次連線可能需要一或兩分鐘的時間。

設定 Ubuntu

  1. 套用任何 OS 更新:

    sudo apt update && sudo apt -y upgrade
    
  2. 安裝必要軟體:

    sudo apt install -y mosquitto mosquitto-clients python3-pip && \
    sudo pip3 install paho-mqtt
    

協助保護 Mosquitto MQTT 訊息代理程式

下列步驟會設定憑證,以協助保護 Altair 模擬器與網路終端機之間的通訊。 結果將會是自我簽署憑證,有效期為 2 年 (730 天)。

  1. 建立設定為 Ubuntu 伺服器 DNS 名稱的 Bash CommonName 變數:

    CommonName=<Your Ubuntu Server DNS Name>
    
  2. 建立暫存工作資料夾:

    mkdir -p ~/mosquitto_certs && cd ~/mosquitto_certs
    
  3. 建立自我簽署 CA 憑證:

    openssl req -new -x509 -days 730 -nodes -extensions v3_ca -keyout ca.key -out ca.crt
    

    當您建立自我簽署 CA 憑證時,可以使用預設值,但一般名稱 (CN) 必須符合伺服器的 DNS 名稱。

  4. 建立伺服器憑證:

    openssl genrsa -out server.key 2048 && \
    openssl req -new -out server.csr -key server.key -subj "/CN=$CommonName" && \
    openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 730 && \
    openssl rsa -in server.key -out server.key
    
  5. 產生 Mosquitto 用戶端憑證:

    openssl genrsa -out client.key 2048 && \
    openssl req -new -out client.csr -key client.key -subj "/CN=$CommonName" && \
    openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 730 && \
    openssl rsa -in client.key -out client.key
    
  6. 將讀取存取權授與金鑰:

    sudo chmod a+r *.key
    
  7. 將憑證複製到 Mosquitto 資料夾:

    sudo cp ca.crt /etc/mosquitto/ca_certificates &&
    sudo cp server.crt /etc/mosquitto/ca_certificates &&
    sudo cp server.key /etc/mosquitto/ca_certificates
    

安裝 Let's Encrypt

Let's Encrypt 是提供 TLS 憑證的非營利憑證授權單位,可為 2.6 億個網站提供 TLS 憑證。 我們將使用免費的 Let's Encrypt 憑證,協助保護網路終端機與 Mosquitto MQTT 訊息代理程式之間的 MQTT 訊息。

下列指示會逐步引導您在 Ubuntu 伺服器上安裝 Certbot ACME 用戶端。 Let's Encrypt 發行的憑證會在六個月之後到期。 Certbot 用戶端可確保憑證會在憑證到期之前更新。

如需詳細資訊,請參閱 Certbot 網站上的指示

  1. 將下列命令區塊複製並貼到 SSH 工作階段,然後選取 Enter 鍵:

    sudo snap install core; sudo snap refresh core && \
    sudo snap install --classic certbot && \
    sudo ln -s /snap/bin/certbot /usr/bin/certbot && \
    sudo certbot certonly --standalone
    
  2. 出現提示時,請輸入您的電子郵件地址,並確認條款及條件。

  3. 當系統提示您輸入伺服器的功能變數名稱時,請輸入您複製到記事本的功能變數名稱。

安裝程式大約需要五分鐘的時間。 完成後,您可以使用下列命令來測試更新程式是否正常運作:

sudo certbot renew --dry-run

您可以使用下列命令來檢視 Let's Encrypt 憑證:

sudo ls -all /etc/letsencrypt/live/$CommonName

建立網路終端機的使用者名稱和密碼

網路終端機會使用 Let's Encrypt 憑證,透過網際網路加密 MQTT 流量。 網路終端機也會用使用者名稱和密碼,向 MQTT 訊息代理程式進行驗證。

下列命令會建立 MQTT 訊息代理程式的密碼檔案,並提示您輸入 WebTerminal 使用者名稱的密碼:

sudo mosquitto_passwd -c /etc/mosquitto/passwd WebTerminal

記下使用者名稱和密碼,因為您需要這些資訊才能設定網路終端機的靜態 Web 應用程式。

設定 Mosquitto MQTT 訊息代理程式

您必須告訴 Mosquitto 訊息代理程式要接聽哪些連接埠,以及憑證的所在位置。

  1. 執行下列命令,將下列設定複製到 /etc/mosquitto/conf.d/default.conf 檔案:

    sudo sh -c "cat > /etc/mosquitto/conf.d/default.conf" << 'EOL'
    per_listener_settings true
    
    listener 1883 localhost
    allow_anonymous true
    
    listener 8884
    allow_anonymous false
    cafile /etc/mosquitto/ca_certificates/ca.crt
    keyfile /etc/mosquitto/ca_certificates/server.key
    certfile /etc/mosquitto/ca_certificates/server.crt
    require_certificate true
    use_identity_as_username true
    tls_version tlsv1.2
    
    listener 8091
    password_file /etc/mosquitto/passwd
    allow_anonymous false
    protocol websockets
    certfile /etc/letsencrypt/live/YOUR_DOMAIN_NAME/cert.pem
    cafile /etc/letsencrypt/live/YOUR_DOMAIN_NAME/chain.pem
    keyfile /etc/letsencrypt/live/YOUR_DOMAIN_NAME/privkey.pem
    EOL
    
  2. 使用 Linux sed 命令,以伺服器的功能變數名稱更新 YOUR_DOMAIN_NAME 預留位置:

    sudo sed -i "s/YOUR_DOMAIN_NAME/$CommonName/g" /etc/mosquitto/conf.d/default.conf
    

測試 Mosquitto 訊息代理程式

會在互動式模式中啟動對 Mosquitto 訊息代理程式有用的疑難排解提示,以確保沒有任何問題。

  1. 您必須先停止 Mosquitto,然後以互動式模式啟動。 選取 Ctrl+C 以結束 Mosquitto 互動式模式,然後輸入下列命令:

    sudo systemctl stop mosquitto && sudo mosquitto -c /etc/mosquitto/conf.d/default.conf
    
  2. 更新 Web 終端機組態:

    1. 啟動 Visual Studio Code。
    2. 從 [Visual Studio Code] 主功能表中,選取 [檔案]>[開啟資料夾]
    3. 開啟您複製或下載的 Cloud-Enabled-Altair-on-Azure-Sphere 資料夾。
    4. 開啟 Altair_Web_Terminal 資料夾。
    5. 按一下 [選取資料夾] 或 [確定] 按鈕以開啟專案。
    6. 移至 Altair 網路終端機的 api 資料夾。
    7. 開啟 local.settings.json 檔案。
    8. 更新這些屬性:
      • "MQTT_BROKER""THE_DNS_NAME_OF_YOUR_VIRTUAL_MACHINE"
      • "MQTT_PASSWORD""YOUR_WebTerminal_USERNAME_PASSWORD"
  3. 上傳 Altair 網路終端機的本地設定:

    1. 仍在 Visual Studio Code 中選取 F1 鍵。
    2. 輸入靜態本機,然後選取 [Azure 靜態 Web 應用程式:上傳本機設定]
    3. 選取您的訂用帳戶。
    4. 選取 [靜態 Web 應用程式]。 針對名稱,輸入 AltairWebTerminal
    5. 輸入生產環境以選取環境。
    6. 系統會提示您覆寫現有的設定。 選取 [全部皆是]
  4. 啟動網路終端機,然後選取 [連線]

  5. 觀察 Mosquitto 訊息代理程式互動式輸出。 輸出看起來應會如下所示:

    1625795690: mosquitto version 1.6.9 starting
    1625795690: Config loaded from /etc/mosquitto/conf.d/default.conf.
    1625795690: Opening ipv4 listen socket on port 1883.
    1625795690: Opening ipv4 listen socket on port 8884.
    1625795690: Opening ipv6 listen socket on port 8884.
    1625795690: Opening websockets listen socket on port 8091.
    1625795897: New client connected from ::ffff:133.233.133.233 as altair1625795897993 (p2, c1, k30, u'WebTerminal').
    

更新 Altair 模擬器設定

更新 Altair 模擬器以連線到新的 Mosquitto MQTT 訊息代理程式:

  1. 將新的 CA 和用戶端憑證複製到 Altair 模擬器的 [憑證] 資料夾。 最簡單的方式是從檔案總管。 憑證至 [憑證] 資料夾,然後開啟新的終端或 PowerShell 視窗。

  2. 執行 scp 命令,將憑證從 Mosquitto 虛擬機器複製到 [憑證] 資料夾。 下列命令假設您已將虛擬機器的私密金鑰複製到 [~/.ssh] 資料夾:

    scp -i ~/.ssh/<your_private_key>.pem <username>@<host_dns_name>:~/mosquitto_certs/* .
    
  3. 在 Visual Studio Code 中的 Altair 模擬器開啟專案。 使用 Mosquitto 訊息代理程式的 DNS 名稱更新 cmake/altair_config.cmake 檔案中的 ALTAIR_MQTT_HOST 定義:

    add_compile_definitions(ALTAIR_MQTT_HOST="REPLACE_WITH_YOUR_VIRTUAL_MACHINE_DNS_NAME")    
    
  4. 儲存 altair_config.cmake 檔案。 此步驟會自動產生 CMake 快取。

  5. app_manifest.jsonAllowedConnections 區段更新為虛擬機器的新功能變數名稱。 移除 test.mosquitto.org 的輸入,因為您將不再使用該端點。

  6. 將 Altair 模擬器重新部署到 Azure Sphere。

  7. 檢查網路終端機。 您應該會看到 Altair 模擬器提示輸入記憶體大小

  8. 檢查以互動式模式執行的 Mosquitto 訊息代理程式輸出。 程式碼看起來應如下所示:

    1625797134: mosquitto version 1.6.9 starting
    1625797134: Config loaded from /etc/mosquitto/conf.d/default.conf.
    1625797134: Opening ipv4 listen socket on port 1883.
    1625797134: Opening ipv4 listen socket on port 8884.
    1625797134: Opening ipv6 listen socket on port 8884.
    1625797134: Opening websockets listen socket on port 8091.
    1625797263: New client connected from ::ffff:133.233.133.233 as altair1625797264017 (p2, c1, k30, u'WebTerminal').
    1625797626: New connection from 133.233.133.233 on port 8884.
    1625797627: New client connected from 133.233.133.233 as altair1234567 (p2, c1, k60, u'your-domain-name.australiaeast.cloudapp.azure.com').
    
    

以精靈模式啟動 Mosquitto MQTT 訊息代理程式

  1. 選取 Ctrl+C,以停止 Mosquitto Broker 的互動式執行個體。

  2. 以精靈模式啟動 Mosquitto 訊息代理程式:

    sudo systemctl enable mosquitto && sudo systemctl start mosquitto
    

在虛擬機器上執行 Python 虛擬磁碟伺服器

在虛擬機器上執行 Python 虛擬磁碟伺服器會大幅改善效能,因為這會從桌面排除 MQTT 伺服器的往返。

將 Altair 專案複製到虛擬機器:

cd ~/ && git clone --depth 1 https://github.com/AzureSphereCloudEnabledAltair8800/AzureSphereAltair8800.git Altair8800Emulator

自動啟動虛擬磁碟伺服器

  1. 輸入下列命令:

    sudo chmod 744 ~/Altair8800Emulator/AltairPY_virtual_disk_server/pyvdisk.sh
    
  2. 將 Python 虛擬磁碟伺服器複製到 /opt 目錄:

    sudo cp -r ~/Altair8800Emulator/AltairPY_virtual_disk_server /opt/pyvdisk
    
  3. 安裝啟動服務:

    sudo cp ~/Altair8800Emulator/AltairPY_virtual_disk_server/pyvdisk.service /etc/systemd/system
    
  4. 重新載入 systemd 單位:

    sudo systemctl daemon-reload
    
  5. 啟動 Python 虛擬磁碟服務:

    sudo systemctl start pyvdisk.service
    
  6. 檢查 Python 虛擬磁碟服務的狀態:

    sudo systemctl status pyvdisk.service
    

疑難排解

mosquitto_pubmosquitto_sub 工具適用於測試憑證。

  1. 在虛擬機器上,輸入:

    cd ~/mosquitto_certs
    
  2. 輸入下列命令:

    mosquitto_pub -h <REPLACE_WITH_YOUR_DOMAIN_NAME> -t "test" -m "hello world" -p 8884 --capath . --cafile ca.crt  --cert client.crt --key client.key
    

    如果 mosquitto_pub 失敗,將會出現錯誤訊息。 最可能的原因是,CA 一般名稱不符合虛擬機器的完整功能變數名稱。

在伺服器上測試您的憑證

輸入下列命令區塊:

mosquitto_pub -h $(hostname) -t "test" -m "hello world" -p 8884 --capath . --cafile ca.crt  --cert client.crt --key client.key

mosquitto_sub -h $(hostname) -t "test" -p 8884 --capath . --cafile ca.crt  --cert client.crt --key client.key