共用方式為


如何在沒有 SDK 的情況下透過 HTTPS 使用對稱金鑰

在本操作說明文章中,您將在未使用 Azure IoT DPS 裝置 SDK 的情況下透過 HTTPS 使用對稱金鑰來佈建裝置。 大部分的語言都提供程式庫來傳送 HTTP 要求,但在本文中 (而不是專注於某一個特定的語言),您將使用 cURL 命令列工具來透過 HTTPS 傳送和接收。

您可以在 Linux 或 Windows 機器上遵循本文中的步驟。 如果您在 Windows 子系統 Linux 版 (WSL) 上執行或在 Linux 機器上執行,則您可以在本機系統上的 Bash 提示字元中輸入所有命令。 如果您在 Windows 上執行,請在本機系統上的 GitBash 提示字元中輸入所有命令。

根據您選擇使用的註冊項目類型而定,本文當中會有不同的路徑。 在安裝必備項目之後,請務必先閱讀概觀,再繼續進行。

必要條件

  • 如果您沒有 Azure 訂用帳戶,請在開始前建立免費帳戶

  • 完成透過 Azure 入口網站來設定 IoT 中樞裝置佈建服務中的步驟。

  • 請確定您的機器上安裝了 Python 3.7 或更新版本。 您可以藉由執行 python --version 來檢查您的 Python 版本。

  • 如果您是在 Windows 中執行,請安裝最新版的 Git。 確定 Git 已新增至可存取命令視窗的環境變數中。 請參閱 Software Freedom Conservancy 的 Git 用戶端工具以取得要安裝的最新版 git 工具,其中包括 Git Bash (您可用來與本機 Git 存放庫互動的命令列應用程式)。 在 Windows 上,您將在本機系統上的 GitBash 提示字元中輸入所有命令。

  • Azure CLI。 您有兩個選項可用來執行本文中的 Azure CLI 命令:

    • 使用 Azure Cloud Shell,這是一種在瀏覽器中執行 CLI 命令的互動式 shell。 建議使用此選項,因為您不需要安裝任何項目。 如果您是第一次使用 Cloud Shell,請登入 Azure 入口網站。 請遵循 Cloud Shell 快速入門中的步驟,以啟動 Cloud Shell選取 Bash 環境
    • 或者,在本機電腦上執行 Azure CLI。 如果已安裝 Azure CLI,請執行 az upgrade 以將 CLI 和擴充功能更新為目前的版本。 若要安裝 Azure CLI,請參閱安裝 Azure CLI
  • 如果您是在 Linux 或 WSL 環境中執行,請開啟 Bash 提示字元以在本機上執行命令。 如果您是在 Windows 環境中執行,請開啟 GitBash 提示字元。

概觀

對於本文,您可以使用個別註冊註冊群組來透過 DPS 佈建。

在建立個別註冊或註冊群組項目之後,請繼續建立 SAS 權杖,並透過 DPS 來註冊您的裝置

使用個別註冊

如果您想要建立要用於本文的新個別註冊,您可以使用 az iot dps enrollment create 命令來建立對稱金鑰證明的個別註冊。

下列命令會為您的 DPS 執行個體建立具有預設配置原則的註冊項目,並讓 DPS 為您的裝置指派主要和次要金鑰:

az iot dps enrollment create -g {resource_group_name} --dps-name {dps_name} --enrollment-id {enrollment_id} --attestation-type symmetrickey
  • 替換您的資源群組和 DPS 執行個體的名稱。

  • 註冊識別碼是您裝置的註冊識別碼。 登錄識別碼 (registration ID) 是一個不區分大小寫的字串 (長度最多為 128 個字元),該字串可包含英數字元加上特殊字元:'-''.''_'':'。 最後一個字元必須是英數字元或破折號 ('-')。 請確定您在命令中所使用的註冊識別碼遵照此格式。

指派的對稱金鑰會在回應的證明屬性中傳回:


