Amazon Web Services ブログ

ハードウェアセキュリティモジュールと AWS IoT Device SDK による IoT デバイスのセキュリティ強化

この記事は Enhancing IoT device security using Hardware Security Modules and AWS IoT Device SDK の日本語訳です。

はじめに

機密情報を扱うお客様や規制の厳しい市場で事業を行うお客様にとって、業務のセキュリティとデータのセキュリティは最優先事項の一つです。 IoT(Internet of Things) のお客様は、クラウドプラットフォームへの IoT 通信において高いセキュリティ基準を実現するという新たな課題を抱えています。非対称アルゴリズムと暗号鍵によるデータ暗号化は、通信トラフィックを保護するために広く採用されているメカニズムです。

IoT デバイスの暗号鍵に関する最も重要な要件は、悪意のあるユーザーからの直接アクセスを拒否するために、暗号鍵を安全に保管しなければならないことです。秘密鍵が流出すると、悪意のあるユーザーが IoT デバイスになりすまし、企業 IT の機密リソースにアクセスしたり、偽造データを送信したりすることが可能となり、脅威となります。

ハードウェアセキュリティモジュール (HSM) は、秘密鍵の漏洩を防ぐための効果的なハードウェアベースのメカニズムを提供し、デジタルキーや証明書を保護したいお客様の間でトレンドとなっている技術です。しかし IoT デバイスのソフトウェアスタックに組み込むことは容易ではありません。

この記事では IoT 業界の垂直統合におけるセキュリティ課題の注目すべき例を紹介し、模擬ハードウェアセキュリティモジュール AWS IoT Device SDK v2AWS IoT を使用し AWS 上で数行のコードで安全な通信 IoT クライアントの実装のサンプルを提供します。

IoT におけるサイバーセキュリティ:デバイスの機密を保護する

IoT 通信セキュリティの一般的な標準は、デバイスとクラウドの間を移動するデータを保護するために TLS(Transport Level Security layer) を活用することです。例えば AWS IoT Core は IoT トランスポートレベルのセキュリティとして TLS v1.2 と X.509 証明書を採用しています。

セキュアな通信シナリオでは IoT デバイスは、秘密鍵と公開証明書を含む鍵ペアと、サーバー認証局 (CA) チェーンを含むトラストストアを提供されます。この情報はクライアント側のサーバー認証(トラストストアを使用)と、サーバー側のクライアント認証(キーペアを使用)の両方を可能にするために必要です。この方法は Mutual TLS 認証と呼ばれ、以下の図に描かれています。

How mutual authentication of IoT Devices with AWS IoT Core works using TLSv1.2

図1:IoT デバイスと AWS IoT Core 間の相互認証の機能概要

IoT デバイスのソフトウェアと運用を管理するお客様は、そのような秘密のプロビジョニング、保管、利用、およびキーの露出を制限する最終的な責任を負います。 AWS とお客様がワークロードのセキュリティを管理する方法の詳細については、「責任共有モデル」を参照してください。

IoT デバイスの機密漏洩のリスク

IoT 機器の機密漏洩に関するリスクの例としては、以下のようなものがあります。

  • 自動車テレマティクス IoT のお客様は、悪意のある攻撃者が車両になりすまし、偽造データをクラウドに送信したり、企業のデータセンターから機密データをダウンロードしたりするリスクにさらされています。
    2021 年 3 月、国連欧州経済委員会 (UNECE) は、コネクテッドビークルのためのUN Regulations on CyberSecurity (UN R155) および SW Updates (UN R156) を承認・公表しました。この規則の中で、暗号鍵の保管に関するセキュリティ管理が、サイバー脅威に対する緩和措置の提案の中に含まれています。
  • IoT スマートシティのお客様は、接続されたスマート照明柱や交通信号などの運用が改ざんされ、サービス停止や治安の悪化につながるリスクにさらされています。
  • IoT スマートグリッドのお客様は、不正なユーザーが接続されたスマートメーターを改ざんし、中央のグリッドシステムに偽造データを提供することを懸念しています。

