Share via


SDK を使用せずに HTTPS 経由で対称キーを使用する方法

この操作方法に関する記事では、Azure IoT DPS デバイス SDK を使用せずに、HTTPS 経由で対称キーを使用してデバイスをプロビジョニングします。 ほとんどの言語では HTTP 要求を送信するためのライブラリが提供されていますが、この記事では、特定の言語に焦点を当てるのではなく、cURL コマンドライン ツールを使用して HTTPS 経由で送受信します。

この記事の手順は、Linux または Windows マシンで実行できます。 Linux 用 Windows サブシステム (WSL) で実行している場合、または Linux マシンで実行している場合は、Bash プロンプトでローカル システム上のすべてのコマンドを入力できます。 Windows で実行している場合は、GitBash プロンプトでローカル システム上のすべてのコマンドを入力します。

この記事には、使用する登録エントリの種類に応じて異なるパスがあります。 前提条件をインストールしたら、続行する前に、必ず概要をお読みください。

前提条件

  • Azure サブスクリプションをお持ちでない場合は、開始する前に 無料アカウント を作成してください。

  • Azure portal での IoT Hub Device Provisioning Service の設定に関するページの手順を完了します。

  • お使いのマシンに Python 3.7 以降がインストールされていることを確認します。 python --version を実行して、使用している Python のバージョンを確認できます。

  • Windows で実行している場合は、最新バージョンの Git をインストールします。 コマンド ウィンドウからアクセスできる環境変数に Git が追加されていることを確認します。 Git Bash (ローカル Git リポジトリとやりとりする際に使用できるコマンドライン アプリ) を含む、インストールする git ツールの最新バージョンについては、Software Freedom Conservancy の Git クライアント ツールに関するページを参照してください。 Windows では、GitBash プロンプトでローカル システム上のすべてのコマンドを入力します。

  • Azure CLI。 この記事で Azure CLI コマンドを実行するには、次の 2 つのオプションがあります。

    • ブラウザーで CLI コマンドを実行する対話型シェルである Azure Cloud Shell を使用します。 何もインストールする必要がないため、このオプションをお勧めします。 Cloud Shell を初めて使用する場合は、Azure portal にサインインします。 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 インスタンスの名前を置き換えます。

  • 登録 ID はデバイスの登録 ID です。 登録 ID は、英数字と特殊文字 ('-''.''_'':') から成る、大文字と小文字が区別されない文字列です (最大 128 文字)。 最後の文字は、英数字またはダッシュ ('-') である必要があります。 コマンドで使用する登録 ID がこの形式に準拠していることを確認します。

割り当てられた対称キーは、応答の構成証明プロパティで返されます。


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

  ...

}

個別登録エントリの主キーと登録 ID をメモしておきます。この記事の後半で使用します。

この記事で既存の個別登録を使用する場合は、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 create コマンドを使用して、対称キー構成証明の登録グループを作成できます。

次のコマンドでは、DPS インスタンスの既定の割り当てポリシーを使用して登録グループ エントリを作成し、DPS が登録グループの主キーとセカンダリ キーを割り当てるようにします。

az iot dps enrollment-group create -g {resource_group_name} --dps-name {dps_name} --enrollment-id {enrollment_id}
  • リソース グループと DPS インスタンスの名前を置き換えます。

  • 登録 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

デバイス キーを派生させる

グループ登録で対称キーの構成証明を使用する場合、登録グループのキーを直接は使用しません。 その代わりに、登録グループ キーから各デバイスに固有のキーを派生させます。 詳細については、対称キーを使用したグループの登録に関するセクションを参照してください。

このセクションでは、登録グループの主キーからデバイス キーを生成し、デバイス用の一意の登録 ID の HMAC-SHA256 を計算します。 結果は Base64 形式に変換されます。

  1. openssl を使用して、一意のキーを生成します。 次の Bash シェル スクリプトを使用します。 {primary-key} を、前にコピーした登録グループの主キーに置き換え、{contoso-simdevice} を、デバイスに使用する登録 ID に置き換えます。 登録 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=
    

派生デバイス キーと、生成に使用した登録 ID をメモしておきます。次のセクションで使用します。

Azure CLI または PowerShell を使用して、デバイス キーを派生することもできます。 詳細については、「デバイス キーを派生させる」を参照してください。

SAS トークンを作成する