{
  "allocationPolicy": null,
  "attestation": {
    "symmetricKey": {
      "primaryKey": "G3vn0IZH9oK3d4wsxFpWBtd2KUrtjI+39dZVRf26To8w9OX0LaFV9yZ93ELXY7voqHEUsNhnb9bt717UP87KxA==",
      "secondaryKey": "4lNxgD3lUAOEOied5/xOocyiUSCAgS+4b9OvXLDi8ug46/CJzIn/3rN6Ys6gW8SMDDxMQDaMRnIoSd1HJ5qn/g=="
    },
    "tpm": null,
    "type": "symmetricKey",
    "x509": null
  },

  ...

}

記下您個別註冊項目的主要金鑰和登錄識別碼 (註冊識別碼),稍後您將在本文中使用。

如果您想要使用本文的現有個別註冊,則您可以使用 az iot dps enrollment show 命令來取得主要金鑰:

az iot dps enrollment show -g {resource_group_name} --dps-name {dps_name} --enrollment-id {enrollment_id} --show-keys true

使用註冊群組

如果您想要建立要用於本文的新註冊群組,您可以使用 az iot dps enrollment-group create 命令來建立對稱金鑰證明的註冊群組。

下列命令會為您的 DPS 執行個體建立具有預設配置原則的註冊群組項目,並讓 DPS 為該註冊群組指派主要和次要金鑰:

az iot dps enrollment-group create -g {resource_group_name} --dps-name {dps_name} --enrollment-id {enrollment_id}
  • 替換您的資源群組和 DPS 執行個體的名稱。

  • 註冊識別碼 (enrollment ID) 是一個不區分大小寫的字串 (長度最多為 128 個字元),該字串可包含英數字元加上特殊字元:'-''.''_'':'。 最後一個字元必須是英數字元或破折號 ('-')。 它可以是您選擇要用於註冊群組的任何名稱。

指派的對稱金鑰會在回應的證明屬性中傳回:


{
  "allocationPolicy": null,
  "attestation": {
    "symmetricKey": {
      "primaryKey": "G3vn0IZH9oK3d4wsxFpWBtd2KUrtjI+39dZVRf26To8w9OX0LaFV9yZ93ELXY7voqHEUsNhnb9bt717UP87KxA==",
      "secondaryKey": "4lNxgD3lUAOEOied5/xOocyiUSCAgS+4b9OvXLDi8ug46/CJzIn/3rN6Ys6gW8SMDDxMQDaMRnIoSd1HJ5qn/g=="
    },
    "tpm": null,
    "type": "symmetricKey",
    "x509": null
  },

  ...

}

記下主要金鑰。

如果您想要使用本文的現有個別註冊,則您可以使用 az iot dps enrollment-group show 命令來取得主要金鑰:

az iot dps enrollment-group show -g {resource_group_name} --dps-name {dps_name} --enrollment-id {enrollment_id} --show-keys true

衍生裝置金鑰

搭配群組註冊使用對稱金鑰證明時,您不會直接使用註冊群組金鑰。 相反地,您會從註冊群組金鑰中衍生每個裝置的唯一金鑰。 如需詳細資訊,請參閱使用對稱金鑰的群組註冊

在本節中,您將從註冊群組主要金鑰中產生裝置金鑰,以計算裝置的唯一登錄識別碼 HMAC-SHA256。 然後結果會轉換成 Base64 格式。

  1. 使用 openssl 來產生您的唯一金鑰。 您將使用下列 Bash shell 指令碼。 將 {primary-key} 取代為您稍早所複製的註冊群組的主要金鑰,並以您想要用於裝置的登錄識別碼來取代 {contoso-simdevice}。 登錄識別碼 (registration ID) 是一個不區分大小寫的字串 (長度最多為 128 個字元),該字串可包含英數字元加上特殊字元:'-''.''_'':'。 最後一個字元必須是英數字元或破折號 ('-')。

    KEY={primary-key}
    REG_ID={contoso-simdevice}
    
    keybytes=$(echo $KEY | base64 --decode | xxd -p -u -c 1000)
    echo -n $REG_ID | openssl sha256 -mac HMAC -macopt hexkey:$keybytes -binary | base64
    
  2. 該指令碼會輸出類似下列金鑰的結果:

    p3w2DQr9WqEGBLUSlFi1jPQ7UWQL4siAGy75HFTFbf8=
    

記下衍生裝置金鑰和您用來產生它的登錄識別碼,您將在下一節中使用。

