クラウド・プラットフォーム

プロビジョニング

機器をネットワーク・クラウドに登録する初期設定。

概要

プロビジョニング(Provisioning)とは、IoTデバイスをネットワークやクラウドサービスに安全に登録し、動作に必要な設定・認証情報・ネットワーク接続情報などを組み込む初期設定プロセスの総称です。工場出荷時または現地設置時に行われ、デバイスが正しいクラウドサービスに正しいID・認証情報で自動的に接続できる状態を作ることが目的です。

プロビジョニングが必要な情報は以下の通りです。

  • デバイスID: クラウド上でデバイスを一意に識別するためのID
  • 認証情報: X.509証明書、SASトークン、JWTキーなど
  • 接続先エンドポイント: 接続するクラウドサービスのURL・ポート
  • 設定値: 初期動作設定(サンプリング周期、閾値など)
  • ネットワーク設定: Wi-Fi SSIDとパスワード、APN設定など

プロビジョニングの形態は以下のように分類されます。

種別タイミング方法
工場プロビジョニング製造時製造ラインでの自動書き込み
Just-in-Time Provisioning(JITP)初回接続時自動登録
Fleet Provisioning現地設置時クレームによる自動取得
手動プロビジョニング任意管理者が手動で設定

歴史・背景

初期のIoTシステムでは、プロビジョニングは非常に労力のかかる手動作業でした。エンジニアが1台1台のデバイスにSSHやシリアル接続でアクセスし、接続先URLや認証情報を手動で設定していました。デバイス数が数十台規模であれば許容できても、数千〜数万台規模になると現実的ではありません。

2015〜2016年頃からAWSやAzureがゼロタッチプロビジョニング(人手を介さない自動プロビジョニング)の仕組みを提供し始めました。AWSのJust-in-Time Provisioning(2016年)、Azure Device Provisioning Service(2017年)がその代表例です。

通信分野ではeSIM(2016年規格化)が登場し、デバイスを物理的に操作することなく、無線でSIMプロファイルを書き込む「リモートSIMプロビジョニング」が可能になりました。これにより、グローバルに出荷するIoTデバイスのSIM管理が劇的に簡素化されました。

LoRaWANなどのLPWAネットワークでも「Over-The-Air Activation(OTAA)」というプロビジョニング方式が標準化され、デバイスがネットワークに初回接続する際に自動的に暗号鍵を交換・登録する仕組みが普及しています。

技術仕様

X.509証明書ベースのプロビジョニング

IoTデバイスのプロビジョニングで最も広く使われる認証方式がX.509クライアント証明書です。

証明書チェーン構成:
Root CA(信頼のアンカー)
    └── Intermediate CA(デバイスグループ毎)
            └── Device Certificate(デバイス固有)
                  ├── Common Name: device-serial-12345
                  ├── Subject Alternative Name: device-serial-12345
                  └── 有効期限: 10年 (多くの場合)

AWS IoT Fleet Provisioning の仕組み

工場出荷段階:
  デバイスに「クレーム証明書」(共通の一時証明書)を焼き付け

現地設置後、初回起動:
  1. クレーム証明書でAWS IoT Coreに接続
  2. CreateKeysAndCertificate APIを呼び出し
  3. デバイス固有の証明書とキーを受け取る
  4. RegisterThing APIでデバイス登録
  5. クレーム証明書を削除、固有証明書を保存
  6. 以降は固有証明書でIoT Coreに接続

LoRaWAN OTAAプロビジョニング

デバイスに事前設定(工場段階):
  - AppEUI (JoinEUI): ネットワークサーバーを識別するID
  - DevEUI: デバイス固有のEUI-64
  - AppKey: 128ビット暗号鍵(秘密)

初回起動(Joinプロセス):
  1. デバイス → Join Request (MIC: AppKeyで計算)
  2. ネットワークサーバー → Join Accept
     (AppKeyでセッションキーNwkSKey/AppSKeyを導出)
  3. セッションキーを使い暗号化通信開始

このプロセス中、AppKeyはネットワーク上に流れない(ゼロ知識証明的な仕組み)

デバイス証明書のライフサイクル