しかし、デバイスの機密がどのように漏れるのでしょうか?

一般的なライフサイクルでは IoT デバイスのセキュリティキーは、プロビジョニング、保管、定期的なローテーション、および暗号操作に使用する必要があります。

ライフサイクルの状態 セキュリティ上の脅威 軽減方法
プロビジョニング 外部からの鍵の注入は、悪意のある攻撃者にさらされる危険性があります 秘密鍵はデバイス内で生成し、決して外部に公開しない
保管 悪意のある攻撃者は、デバイスを改ざんしたり、デバイスのソフトウェアを制御して、不揮発性メモリにアクセスすることができます 改ざん防止機構 (HSMなど) を備えたデバイスを使用する。利用できない場合は、ストレージを暗号化することでリスクを軽減することができます
使用 ソフトウェア暗号ライブラリを使用する場合、ソフトウェアは揮発性メモリを通して(暗号化せずに)秘密にアクセスする必要があります。攻撃者は JTAG(Joint Test Action Group) デバッガや同様のメカニズムを通してそれを取得することができます 暗号演算をオフチップで行い、ソフトウェアフロー上で鍵が露出しないようにする

一般的に、デバイスキーをデバイスのメモリ内部やクラウドストレージに保存することは望ましくありません。2020 年に発生した SolarWinds 社のハッキングと呼ばれるセキュリティ事件では、悪意のある攻撃者がお客様の Active Directory Federation Services(ADFS) 内の保護データにアクセスし、システムに保存されていた暗号鍵を収集し、それを使って正規ユーザーになりすまし、機密データを盗み出すことができたという事件がありました。

ハードウェアセキュリティモジュールによる IoT 通信の安全性向上について

HSM(Hardware Security Module) は、暗号チップの形をした物理的なモジュールです。デバイスの基板上にはんだ付けされるか、高速バスに接続されます。そして以下のような機能を提供します。

  • 安全な鍵保管庫とエントロピー・ベースのランダム鍵生成
  • ソフトウェアスタックに公開することなく、オンチップで暗号化処理を実装
  • チップの不揮発性メモリ (NVM) を物理的に保護する高度なアンチタンパリング機構

How Hardware Security Modules (HSM) integrate with business application logic

図2:PKCS#11 API を使用したハードウェアセキュリティモジュールとビジネスアプリケーションの統合の概要

このようなデバイスを使用すると、秘密鍵の生成と暗号化操作がチップ自体で行われるため、顧客はセキュリティ鍵の露出を減らすことができます。

アプリケーションは、特定の目的のために作られた API を通じてデバイスと対話しますが、そのうちの 1 つが業界標準の PCKS#11 または「 Cryptoki 」です。 PKCS#11 API の完全な説明は OASIS PKCS#11 仕様で参照できます。

HSM を使用することで、以下のような秘密鍵の漏洩リスクを軽減することができます。

ライフサイクルの状態 セキュリティー脅威
プロビジョニング 外部からの鍵の注入は、悪意のある攻撃者にさらされる危険性があります
保管 悪意のある攻撃者は、デバイスを改ざんしたり、デバイスのソフトウェアを制御して、不揮発性メモリにアクセスすることができます
使用 ソフトウェア暗号ライブラリを使用する場合、ソフトウェアは揮発性メモリを通して(暗号化せずに)秘密にアクセスする必要があります。攻撃者は JTAG(Joint Test Action Group) デバッガや同様のメカニズムを通してそれを取得することができます

PCKS#11 を通じて HSM をインターフェースすることは、実装が複雑なため IoT エンジニアにとって時間がかかり、困難な作業となる可能性があります。

AWS IoT Device SDKs v2 は HSM ベースのデバイスセキュリティを実装したいお客様を支援し、開発者が数行のコードで PKCS#11 付き HSM を使用して安全な MQTT クライアント接続を実装できるよう専用ライブラリーを提供します。