您也可以使用 Azure CLI 或 PowerShell 來衍生裝置金鑰。 若要深入了解,請參閱衍生裝置金鑰

建立 SAS 權杖

使用對稱金鑰證明時,裝置會使用「共用存取簽章」(SAS) 權杖來向 DPS 進行驗證。 對於透過個別註冊的裝置佈建,該權杖會使用註冊項目中所設定的主要或次要金鑰來進行簽署。 對於透過註冊群組的裝置佈建,該權杖會使用衍生裝置金鑰來進行簽署,該金鑰已使用註冊群組項目中所設定的主要或次要金鑰按順序產生。 該權杖會指定到期時間和目標資源 URI。

下列 Python 指令碼可用來產生 SAS 權杖:

from base64 import b64encode, b64decode
from hashlib import sha256
from time import time
from urllib.parse import quote_plus, urlencode
from hmac import HMAC

def generate_sas_token(uri, key, policy_name, expiry=3600):
     ttl = time() + expiry
     sign_key = "%s\n%d" % ((quote_plus(uri)), int(ttl))
     print(sign_key)
     signature = b64encode(HMAC(b64decode(key), sign_key.encode('utf-8'), sha256).digest())

     rawtoken = {
         'sr' :  uri,
         'sig': signature,
         'se' : str(int(ttl))
     }

     if policy_name is not None:
         rawtoken['skn'] = policy_name

     return 'SharedAccessSignature ' + urlencode(rawtoken)

uri = '[resource_uri]'
key = '[device_key]'
expiry = [expiry_in_seconds]
policy= '[policy]'

print(generate_sas_token(uri, key, policy, expiry))

其中:

  • [resource_uri] 是您嘗試使用此權杖存取的資源 URI。 對於 DPS,其格式為 [dps_id_scope]/registrations/[dps_registration_id],其中 [dps_id_scope] 是 DPS 執行個體的識別碼範圍,而 [dps_registration_id] 是您用於裝置的登錄識別碼。

    您可以從 Azure 入口網站中您的執行個體的 [概觀] 窗格取得 DPS 執行個體的識別碼範圍,或者也可以使用 az iot dps show Azure CLI 命令 (將預留位置取代為資源群組和 DPS 執行個體的名稱):

    az iot dps show -g {resource_group_name} --name {dps_name}
    
  • [device_key] 是與您的裝置相關聯的裝置金鑰。 此金鑰是在個別註冊中為您指定的金鑰或自動產生的金鑰,或是群組註冊的衍生金鑰。

    • 如果您是使用個別註冊,請使用儲存在 [使用個別註冊] 中的主要金鑰。

    • 如果您是使用註冊群組,請使用您在 [使用註冊群組] 中所產生的衍生裝置金鑰。

  • [expiry_in_seconds] 是此 SAS 權杖的有效期間 (以秒為單位)。

  • [policy] 是與裝置金鑰相關聯的原則。 對於 DPS 裝置登錄,原則會硬式編碼為 'registration'。

名為 my-symkey-device 且有效期間為 30 天的裝置,其輸入的範例集可能看起來像這樣。

uri = '0ne00111111/registrations/my-symkey-device'
key = '18RQk/hOPJR9EbsJlk2j8WA6vWaj/yi+oaYg7zmxfQNdOyMSu+SJ8O7TSlZhDJCYmn4rzEiVKIzNiVAWjLxrGA=='
expiry = 2592000
policy='registration'

為您的裝置和 DPS 執行個體修改指令碼,並將其儲存為 Python 檔案; 例如,generate_token.py。 執行該指令碼,例如 python generate_token.py。 它應會輸出類似下列的 SAS 權杖:

0ne00111111%2Fregistrations%2Fmy-symkey-device
1663952627
SharedAccessSignature sr=0ne00111111%2Fregistrations%2Fmy-symkey-device&sig=eNwg52xQdFTNf7bgPAlAJBCIcONivq%2Fck1lf3wtxI4A%3D&se=1663952627&skn=registration

複製並儲存開頭為 SharedAccessSignature 的一整行。 這一行是 SAS 權杖。 您將在下面各節中需要它。

若要深入了解如何向 DPS 使用 SAS 權杖及其結構,請參閱使用 SAS 控制對 DPS 的存取