フェーズ内容
製造HSM/TPMで秘密鍵生成・CSR発行
証明書発行製造ラインのCA/PKIシステムで署名
焼き付けセキュアエレメントへの格納
初回起動クラウドへの登録(DPS/JITP等)
運用中証明書有効期限監視
更新OTAによる証明書ローテーション
廃棄証明書の失効・デバイス登録削除

動作原理

ゼロタッチプロビジョニングの実装

# AWS Fleet Provisioning: デバイス側の実装(Python例)
import boto3
import json
import ssl
import paho.mqtt.client as mqtt

class FleetProvisioner:
    """AWSのFleet Provisioningを使ったゼロタッチプロビジョニング"""

    CLAIM_CERT = "/etc/iot/claim_cert.pem"
    CLAIM_KEY = "/etc/iot/claim_key.pem"
    ROOT_CA = "/etc/iot/root-CA.crt"
    ENDPOINT = "XXXXXX.iot.ap-northeast-1.amazonaws.com"
    TEMPLATE_NAME = "MyFleetProvisioningTemplate"

    def __init__(self):
        self.mqtt_client = mqtt.Client()
        self.provisioned = False
        self.device_cert = None
        self.device_key = None

    def provision(self, serial_number: str):
        """クレーム証明書を使って固有証明書を取得"""
        # クレーム証明書でTLS設定
        self.mqtt_client.tls_set(
            ca_certs=self.ROOT_CA,
            certfile=self.CLAIM_CERT,
            keyfile=self.CLAIM_KEY,
            tls_version=ssl.PROTOCOL_TLS
        )
        self.mqtt_client.on_connect = self._on_connect
        self.mqtt_client.on_message = self._on_message
        self.mqtt_client.connect(self.ENDPOINT, 8883)

        # CreateKeysAndCertificateのトピックをサブスクライブ
        self.mqtt_client.subscribe(
            "$aws/certificates/create/json/accepted", qos=1)
        self.mqtt_client.subscribe(
            "$aws/provisioning-templates/{}/provision/json/accepted".format(
                self.TEMPLATE_NAME), qos=1)

        # 証明書発行リクエスト
        self.mqtt_client.publish(
            "$aws/certificates/create/json", json.dumps({}), qos=1)

        self.mqtt_client.loop_forever()

    def _on_message(self, client, userdata, message):
        topic = message.topic
        payload = json.loads(message.payload)

        if "certificates/create/json/accepted" in topic:
            # 証明書を受け取ったら、デバイス登録リクエスト
            self.device_cert = payload["certificatePem"]
            self.device_key = payload["privateKey"]

            register_payload = {
                "certificateOwnershipToken": payload["certificateOwnershipToken"],
                "parameters": {
                    "SerialNumber": self._get_serial_number()
                }
            }
            client.publish(
                "$aws/provisioning-templates/{}/provision/json".format(
                    self.TEMPLATE_NAME),
                json.dumps(register_payload), qos=1)

        elif "provision/json/accepted" in topic:
            # 登録完了: 固有証明書を保存
            self._save_device_credentials(
                payload["thingName"], self.device_cert, self.device_key)
            self.provisioned = True
            client.disconnect()

    def _save_device_credentials(self, thing_name, cert, key):
        """デバイス固有の証明書を安全なストレージに保存"""
        with open("/etc/iot/device_cert.pem", "w") as f:
            f.write(cert)
        with open("/etc/iot/device_key.pem", "w") as f:
            f.write(key)
        with open("/etc/iot/device_id", "w") as f:
            f.write(thing_name)
        # クレーム証明書を削除(セキュリティ上重要)
        import os
        os.remove(self.CLAIM_CERT)
        os.remove(self.CLAIM_KEY)

Secure Elementを使ったハードウェアプロビジョニング

マイコンのセキュアエレメント(ATECC608A等)を使うことで、秘密鍵をソフトウェアから読み出せない形で保護できます。

#include "cryptoauthlib.h"

// ATECC608AでCSR(証明書署名要求)を生成
ATCAIfaceCfg cfg = cfg_ateccx08a_i2c_default;
atcab_init(&cfg);

// デバイス固有の公開鍵を取得(秘密鍵はチップ外に出ない)
uint8_t public_key[64];
atcab_get_pubkey(0, public_key);  // スロット0の鍵ペアを使用

