Amazon Web Services ブログ

AWS IoT Coreでブートストラップ証明書を使ったプロビジョニング

IoTデバイスを管理する上で、プロビジョニングは一つの重要な事項です。プロビジョニングとは、IoTデバイスをプラットフォームあるいはシステムに登録するプロセスです。デバイスのブートストラップ処理において、中間者攻撃などを防止するために、デバイスとIoTエンドポイントの間で相互認証を確立することが大事です。デバイス認証で現状最もセキュアな方法はデバイス証明書を使用することであり、一般的にデバイスアイデンティティ管理の第一選択肢でもあります。

このブログでは、AWS IoT CoreAWS IoT Device Managementでブートストラップ証明書を使ったプロビジョニング方法について深掘りしていきます。AWS IoT Coreは、接続されたデバイスがクラウドのアプリケーションや他のデバイスとセキュアかつ簡単に通信することを実現するマネージド型のクラウドサービスです。AWS IoT Device Managementは大規模なIoTデバイスのセキュアなオンボード、管理、モニタリング、遠隔操作を実現するサービスです。

ブートストラップ証明書とは?なぜ必要なのか?

今回は、WiFi接続が可能な歯ブラシを取り扱う”SmartTeeth”という架空な会社のユースケースについて考えていきましょう。SmartTeethは歯ブラシの生産をサードパーティに委託しています。サードパーティの生産会社は、歯ブラシがクラウドと繋がる際のデバイス証明書を歯ブラシに組み込む必要があります。ただし、SmartTeethは歯ブラシが顧客の手元に届いてから、クラウドとどのような通信を許可するか制限したいと考えています。

初期の証明書は、歯ブラシがクラウドに繋がって自分自身を登録し、必要な権限一式が付与された証明書をリクエストすることのみを許可している状況が理想的です。さらに、このプロセスが自動化されており、SmartTeethの顧客からは透過的であること、そして歯ブラシが初めて接続する時、クラウドで必要なリソースが全て作成され、初期の証明書と実用フェーズの証明書を入れ替える部分をファシリテートする形が理想的です。

以下の図は歯ブラシの購入後に初期クレデンシャルを実用フェーズのクレデンシャルに置き換えるフローを示しています。

 

 

とあるSmartTeethの顧客がブートストラップ証明書をインストールするとします。ブートストラップ証明書は、デバイスの生産段階で各デバイスに実装される一意で低レベルの権限を持つ証明書です。この証明書には、デバイスがIoT Coreに接続し、最終的な証明書を取得するための特定のMQTTトピックとやりとりをする権限のみが定義されたAWS IoTポリシーが紐づいています。

デバイスプロビジョニングワークフロー

ブートストラップ証明書を利用したデバイスプロビジョニングには3つのステップが含まれます:

  1. デバイス組立
  2. デバイス登録
  3. デバイスアクティベーション

デバイス組立

デバイス組立とはデバイス生産プロセスにおいてサプライヤーが証明書をデバイスに埋め込むタイミングを指しています。このタイミングで一意なブートストラップ証明書がデバイスに格納されます。

このアプローチでは以下の条件を満たす必要があります:

  • CA証明書がAWS IoT Coreに登録されており、デバイス証明書の自動登録が有効化されている
  • デバイスには登録されたCA証明書によって署名されたデバイス証明書が生産時に格納されている

デバイス登録

デバイス登録とはAWS IoT Coreのモノ(thing)としてデバイスを登録することを指しています。このプロセスでは以下の項目を実施する必要があります:

  • AWS IoT Coreでモノとブートストラップ証明書を登録する
  • IoTポリシーを作成し、ブートストラップ証明書にアタッチする
  • ブートストラップ証明書とモノを関連づける
  • 実用フェーズの証明書を(inactive状態で)AWS IoT Coreでプロビジョンする
  • モノをAWS IoT モノのグループに、またはタイプを追加する

ただし、これらを実施する前に、一つ重要なステップがあります。デバイスのサプライヤーは許可されたデバイスのリストを提供する必要があります(これをホワイトリストとも呼びます)。このファイルはデバイスIDのリストのみ、または他の属性情報を含んでいても構いません:

cat ./allowed-device-list.txt
demo001
demo002
demo003

デバイス登録プロセスでは、許可されたデバイスのリストに照会し、そのデバイスがサプライヤーにより保証されていることを確認します。また、ブートストラップ証明書が顧客指定のCAによって署名されていることも確認します。