登記裝置

您可以呼叫 Register Device REST API 來透過 DPS 佈建您的裝置。

使用下列的 curl 命令:

curl -L -i -X PUT -H 'Content-Type: application/json' -H 'Content-Encoding:  utf-8' -H 'Authorization: [sas_token]' -d '{"registrationId": "[registration_id]"}' https://global.azure-devices-provisioning.net/[dps_id_scope]/registrations/[registration_id]/register?api-version=2019-03-31

其中:

  • -L 告知 curl 遵循 HTTP 重新導向。

  • –i 告知 curl 在輸出中包括通訊協定標頭。 這些標頭並非絕對必要,但它們可能很有用。

  • -X PUT 告知 curl 這是 HTTP PUT 命令。 此 API 呼叫需要。

  • -H 'Content-Type: application/json' 告知 DPS 我們正在張貼 JSON 內容,而且必須是 'application/json'。

  • -H 'Content-Encoding: utf-8' 告知 DPS 我們用於訊息本文的編碼方式。 針對您的 OS/用戶端設為適當的值;不過,它通常是 utf-8

  • -H 'Authorization: [sas_token]' 告知 DPS 使用您的 SAS 權杖來進行驗證。 將 [sas_token] 取代為您在建立 SAS 權杖中所產生的權杖。

  • -d '{"registrationId": "[registration_id]"}'–d 參數是我們張貼的訊息的「資料」或本文。 其必須是 JSON,格式為 '{"registrationId":"[registration_id"}'。 請注意,對於 curl,它會以單引號括住;否則,您必須逸出 JSON 中的雙引號。

  • 最後,最後一個參數是要張貼的 URL。 對於「一般」(亦即非內部部署)DPS,則會使用全域 DPS 端點 global.azure-devices-provisioning.nethttps://global.azure-devices-provisioning.net/[dps_id_scope]/registrations/[registration_id]/register?api-version=2019-03-31。 請注意,您必須以適當的值來取代 [dps_scope_id][registration_id]

例如:

curl -L -i -X PUT -H 'Content-Type: application/json' -H 'Content-Encoding:  utf-8' -H 'Authorization: SharedAccessSignature sr=0ne00111111%2Fregistrations%2Fmy-symkey-device&sig=eNwg52xQdFTNf7bgPAlAJBCIcONivq%2Fck1lf3wtxI4A%3D&se=1663952627&skn=registration' -d '{"registrationId": "my-symkey-device"}' https://global.azure-devices-provisioning.net/0ne00111111/registrations/my-symkey-device/register?api-version=2021-06-01

成功的呼叫會有類似下列的回應:

HTTP/1.1 202 Accepted
Date: Wed, 31 Aug 2022 22:02:49 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Location: https://global.azure-devices-provisioning.net/0ne00111111/registrations/my-symkey-device/register
Retry-After: 3
x-ms-request-id: a021814f-0cf6-4ce9-a1e9-ead7eb5118d9
Strict-Transport-Security: max-age=31536000; includeSubDomains

{"operationId":"5.316aac5bdc130deb.b1e02da8-c3a0-4ff2-a121-7ea7a6b7f550","status":"assigning"}

該回應包含作業識別碼和狀態。 在此情況下,狀態會設定為 assigning。 DPS 註冊可能是一項長時間執行的作業,因此會以非同步的方式來完成。 一般而言,您將使用 Operation Status Lookup REST API 來輪詢狀態,以判斷裝置是否已指派或是否發生失敗問題。

DPS 的有效狀態值為:

  • assigned:來自狀態呼叫的傳回值會指出裝置被指派到哪個 IoT 中樞。

  • assigning:作業仍在執行中。

  • disabled:註冊記錄已在 DPS 中停用,因此無法指派裝置。

  • failed:指派失敗。 將會在回應的 registrationState 記錄中傳回 errorCodeerrorMessage,以指出什麼失敗了。

  • unassigned

若要呼叫 Operation Status Lookup API,請使用下列 curl 命令:

curl -L -i -X GET -H 'Content-Type: application/json' -H 'Content-Encoding:  utf-8' -H 'Authorization: [sas_token]' https://global.azure-devices-provisioning.net/[dps_id_scope]/registrations/[registration_id]/operations/[operation_id]?api-version=2019-03-31