IoT Device SDK for Python v2 とソフトウェア HSM による IoT デバイスからのセキュアな MQTT クライアントの実装

このブログでは、ハードウェアセキュリティモジュールと AWS IoT Device SDK for Python v2 を使用して AWS IoT Core に MQTT IoT Client をセットアップするために必要な手順を、数行のコードで再現しています。

次の図は、提案するソリューションのアーキテクチャを表しています。

High level architecture diagram to use Hardware Security Modules for AWS IoT Core mutual authentication

図3:IoT デバイスと AWS IoT Core 間のセキュアなIoT通信のための提案ソリューションのハイレベル・アーキテクチャ図

提案する例では OpenDNSSEC プロジェクトの softHSM2 を用いて、ハードウェアセキュリティモジュールとソフトウェア HSM をシミュレートしています。

デバイス証明書は AWS IoT Core に管理された Amazon Root CA によって署名されます。 Private CA を使用する場合は、お客様の適切な公開鍵基盤 (PKI) にリクエストを送信する必要があります。

前提条件

  • AWS のアカウント
  • debian ベースの LinuxPC
  • OpenSSL 3.0+ がインストールされている (インストール手順は、こちらのリンクを参照)
  • Python 3.6+ がインストールされている (インストール手順は、こちらのリンクを参照)
  • softHSM version2 がインストールされている (インストール手順は、こちらのリンクを参照)
  • Amazon RSA 2048 bit rootCA 1 key (ダウンロードは こちらから).

ステップ1:HSM による AWS IoT Core デバイス証明書のプロビジョニング

AWS IoT Core でデバイスの証明書をプロビジョニングし、有効化する必要があります。 HSM のシミュレーションには softHSM2 ソフトウェアを CSR(Certificate Signing Request) の生成には openssl を使用できます。

softHSM2openssl の使い方についてはこのブログの範囲外ですので、それぞれのソフトウェアのドキュメントを参照してください。

必要な手順は以下の通りです。

sudo apt install softhsm
sudo apt install opensc opensc-pkcs11 openssl libengine-pkcs11-openssl
  • トークンを設定し、秘密鍵を生成
sudo softhsm2-util --init-token --free --label <token-label>

このコマンドを実行すると PIN を入力するよう促されますので、指示に従って PIN を覚えておいてください。

  • スロットID を取得

トークンの設定が完了したら、次のコマンドで使用する Slot 番号を取得する必要があります。そのために、以下を実行します。

sudo softhsm2-util --show-slots

以下のような応答があります

Available slots:
Slot <slot-id>
    Slot info:
        Description:      SoftHSM slot ID 0x35927c85
        Manufacturer ID:  SoftHSM project
        Hardware version: 2.6
        Firmware version: 2.6
        Token present:    yes
    Token info:
        Manufacturer ID:  SoftHSM project
        Model:            SoftHSM v2
        Hardware version: 2.6
        Firmware version: 2.6
        Serial number:    aede8dd735927c85
        Initialized:      yes
        User PIN init.:   yes
        Label:            <token-label>
Slot 1
    Slot info:
        Description:      SoftHSM slot ID 0x1
        Manufacturer ID:  SoftHSM project
        Hardware version: 2.6
        Firmware version: 2.6
        Token present:    yes
    Token info:
        Manufacturer ID:  SoftHSM project
        Model:            SoftHSM v2
        Hardware version: 2.6
        Firmware version: 2.6
        Serial number:
        Initialized:      no
        User PIN init.:   no
        Label:

前のコマンドに関連するラベルがどのスロットにあるか確認し、その ID (Slot <slot-id> 行の左側にあるもの) を取得します。

  • 証明書を生成