対称キー構成証明を使用する場合、デバイスは Shared Access Signature (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 インスタンスの ID スコープであり、[dps_registration_id] はデバイスに使用した登録 ID です。

    DPS インスタンスの ID スコープは、Azure portal のインスタンスの [概要] ウィンドウから取得するか、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 デバイス登録の場合、ポリシーは '登録' にハード コーディングされます。

有効期間が 30 日の my-symkey-device というデバイスの入力セットの例を次に示します。

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 へのアクセスを制御する」を参照してください。

デバイスを登録する

デバイスの登録 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 は、HTTP リダイレクトに従うように curl に指示します。

  • –i は、出力にプロトコル ヘッダーを含むように curl に指示します。 これらのヘッダーは厳密には必要ありませんが、役立つ場合があります。

  • -X PUT は、これが HTTP PUT コマンドであることを curl に通知します。 この API 呼び出しに必要です。

  • -H 'Content-Type: application/json' は、JSON コンテンツを投稿しており、'application/json' である必要があることを DPS に通知します。

  • -H 'Content-Encoding: utf-8' は、メッセージ本文に使用しているエンコードを DPS に通知します。 OS/クライアントの適切な値に設定します。ただし、一般的には utf-8 です。

  • -H 'Authorization: [sas_token]' は、SAS トークンを使用して認証するように DPS に指示します。 [sas_token] を、「SAS トークンの作成」で生成したトークンに置き換えます。

  • -d '{"registrationId": "[registration_id]"}'–d パラメーターは、投稿するメッセージの 'データ' または本文です。 '{"registrationId":"[registration_id"}' の形式の JSON である必要があります。 curl の場合は、単一引用符で囲まれていることに注意してください。それ以外の場合は、JSON 内の二重引用符をエスケープする必要があります。

  • 最後のパラメーターは投稿先の URL です。 "通常" (つまりオンプレミスではない) DPS の場合、グローバル DPS エンドポイント、global.azure-devices-provisioning.net が使用されます: https://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"}

応答には、操作 ID と状態が含まれています。 この場合、状態は assigning に設定されます。 DPS 登録は、実行時間の長い操作である可能性があるため、非同期的に実行されます。 通常は、操作状態の検索 REST API を使用して状態をポーリングして、デバイスがいつ割り当てられたか、障害が発生したかどうかを判断します。

DPS の有効な状態の値は次のとおりです。

  • assigned: 状態呼び出しからの戻り値は、デバイスが割り当てられた IoT Hub を示します。

  • assigning: 操作はまだ実行中です。

  • disabled: 登録レコードは DPS で無効になっているため、デバイスを割り当てることはできません。

  • failed: ロールの割り当てに失敗しました。 応答で registrationState レコードに errorCodeerrorMessage が返され、何が失敗したかを示します。

  • unassigned

操作状態の検索 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

デバイスの登録要求で使用したのと同じ ID スコープ、登録 ID、SAS トークンを使用します。 デバイスの登録応答で返された操作 ID を使用します。

次に例を示します。

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 Hub ホスト名を使用します。

    • [device-id] の場合は、前のセクションの deviceId プロパティで返されたデバイス ID を使用します。

  • [device_key] は、デバイスに関連付けられているデバイス キーです。 このキーは、個別登録で指定されたまたは自動生成されたキー、またはグループ登録の派生キーです。 (これは、DPS のトークンを作成するために以前に使用したのと同じキーです)。

  • [expiry_in_seconds] は、この SAS トークンの有効期間 (秒単位) です。

  • policy=None IoT ハブにテレメトリを送信するデバイスにはポリシーは必要ないため、このパラメーターは None に設定されます。

トークンの有効期間が 1 時間の MyExampleHub という IoT Hub に送信する my-symkey-device というデバイスの入力セットの例を次に示します。

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 Hub の SAS トークンの作成の詳細については、「Shared Access Signature を使用して IoT Hub へのアクセスを制御する」を参照してください。

Note

便宜上、Azure CLI az iot hub generate-sas-token コマンドを使用して、IoT ハブに登録されているデバイスの SAS トークンを取得できます。 たとえば、次のコマンドは、期間が 1 時間の SAS トークンを生成します。 {iothub_name} の場合は、ホスト名の最初の部分 (例: MyExampleHub) のみが必要です。

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

IoT ハブにデータを送信する

デバイスにテレメトリを送信するには、IoT Hub デバイス イベントの送信 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 は、これが HTTP POST コマンドであることを curl に通知します。 この API 呼び出しに必要です。

  • -H 'Content-Type: application/json' は、JSON コンテンツを投稿しており、'application/json' である必要があることを IoT Hub に通知します。

  • -H 'Content-Encoding: utf-8' は、メッセージ本文に使用しているエンコードを IoT Hub に通知します。 OS/クライアントの適切な値に設定します。ただし、一般的には utf-8 です。

  • -H 'Authorization: [sas_token]' は、SAS トークンを使用して認証するように IoT Hub に指示します。 [sas_token] を、割り当てられた IoT ハブ用に生成したトークンに置き換えます。

  • -d '{"temperature": 30}'–d パラメーターは、投稿するメッセージの 'データ' または本文です。 この記事では、単一の温度データ ポイントを投稿します。 コンテンツの種類が application/json として指定されているため、この要求の本文は JSON です。 curl の場合は、単一引用符で囲まれていることに注意してください。それ以外の場合は、JSON 内の二重引用符をエスケープする必要があります。

  • 最後のパラメーターは投稿先の URL です。 デバイス イベントの送信 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] を、デバイスの登録時に割り当てられたデバイス ID に置き換えます。 登録グループを介してプロビジョニングするデバイスの場合、デバイス ID は登録 ID になります。 個別登録では、必要に応じて、登録エントリの登録 ID とは異なるデバイス ID を指定できます。

たとえば、デバイス 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

次のステップ