您將使用與在 Register Device 要求中使用相同的識別碼範圍、登錄識別碼和 SAS 權杖。 使用 Register Device 回應中已傳回的作業識別碼。

例如:

curl -L -i -X GET -H 'Content-Type: application/json' -H 'Content-Encoding:  utf-8' -H 'Authorization: SharedAccessSignature sr=0ne00111111%2Fregistrations%2Fmy-symkey-device&sig=eNwg52xQdFTNf7bgPAlAJBCIcONivq%2Fck1lf3wtxI4A%3D&se=1663952627&skn=registration' https://global.azure-devices-provisioning.net/0ne00111111/registrations/my-symkey-device/operations/5.316aac5bdc130deb.f4f1828c-4dab-4ca9-98b2-dfc63b5835d6?api-version=2021-06-01

下列輸出顯示已成功指派裝置的回應。 請注意,status 屬性是 assigned,而 registrationState.assignedHub 屬性會設為在其中佈建裝置的 IoT 中樞。

HTTP/1.1 200 OK
Date: Wed, 31 Aug 2022 22:05:23 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
x-ms-request-id: ffb98d42-023e-4e75-afb0-1807ff091cbb
Strict-Transport-Security: max-age=31536000; includeSubDomains

{
   "operationId":"5.316aac5bdc130deb.b1e02da8-c3a0-4ff2-a121-7ea7a6b7f550",
   "status":"assigned",
   "registrationState":{
      "registrationId":"my-symkey-device",
      "createdDateTimeUtc":"2022-08-31T22:02:50.5163352Z",
      "assignedHub":"MyExampleHub.azure-devices.net",
      "deviceId":"my-symkey-device",
      "status":"assigned",
      "substatus":"initialAssignment",
      "lastUpdatedDateTimeUtc":"2022-08-31T22:02:50.7370676Z",
      "etag":"IjY5MDAzNTUyLTAwMDAtMDMwMC0wMDAwLTYzMGZkYThhMDAwMCI="
   }
}

傳送遙測訊息

在能夠傳送遙測訊息之前,您必須先針對將裝置指派到其中的 IoT 中樞建立 SAS 權杖。 您可以使用用來為您的 DPS 執行個體簽署 SAS 權杖的同一個主要金鑰或衍生裝置金鑰來簽署此權杖。

針對您的 IoT 中樞建立 SAS 權杖

若要建立 SAS 權杖,您可以執行與針對您的 DPS 執行個體來建立權杖所執行的相同程式碼,但要進行下列的變更:

uri = '[resource_uri]'
key = '[device_key]'
expiry = [expiry_in_seconds]
policy= None

其中:

  • [resource_uri] 是您嘗試使用此權杖存取的資源 URI。 對於將訊息傳送至 IoT 中樞的裝置,其格式為 [iot-hub-host-name]/devices/[device-id]

    • 對於 [iot-hub-host-name],請使用前節的 assignedHub 屬性中所傳回的 IoT 中樞主機名稱。

    • 對於 [device-id],請使用前節的 deviceId 屬性中所傳回的裝置識別碼。

  • [device_key] 是與您的裝置相關聯的裝置金鑰。 此金鑰是在個別註冊中為您指定的金鑰或自動產生的金鑰,或是群組註冊的衍生金鑰。 (您先前用來針對 DPS 建立權杖的同一個金鑰。)

    • 如果您是使用個別註冊,請使用儲存在 [使用個別註冊] 中的主要金鑰。

    • 如果您是使用註冊群組,請使用您在 [使用註冊群組] 中所產生的衍生裝置金鑰。

  • [expiry_in_seconds] 是此 SAS 權杖的有效期間 (以秒為單位)。

  • policy=None 傳送遙測至 IoT 中樞的裝置不需要任何原則,所以此參數會設為 None

名為 my-symkey-device 且傳送至名為 MyExampleHub 的 IoT 中樞的裝置 (具有一小時的權杖有效期),其輸入的範例集可能看起來像這樣:

uri = 'MyExampleHub.azure-devices.net/devices/my-symkey-device'
key = '18RQk/hOPJR9EbsJlk2j8WA6vWaj/yi+oaYg7zmxfQNdOyMSu+SJ8O7TSlZhDJCYmn4rzEiVKIzNiVAWjLxrGA=='
expiry = 3600
policy= None