softHSM2 上でトークンを生成し <slot-id> を取得したら pkcs11-tool を使って、その中にキーペアを生成することができます。そのためには、以下のコマンドで <PIN><token-lable> のプレースホルダーを置き換えてください。

注意:モジュールパス /usr/lib/softhsm/libsofthsm2.so は ubuntu のようなインスタンスのマシンを基準にしています。テストする環境によっては異なる場合があります。

sudo pkcs11-tool -l --pin <PIN> --keypairgen --hash-algorithm "SHA256" --key-type RSA:2048 --label <token-label> --slot <slot-id> --module /usr/lib/softhsm/libsofthsm2.so

以下のような応答があります

Key pair generated:
Private Key Object; RSA
  label:      <token-label>
  Usage:      decrypt, sign, unwrap
  Access:     sensitive, always sensitive, never extractable, local
Public Key Object; RSA 2048 bits
  label:      <token-label>
  Usage:      encrypt, verify, wrap
  Access:     local
  • openssl と softHSM2 を使用して Certificate Signing Request を作成します(ウォークスルーのサンプルはこのリンクを参照)
  • 長さ 2048 ビット、SHA256 アルゴリズムの RSA 鍵を生成することができます。サポートされる証明書署名アルゴリズムの完全なリストについては AWS IoT Core のドキュメントを参照してください。
sudo openssl req -new -engine pkcs11 -keyform engine -key “pkcs11:object=<token-label>;pin-value=<PIN>” -out certificate.csr

このコマンドは、署名要求に埋め込む証明書情報を入力するよう促します。

  • 以下のコマンドで Certificate Signing Request に正しい情報が入力されているかどうかを確認
openssl req -in certificate.csr -noout -text
  • 以下の AWS CLI コマンドを実行し CSR を使用してデバイス証明書を生成
aws iot create-certificate-from-csr \
  --set-as-active \
  --certificate-signing-request=file://certificate.csr

コマンドを実行すると、証明書の Amazon Resource Name(ARN) と内容が表示されます。

{
   "certificateArn": "arn:aws:iot:{region}:{accountId}:cert/{certificateId}",
   "certificateId": "{certificateId}",
   "certificatePem": "<certificate-text>"
}
  • 以下の AWS CLI コマンドを使用して、公開証明書を deviceCertificate.pem というファイルにデバイスに格納
aws iot describe-certificate \
  --certificate-id "{certificateId}"| jq -r ".certificateDescription.certificatePem" > deviceCertificate.pem
  • “iot:Connect“ のみのアクション権限を持つIoT Policyを表すpolicy.jsonというファイルを作成
{
   "Version": "2012-10-17",
   "Statement": [
        { 
           "Effect": "Allow",
           "Action": "iot:Connect",
           "Resource": "arn:aws:iot:{region}:{accountId}:client/${iot:Connection.Thing.ThingName}"
        }
   ]
}

{region}{accountId} を置き換えることを忘れないでください

  • 以下の AWS CLI コマンドで AWS IoT Core に IoT ポリシーリソースを作成
aws iot create-policy \
  --policy-name HSMDevicePolicy \
  --policy-document file://policy.json
  • AWS IoT Core で ‘thing’ を作成し IoT ポリシーを証明書に紐付け、証明書を ‘thing’ に紐付けます ( {certificateArn} を先ほど取得した値に置き換えてください)。
aws iot create-thing \
  --thing-name HSMDevice
aws iot attach-policy \
  --target "{certificateArn}" \
  --policy-name "HSMDevicePolicy"
aws iot attach-thing-principal \
  --thing-name HSMDevice \
  --principal "{certificateArn}"

ステップ2:AWS IoT Device SDK v2 を利用してクライアントをセットアップ

AWS IoT Device SDK v2 を使用すると 1 行のコードで IoT クライアントを作成し、 HSM を使用して MQTT 接続を確立することができます。

以下の例では Python を使用していますが、この機能は AWS IoT Device SDK v2 のすべてのターゲット言語で利用可能です(一覧はこのリンクからご覧ください)。