デバイスの登録プロセスを発動させるにはいくつかの方法があります。今回のユースケースでは、AWS IoT CoreのJust-in-time registration (以下JITR)方式を使って実現します。

JITR方式を使ってデバイス登録を行うには、以下条件を満たす必要があります。

  • デバイスが登録しようとしているデバイスIDが証明書のCommon Nameに埋め込まれている
  • 許可されたデバイスのリストがS3などのAWSサービスに保管されている

以下が具体的にJITRの流れを示します:

  1. デバイス(モノ)がブートストラップ証明書を使用してAWS IoT CoreにMQTTプロトコルで接続する
  2. JITRを使い、AWS IoT Coreが登録済みのCAによって署名された未登録の証明書が存在することを検知します。その後、証明書は自動的に登録され、デバイスの接続を切断します
  3. 切断時に証明書を有効化するLambdaがトリガーされ、許可されたデバイスのリストにデバイスについて照会をします
  4. 確認の結果問題がなければ、Lambdaは証明書を有効化します。Lambdaは同時にデバイスプロビジョニングのワークフローをトリガーします。ワークフローでは、証明書とポリシーの紐付けや、モノのグループ、タイプの設定などを行います。

デバイスアクティベーション

デバイスアクティベーションとはデバイスが初めてパワーオンになり、ブートストラップ証明書を用いてAWS IoT Coreエンドポイントに接続する時を指しています。この接続で、デバイスは必要な権限が付与されている証明書をダウンロードします。全体のフローは以下のようになっています:

  1. デバイスはブートストラップ証明書を使用してAWS IoT Coreに接続し、証明書ローテーションジョブが送られてきます
  2. デバイスは”get certificate”メッセージを送信します
  3. 証明書ローテーションのLambdaは運用フェーズの証明書の署名付きURLを発行し、デバイスに送信します
  4. デバイスはS3バケットから運用フェーズの証明書をダウンロードします
  5. デバイスは証明書をローテートし、AWS IoTエンドポイントに再接続します

以下の図はこの一連の流れを示しています。

ベストプラクティスとしてある最小権限付与にしたがって、ブートストラップ証明書は上記手順を実行する権限のみが付与されています。具体的には以下が権限で許可されています:

  • 自身のデバイスIDをMQTTクライアントIDとしてAWS IoT Coreに接続する
  • デバイスの特定のIoT Jobトピックへサブスクライブする
  • 証明書のローテーションに必要がMQTTトピックへのパブリッシュとサブスクライブ

今回使用されるAWS IoTデバイス管理の重要な機能の一つは、連続ジョブです。ワンタイムの初期セットアップイベントとして、証明書をローテートさせる連続ジョブは一つのAWS IoTモノのグループをターゲットとすることが可能です。デバイスの登録プロセスにおいて、新たに登録されたデバイスはこのグループに追加されます。そして、デバイスの初回接続時に証明書をローテートさせるジョブが自動的にキューイングされます。

デバイスがAWS IoT Coreエンドポイントに接続する時、以下のAWS IoTトピックにサブスクライブします:

$aws/things/{thingName}/jobs/notify-next および $aws/things/{thingName}/jobs/get/+.

AWS IoT ジョブから返答されるジョブドキュメントには、証明書をローテートするためにパブリッシュ・サブスクライブする必要があるトピックが含まれます。ジョブドキュメントの例を以下に挙げます:

{
  "get": {
    "subscribe": "certificates/{thingName}/get/+",
    "publish": "certificates/{thingName}/get"
  },
  "ack": {
    "subscribe": "certificates/{thingName}/ack/+",
    "publish": "certificates/{thingName}/ack"
  }
}

デバイスはジョブドキュメントで指定されているget.subscribe (certificates/{thingName}/get/+)トピックにサブスクライブし、その次に空メッセージをget.publish (certificates/{thingName}/get)トピックにパブリッシュします。

AWS IoT Coreはメッセージを証明書ローテーションLambda関数にルーティングします。これにはMQTTトピックcertificates/+/getをモニタリングするAWS IoTルールアクションが使われており、受信した全メッセージをLambda関数にルーティングします。以下はAWS IoT Coreから送信されるメッセージ(AWS IoT ルールによるpostメッセージの変換)の一例です:

{
  "deviceId": "device123",
  "action": "get"
}

リクエストを受信すると、証明書ローテーションLambda関数はデバイスが許可されたリストに存在することを確認します。確認が取れたら、以下を実行します:

  1. 証明書パッケージに関連するS3オブジェクトメタデータをダウンロードし、certificateIdを取得
  2. 証明書をアクティベート
  3. デバイスが証明書パッケージをダウンロードできる署名付きURLを生成し返答する

以上をもってデバイスステータスはactivatedに更新されます。

以下は成功時に証明書ベンダーよりデバイスに送信されるレスポンスの例です。これはMQTTトピックcertificates/{thingName}/get/accepted にパブリッシュされます:

{
  "location": "https://certificatevendor-us-west-2.s3.amazonaws.com/certificates/device123.zip?AWSAccessKeyId=xxxxxxx&Expires=1542129538&Signature=xxxxx"
}

もし途中何かの理由で失敗した場合、拒否メッセージがMQTTトピック certificates/{thingName}/get/rejected にパブリッシュされ、デバイスに送信されます。以下が一例です:

{
  "message": "DEVICE_NOT_WHITELISTED"
}

新しい証明書の準備が完了したら、デバイスはack.subscribeトピックにサブスクライブします(具体的にはcertificates/{thingName}/ack/+トピックです)。その後、デバイスは空メッセージをack.subscribe (certificates/{thingName}/ack)トピックにパブリッシュし、証明書ローテーションLambda関数にアクティベーションの成功を通知します。Lambda関数はこれらの成功通知用のトピックにサブスクライブしており、デバイスを登録デバイスグループより削除します。

以上をもって、デバイスは新しい証明書の取得プロセスを完了しました。この証明書にはより広い権限を持ったポリシーがアタッチされているため、デバイスは設計通りクラウドのリソースと通信することが可能になります。

セキュリティベストプラクティス

デバイスはMQTTプロトコルで最終的な証明書をセキュアにダウンロードするための署名付きURLをリクエストします。デバイス特有のプロファイルを作成し、そのデバイスのブートストラップ証明書と紐づけ、デバイスがMQTT clientIdに自身のThingNameを使用するよう強制します。これにより、自身のために用意された証明書にのみアクセスを制限できます。

ブートストラップ証明書にはもう一つの汎用プロファイルが紐づけられています。このプロファイルはデバイスがAWS IoTジョブからの指示を受け付けられるようにするもので、具体的にはリクエストのパブリッシュや証明書ローテーションLambda関数からレスポンスを受信することが許可されています。許可されたデバイスのリストに記載がある場合のみ新しい証明書が発行されます。

もう一つのセキュリティベストプラクティスは明示的に証明書のローテーションを要求するAPIを発行することです。これは許可されていないデバイス(例えば盗難されたデバイスや第三者によって許可なく実装されたデバイスなど)を制限するための仕組みになります。

最後に、許可されたデバイスのリストの補足案/代替案として、証明書ブラックリストという選択肢もあります。これは証明書失効リスト(Certification Revocation List, CRL) とも呼びます。この場合、証明書ローテーションLambda関数は証明書を有効化する前に(Amazon S3に保存された) CRLに照会します。

最後に

このブログでは、デバイスの権限を実際のエンドユーザーの手元に届くまでの間制限する手法について紹介しました。このプロビジョニングフローの技術的要点を以下にまとめます:

  • サーバーレスコンピューティング (API Gateway, Lambda)を使ってマイクロサービスを構築します。通常、プロビジョニングはワンタイムプロセスであり、デバイスのライフサイクルにおいては継続的でありません。継続的にコストが発生するサーバー(Amazon EC2)もしくはコンテナ(Amazon ECS、Amazon EKS) は必要ありません。
  • Just-in-time registration (JITR)を使ってグローバルなプロビジョニングを自動化します。
  • AWS IoTジョブをトリガーとし最終的な証明書を入手することでデバイスの起動ルーチンにハードコーディングする必要がなくなります。これにより、セキュリティ違反が発生してもこの機能を再利用して新しい証明書を発行、もしくは既存の証明書をローテートすることができます。AWS IoT Device Defenderを使って証明書更新やセキュリティ違反をトラッキングし、証明書ローテーションジョブを開始することが可能です。

翻訳はソリューションアーキテクト金杉が担当しました。原文はこちらです。