下列輸出顯示這些輸入的範例 SAS 權杖:

SharedAccessSignature sr=MyExampleHub.azure-devices.net%2Fdevices%2Fmy-symkey-device&sig=f%2BwW8XOKeJOtiPc9Iwjc4OpExvPM7NlhM9qxN2a1aAM%3D&se=1663119026

若要深入了解如何針對 IoT 中樞建立 SAS 權杖 (包括其他程式設計語言的範例程式碼),請參閱使用共用存取簽章來控制對 IoT 中樞的存取

注意

為了方便起見,您可以使用 Azure CLI az iot hub generate-sas-token 命令來針對要向 IoT 中樞登錄的裝置取得 SAS 權杖。 例如,下列命令會產生持續時間為一小時的 SAS 權杖。 對於 {iothub_name},您只需要主機名稱的第一個部分,例如 MyExampleHub

az iot hub generate-sas-token -d {device_id} -n {iothub_name}

將資料傳送至您的 IoT 中樞

您可以呼叫 IoT Hub Send Device Event REST API,以將遙測傳送至裝置。

使用下列的 curl 命令:

curl -L -i -X POST -H 'Content-Type: application/json' -H 'Content-Encoding:  utf-8' -H 'Authorization: [sas_token]' -d '{"temperature": 30}' https://[assigned_iot_hub_name].azure-devices.net/devices/[device_id]/messages/events?api-version=2020-03-13

其中:

  • -X POST 告知 curl 這是 HTTP POST 命令。 此 API 呼叫需要。

  • -H 'Content-Type: application/json' 告知 IoT 中樞我們正在張貼 JSON 內容,而且必須是 'application/json'。

  • -H 'Content-Encoding: utf-8' 告知 IoT 中樞我們用於訊息本文的編碼方式。 針對您的 OS/用戶端設為適當的值;不過,它通常是 utf-8

  • -H 'Authorization: [sas_token]' 告知 IoT 中樞使用您的 SAS 權杖來進行驗證。 將 [sas_token] 取代為您為指派的 IoT 中樞所產生的權杖。

  • -d '{"temperature": 30}'–d 參數是我們張貼的訊息的「資料」或本文。 對於本文,我們會張貼一個單一的溫度資料點。 內容類型已指定為 application/json,所以對於此要求,本文為 JSON。 請注意,對於 curl,其會以單引號括住;否則,您必須逸出 JSON 中的雙引號。

  • 最後一個參數是要張貼的 URL。 對於 Send Device Event API,URL 為:https://[assigned_iot_hub_name].azure-devices.net/devices/[device_id]/messages/events?api-version=2020-03-13

    • [assigned_iot_hub_name] 取代為將您的裝置指派到其中的 IoT 中樞名稱。

    • [device_id] 取代為您登錄裝置時所指派的裝置識別碼。 對於透過註冊群組所佈建的裝置,裝置識別碼會是登錄識別碼。 對於個別註冊,您可以選擇性地指定與註冊項目中登錄識別碼不同的裝置識別碼。

例如,對於裝置識別碼為 my-symkey-device 的裝置 (將遙測資料點傳送至名為 MyExampleHub 的 IoT 中樞):

curl -L -i -X POST -H 'Content-Type: application/json' -H 'Content-Encoding:  utf-8' -H 'Authorization: SharedAccessSignature sr=MyExampleHub.azure-devices.net%2Fdevices%2Fmy-symkey-device&sig=f%2BwW8XOKeJOtiPc9Iwjc4OpExvPM7NlhM9qxN2a1aAM%3D&se=1663119026' -d '{"temperature": 30}' https://MyExampleHub.azure-devices.net/devices/my-symkey-device/messages/events?api-version=2020-03-13

成功的呼叫會有類似下列的回應:

HTTP/1.1 204 No Content
Content-Length: 0
Vary: Origin
Server: Microsoft-HTTPAPI/2.0
x-ms-request-id: 9e278582-3561-417b-b807-76426195920f
Date: Wed, 14 Sep 2022 00:32:53 GMT

後續步驟