前提条件

  • PKCS#11 libso が HSM で利用可能である (softHSM の場合、通常 /usr/lib/softhsm/libsofthsm2.so で見つかります)。このファイルは AWS IoT Device SDK v2 から適切に接続を設定するために必要です
  • クライアントを実行する前に、以下の Python モジュール(およびその依存関係)をインストールする必要があります。
    sudo pip3 install awsiotsdk
  • 以下の内容で client.py というファイルを作成します。
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0.

from awscrt import io
from awsiot import mqtt_connection_builder
from uuid import uuid4
import argparse
import sys

# Callback when connection is accidentally lost.
def on_connection_interrupted(connection, error, **kwargs):
    print("Connection interrupted. error: {}".format(error))

# Callback when an interrupted connection is re-established.
def on_connection_resumed(connection, return_code, session_present, **kwargs):
    print("Connection resumed. return_code: {} session_present: {}".format(return_code, session_present))

if __name__ == '__main__':
    # Create a connection using websockets.
    # Note: The data for the connection is gotten from cmdUtils.
    # (see build_pkcs11_mqtt_connection for implementation)

    parser = argparse.ArgumentParser(description='Input arguments for PKCS#11 MQTT Client.')
    parser.add_argument("--pcks11lib", type=str , help="path to pkcs11 library")
    parser.add_argument("--slot", type=int , help="HSM slot")
    parser.add_argument("--pin", type=str , help="HSM slot pin")
    parser.add_argument("--tokenlabel", type=str , help="HSM token label")
    parser.add_argument("--keylabel", type=str , help="HSM ptivate key label")
    parser.add_argument("--certpath", type=str , help="device certificate file path")
    parser.add_argument("--endpoint", type=str , help="AWS IoT Core endpoint")
    parser.add_argument("--cafile", type=str , help="CA certificate file path")
    parser.add_argument("--clientid", type=str , help="clientId to use for MQTT connection")

    if len(sys.argv)==1:
        parser.print_help(sys.stderr)
        sys.exit(1)
    args = parser.parse_args()
    
    # We load the HSM library
    pkcs11_lib_path = args.pcks11lib
    print(f"Loading PKCS#11 library '{pkcs11_lib_path}' ...")
    pkcs11_lib = io.Pkcs11Lib(
        file=pkcs11_lib_path,
        behavior=io.Pkcs11Lib.InitializeFinalizeBehavior.STRICT)
    print("Loaded!")

    pkcs11_slot_id = args.slot
    pkcs11_pin = args.pin
    pkcs11_tokenlabel = args.tokenlabel
    pkcs11_keylabel = args.keylabel
    certpath = args.certpath
    endpoint = args.endpoint     
    cafile = args.cafile 
    clientid = args.clientid

    # This is the core section of the example client. 
    # This single instruction instantiates an MQTT connection 
    # and performs encyrption operations using your HSM
    # through the mqtt_connection_builder.mtls_with_pkcs11 method
    mqtt_connection = mqtt_connection_builder.mtls_with_pkcs11(
        pkcs11_lib          =   pkcs11_lib,
        user_pin            =   pkcs11_pin,
        slot_id             =   pkcs11_slot_id,
        token_label         =   pkcs11_tokenlabel,
        private_key_label   =   pkcs11_keylabel,
        cert_filepath       =   certpath,
        endpoint            =   endpoint,
        port                =   8883,
        ca_filepath         =   cafile,
        on_connection_interrupted   =   on_connection_interrupted,
        on_connection_resumed       =   on_connection_resumed,
        client_id           =   clientid,
        clean_session       =   False,
        keep_alive_secs     =   30)

    connect_future = mqtt_connection.connect()

    # Future.result() waits until a result is available
    connect_future.result()
    print("Connected!")

    # Disconnect
    print("Disconnecting...")
    disconnect_future = mqtt_connection.disconnect()
    disconnect_future.result()
    print("Disconnected!")

