概要
プロビジョニング(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. アプリにデバイス登録完了通知
実装・開発のポイント
セキュアプロビジョニングの原則
- デバイス固有の秘密鍵は工場外に出さない: HSM/TPMまたはセキュアエレメントで生成
- クレーム証明書の権限を最小化: プロビジョニング操作のみに制限
- プロビジョニング完了後にクレーム証明書を削除: 再利用・漏洩を防ぐ
- プロビジョニング操作のログ記録: 不正登録の検知のため
プロビジョニング状態の管理
/* フラッシュにプロビジョニング状態を保存 */
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が代表的な実装です。通信経路の確立にはeSIMやSIMカードのプロビジョニングも含まれます。