// CSRの生成(秘密鍵はチップ内で署名するだけ)
atcacert_client_ctx_t csr_ctx;
uint8_t csr_buf[512];
size_t csr_buf_size = sizeof(csr_buf);
atcacert_create_csr(&csr_template, csr_buf, &csr_buf_size);

// CSRをクラウドに送り、証明書を発行してもらう
// 秘密鍵はチップから一切出ない

用途・ユースケース

大量生産デバイスの工場プロビジョニング

製造ライン上で自動的にデバイスのプロビジョニングを行うフローです。

製造ライン自動化フロー:
1. ボードにMCUを実装
2. 製造検査治具でファームウェア書き込み
3. 治具がクラウドAPIを呼び出し:
   - AWS IoT CoreにThing登録
   - 証明書発行・デバイスへ書き込み
   - デバイスIDとシリアル番号をERPに記録
4. 箱詰め・出荷
5. エンドユーザーが電源オン → 自動でクラウド接続

eSIMリモートプロビジョニング(M2M/IoT向け)

グローバルに出荷するIoTデバイスには、出荷先の国・地域に応じてキャリアのSIMプロファイルを後から書き込むeSIMが有効です。GSMA SGP.02規格のM2MリモートSIMプロビジョニング、またはSGP.32のIoT向けeSIMプロビジョニング仕様が標準です。

Wi-Fi認証情報の配布(BLE/QRコード方式)

家電・スマートホームデバイスのプロビジョニングは、スマートフォンアプリとBLEを組み合わせた方式が一般的です。

1. ユーザーがスマホアプリを起動
2. アプリがBLEでデバイスを検出
3. アプリがWi-Fi SSIDとパスワードをBLE経由でデバイスに送信
4. デバイスがWi-Fiに接続
5. デバイスがクラウドに登録(JITP/DPS)
6. アプリにデバイス登録完了通知

実装・開発のポイント

セキュアプロビジョニングの原則

  1. デバイス固有の秘密鍵は工場外に出さない: HSM/TPMまたはセキュアエレメントで生成
  2. クレーム証明書の権限を最小化: プロビジョニング操作のみに制限
  3. プロビジョニング完了後にクレーム証明書を削除: 再利用・漏洩を防ぐ
  4. プロビジョニング操作のログ記録: 不正登録の検知のため

プロビジョニング状態の管理

/* フラッシュにプロビジョニング状態を保存 */
typedef enum {
    PROV_STATE_UNPROVISIONED = 0,
    PROV_STATE_IN_PROGRESS   = 1,
    PROV_STATE_PROVISIONED   = 2,
    PROV_STATE_FAILED        = 3,
} provisioning_state_t;

typedef struct {
    provisioning_state_t state;
    char device_id[64];
    char endpoint[128];
    uint8_t cert_fingerprint[32];  // 証明書の検証用
    uint32_t provisioned_timestamp;
    uint32_t crc;  // データ整合性チェック
} provisioning_info_t;

/* フラッシュから読み出して状態確認 */
provisioning_info_t prov_info;
flash_read(PROV_INFO_ADDRESS, &prov_info, sizeof(prov_info));

if (crc32(&prov_info, sizeof(prov_info) - 4) != prov_info.crc ||
    prov_info.state != PROV_STATE_PROVISIONED) {
    /* 未プロビジョニング: プロビジョニングシーケンスを実行 */
    start_provisioning();
} else {
    /* プロビジョニング済み: 通常動作 */
    connect_to_cloud(prov_info.endpoint, prov_info.device_id);
}

他技術との比較

方式手間セキュリティスケーラビリティ用途
手動設定非常に高低(人的ミス)少数デバイス
QRコード/アプリ低(ユーザーが操作)消費者向けIoT
JITP(AWS/Azure)低(自動)大量デバイス
Fleet Provisioning低(自動)非常に高産業IoT
eSIMプロビジョニング低(無線)グローバル展開
LoRaWAN OTAA低(自動)LPWAネットワーク

プロビジョニングはIoTプラットフォーム上でのデバイス初期設定であり、フリート管理の前提となるプロセスです。AWS IoT CoreのFleet ProvisioningやAzure IoT HubのAzure IoT HubのDevice Provisioning Serviceが代表的な実装です。通信経路の確立にはeSIMSIMカードのプロビジョニングも含まれます。

関連用語

参考リンク