上記のクライアント実装の重要なのは AWS IoT Device SDK v2 の awsiot.mqtt_connection_builder.mtls_with_pkcs11() メソッドです。 このメソッドは HSM を使って暗号化操作を実行し、安全な MQTT 接続を確立する役割を担っています。

メソッドの入力パラメータは:

パラメータ 説明
pkcs11_lib pkcs11 ライブラリへのリンク(softHSM の場合、これは通常 /usr/lib/x86_64-linux-gnu/softhsm/libsofths2.so にあります)。
user_pin HSM の ユーザー PIN
slot_id 秘密鍵のスロット ID
token_label 秘密鍵のトークンラベル
private_key_label 秘密鍵のラベル
cert_filepath deviceCertificate.pem ファイルへのパス
ca_filepath AmazonRootCA1.pem ファイルへのパス
client_id AWS IoT Core の接続に使用する clientID
port MQTT 接続に使用するポート

この例では、パラメータはコマンドライン引数を通して指定されます

ステップ3:セキュアな接続をテスト

以下の CLI コマンドで MQTT 接続のエンドポイントを取得することができます。

aws iot describe-endpoint \
  --endpoint-type iot:Data-ATS

endpointAddress フィールドの内容を後で使用する環境変数に入れます。

export IOT_CORE_ENDPOINT=<endpointAddress>

HSM ライブラリにアクセスできるように Python3 の実行ファイル (python3) を sudo 権限で使用し、上記スクリプトを実行します。

sudo python3 client.py --pcks11lib /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so \
 --pin <PIN> \
 --tokenlabel <token-label> \
 --certpath deviceCertificate.pem \
 --endpoint ${IOT_CORE_ENDPOINT} \
 --cafile AmazonRootCA1.pem \
 --clientid HSMDevice

実行に成功すると、次のように返されるはずです。

Loading PKCS#11 library '/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so' ...
Loaded!
Connected!
Disconnecting...
Disconnected!

リソースのクリーンアップ

登録済み証明書から ‘thing’ と IoT Policy の紐付けを解除します

aws iot detach-policy \    
    --target "{certificateArn}" \
    --policy-name "HSMDevicePolicy"
aws iot detach-thing-principal \    
    --thing-name HSMDevice \
    --principal "{certificateArn}"

デバイス証明書、‘thing’ 、IoT Policy を削除します

aws iot delete-thing \
    --thing-name HSMDevice
aws iot delete-certificate \
    --certificate-id "{certificateId}"
aws iot delete-policy --policy-name "HSMDevicePolicy"

まとめ

この投稿では IoT デバイス群の鍵/機密管理で直面するいくつかの課題と、ハードウェアセキュリティモジュールを採用することで対処できる方法について説明しました。また AWS IoT Device SDK v2 を使用して、数行のコードで暗号チップを使用したシンプルな MQTT クライアントを作成する方法について説明しました。

これらの提案を採用することで、お客様は悪意のあるユーザーによるセキュリティキーの流出を防ぎ、デバイスの全体的なセキュリティ体制を強化することができます。

AWS IoT Core の使用方法については、ドキュメントを参照することができます。

翻訳者について

Daniele Crestini

Daniele Crestini

Daniele は AWS Professional Services の IoT データ・コンサルタントです。AWS クラウド上で AWS IoT サービスを活用した革新的なソリューションを設計・構築し AWS カスタマーのビジネスゴール達成を支援しています。

 

Iacopo Palazzi

Iacopo Palazzi

Iacopo はミラノを拠点とする AWS Professional Services チームで働く IoT エンジニアです。彼は、ソフトウェア開発と DevOps に情熱を持ち、それらを使って AWS の顧客のために堅牢でスケーラブルで革新的なアーキテクチャを実装しています。

この記事は IoT Prototyping Solutions Architect の市川が翻訳しました。