メモ

ACTABAのホームページ

TOP > AWS IoTを試してみた

見出し

AWS IoTを試してみたのでそのメモ。(2021/3)

AWS IoTとは?!

Amazon Web ServiceのIoTは、Amazonのドキュメントによると、

AWS IoT は、IoT デバイスを他のデバイスや AWS クラウドサービスに接続するクラウドサービスを提供します。 AWS IoT は、IoT デバイスを AWS IoT ベースのソリューションに統合するのに役立つデバイスソフトウェアを提供します。 デバイスが AWS IoT に接続できる場合、AWS IoT は AWS が提供するクラウドサービスに接続できます。
とのこと。
参考:AWS IoT とは?(https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/what-is-aws-iot.html)

AWS IoTを使用するとIoT向けのプロトコル(MQTTなど)を簡単に利用できる。また、AWSの各ソリューションとの連携も容易にできる。
一方で、AWS IoTをMQTT ブローカーのみとして利用することも可能となっている。
今回、Pythonを使ってAWS IoTでMQTTを使用してみたので、それについて記載する。

実施した環境

使用した環境は次の通り。

  • サーバ(MQTTサーバ/ブローカー)
    • AWS IoT
  • クライアント(その1)
    • Python 3.8.8(msi版)
      ※Python 3.9.2は「AWS IoT SDK for Python v2」インストール時にエラーで断念
    • AWS IoT SDK for Python v2
    • Windows 10
    • Visual Studio Code
  • クライアント(その2)
    • AWS IoT テスト(AWS WEBコンソールで使用できるテストツール
  • 環境の構築

    実施した環境」にも記載したが、環境の構築は一筋縄ではいかなかった。
    Pythonのバージョンによっては、AWS IoTのSDKがインストールできなかったからだ。
    AWS が Lambda で Python 3.8をサポートした記事はあったが、Python 3.9のサポートについて記事が無かったことに気づけばよかったのかもしれない。
    AWSの最新情報は見た方がよいです。
    参考:AWS の最新情報(https://aws.amazon.com/jp/new/)

    Visual Studio CodeでPythonを扱えるように設定する。
    設定は以下のサイトを参考にpythonをセットアップした。
    参考:https://code.visualstudio.com/docs/python/python-tutorial

    Visual Studio Codeのインストール

    Visual Studio Codeをインストールしていない場合は下記URLからインストールする。
    バージョンは最新でOK。
     https://code.visualstudio.com/

    VSCodeの拡張機能のインストール

    次に「Python extension for Visual Studio Code」をインストールする
    似たような拡張機能が複数あるので、他の拡張機能と間違えないように注意する。
    インストール手順は下記。

    1.WEBブラウザで「Python extension for Visual Studio Code」のURL(下記)を表示する。
     https://marketplace.visualstudio.com/items?itemName=ms-python.python

    2.ページ内の「Install」をクリックする。
    Screenshot

    3.「Visual Studio Codeを開きますか?」のメッセージが表示されるので、「Visual Studio Codeを開く」をクリックする。
    Screenshot

    4.Visual Studio Codeで「Python extension for Visual Studio Code」が表示されるのでインストールする。
     (下図はインストール済みの画面) Screenshot
    これで、「Python extension for Visual Studio Code」のインストールは完了。

    Pythonのインストール

    Python 3.8.8をインストールする。
    今回はmsiでPythonをインストールするので、すでに他のバージョンをインストールしている場合はアンインストールすることをお勧めする。
    複数バージョンを同居させる場合は、使用するバージョンに注意する。

    今回設定するPython 3.8.8のインストール手順は下記の通り。

    1.Python 3.8.8をダウンロードする。ダウンロードページのURLは下記。
     https://www.python.org/downloads/release

    Python 3.9.2で発生したエラー
    Python 3.9.2では「AWS IoT SDK for Python v2」のインストールで失敗した。
    コマンドプロンプトで
     > pip install awsiotsdk
    を実行すると下記のようなエラーが表示されてしまう。
    Screenshot
    Screenshot

    下記の情報があり、現時点では未解決となっている。
    https://github.com/aws/aws-iot-device-sdk-python-v2/issues/150
    上記URLの記事の中で、python3.8では動作したとの記載がり、Pyhton 3.8.8で試したところ成功した。

    2.Python 3.8.8をインストールしたら、下記コマンドでバージョンを確認する。

    >py -3 --version
    Python 3.8.8
    インストールが成功していれば「Python 3.8.8」が表示される。

    3.Pythonではプロジェクトでいろいろなライブラリを使用するので、プロジェクトごとに参照するパッケージを設定するために仮想環境を設定する。
    コマンドプロンプトを表示して下記コマンドを実行する。
    フォルダ「c:\iot-test」は今回作成するPythonのファイルを保存フォルダに置き換えてください。

    cd c:\iot-test
    py -3 -m venv .venv
    .venv\scripts\activate

    4.Visual Studio Codeで「ctrl+Shift+P」を押して、「Python: Select Interpreter」を選択する。
    Pythonの環境が選択できるので、「Python 3.8.8 64-bit (.venv)」を選択する。(仮想環境作成のコマンドで「.venv」以外の名前を指定した場合は、その名前の環境を選択する)
    この後「pip」コマンドでインストールしたパッケージはこのプロジェクト環境(.venv)のみに適用される(らしい)。

    AWS IoT SDK for Python のインストール

    「AWS IoT SDK for Python v2」をインストールします。 インストール手順は下記の通り。

    1.Visual Studio Codeで「ctrl+Shift+@」を押して、Terminalを表示します。 コマンドプロンプトが、下記のように仮想環境の名称(.venv)がついていると思います。

     (.venv) c:\iot-test>
    ついていない場合は、カレントフォルダを「c:\iot-test>」に変更して、
     c:\iot-test>.venv\scripts\activate
    を実行します。

    2.Terminalで下記コマンドを実行します。

    pip install awsiotsdk
    成功すると下記のようなメッセージが表示されます。
    Screenshot

    Python のプログラム

    下記サイトを参考にpythonクライアントを構築した。
    https://aws.amazon.com/jp/premiumsupport/knowledge-center/iot-core-publish-mqtt-messages-python/

    Pythonのソースコードは下記。
    ほとんど元のソースコードのまま。変更点は接続時のポート番号を443と明記したくらい。
    Visual Studio Codeで「publish.py」との名前でファイルを作成する。

    # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
    # SPDX-License-Identifier: MIT-0
    
    from awscrt import io, mqtt, auth, http
    from awsiot import mqtt_connection_builder
    import time as t
    import json
    
    # Define ENDPOINT, CLIENT_ID, PATH_TO_CERT, PATH_TO_KEY, PATH_TO_ROOT, MESSAGE, TOPIC, and RANGE
    ENDPOINT = "XXXXXXXXXXXXXXXXXX.iot.ap-northeast-1.amazonaws.com"
    CLIENT_ID = "testDevice"        # Test-Thing
    PATH_TO_CERT = "certificates/XXXXXXXXXXXXXXXXXX-certificate.pem.crt"
    PATH_TO_KEY = "certificates/XXXXXXXXXXXXXXXXXX-private.pem.key"
    PATH_TO_ROOT = "certificates/AmazonRootCA1.pem"
    MESSAGE = "Hello World"
    TOPIC = "replaceWithATopic/1"
    RANGE = 20
    
    # Spin up resources
    event_loop_group = io.EventLoopGroup(1)
    host_resolver = io.DefaultHostResolver(event_loop_group)
    client_bootstrap = io.ClientBootstrap(event_loop_group, host_resolver)
    mqtt_connection = mqtt_connection_builder.mtls_from_path(
                endpoint=ENDPOINT,
                port=443,
                cert_filepath=PATH_TO_CERT,
                pri_key_filepath=PATH_TO_KEY,
                client_bootstrap=client_bootstrap,
                ca_filepath=PATH_TO_ROOT,
                client_id=CLIENT_ID,
                clean_session=False,
                keep_alive_secs=6
                )
    print("Connecting to {} with client ID '{}'...".format(
            ENDPOINT, CLIENT_ID))
    # Make the connect() call
    connect_future = mqtt_connection.connect()
    # Future.result() waits until a result is available
    connect_future.result()
    print("Connected!")
    # Publish message to server desired number of times.
    print('Begin Publish')
    for i in range (RANGE):
        data = "{} [{}]".format(MESSAGE, i+1)
        message = {"message" : data}
        mqtt_connection.publish(topic=TOPIC, payload=json.dumps(message), qos=mqtt.QoS.AT_LEAST_ONCE)
        print("Published: '" + json.dumps(message) + "' to the topic: '" + TOPIC + "'")
        t.sleep(0.1)
    print('Publish End')
    disconnect_future = mqtt_connection.disconnect()
    disconnect_future.result()
    			

    ソースコード内の下記はAWS IoTの管理コンソールから取得する必要がある。

    ENDPOINT = "XXXXXXXXXXXXXXXXXX.iot.ap-northeast-1.amazonaws.com"
    PATH_TO_CERT = "certificates/XXXXXXXXXXXXXXXXXX-certificate.pem.crt"
    PATH_TO_KEY = "certificates/XXXXXXXXXXXXXXXXXX-private.pem.key"
    PATH_TO_ROOT = "certificates/AmazonRootCA1.pem"
    ENDPOINTは、AWSのエンドポイントURL、
    PATH_TO_CERTは、クライアント証明書
    PATH_TO_KEYは、クライアントのプライベートキー
    PATH_TO_ROOTは、サーバ証明書
    となっている。

    下記のTOPICの値を変えたときに動作がどのように変わるかをみることにする。
    TOPIC = "replaceWithATopic/1"

    AWS IoTのWEBコンソールの設定

    AWSの利用規約では画面キャプチャのネット掲載は許可されていなさそうなので、画面キャプチャは載せていないです。

    AWS IoTのWEBコンソールで下記を設定します。
    ・モノ
    ・証明書(クライアント証明書)
    ・ポリシ

    証明書は、モノひとつづつか、ロット単位で変更する想定でWEBコンソールを確認するとよさそう。
    IoTの場合は、モノがリバースエンジニアリング可能性が高いため、リスクヘッジのためにすべてのモノで同じクライアント証明書を使用するのは避けたほうがよさそうです。
    ポリシはサービス単位で作成を想定したほうがよさそうです。

    モノと証明書の作成

    1. AWS IoT Coreコンソールを表示します。
    下記のリンク、またはログインして画面上部の検索欄に「iot」と入力すると、候補に「IoT Core」がっ表示されますので、それを選択します。
    https://console.aws.amazon.com/iot/

    2. 左のメニューで[管理]-[モノ]の順に選択します。
    「作成」または「モノを登録」ボタンをクリックします。

    3. 「単一のモノを作成する」をクリックします。
    複数登録する場合は「多数のモノの作成」をクリックできますがここでは触れません。

    4. 必須項目を入力します。
    必須項目は「名前」のみです。
    「名前」は管理画面で表示する上の名前です。識別子しやすい名前がよいでしょう。
    使用できる文字は英数字と「-_:」です。(2021/3時点)
    ここでは「名前」を「Test-Thing-1」とします。
    入力後「次へ」をクリックします。

    5. 「モノに証明書を追加」画面が表示されます。
    いろいろなオプションがあるので、運用に合わせて導入できそうです。
    今回はテストなので、簡単に利用できる「1-Click 証明書作成 (推奨)」にします。
    「1-Click 証明書作成 (推奨)」欄の「証明書を作成」ボタンをクリックします。

    6. 「証明書が作成されました!」画面が表示されます。
    なんとすぐに作成されました!
    「このモノの証明書」と「プライベートキー」はここでしかダウンロードできませんので、必ずダウンロードします。
    右にある「ダウンロード」をクリックするとファイルをダウンロードできます。
    パブリックキーは使いませんが、念のため、ダウンロードしておきましょう。
    ダウンロードしたファイルはPythonで使用しますので、

    c:\iot-test\certificates
    に配置します。

    また、AWS IoT のルートCAの証明書も必要なので「AWS IoT のルートCA ダウンロード」をクリックします。
    別タブでServer authenticationページの「CA certificates for server authentication」のコンテンツが表示されます。
    すぐ下に「RSA 2048 bit key: Amazon Root CA 1」のリンクがありますので、右クリックして「名前を付けて保存」でローカルに保存します。
    この証明書はサーバ証明書なので一度ダウンロードすれば、証明書の有効期間内は使いまわせます。

    7. 「完了」ボタンをクリックします。
    これでモノが作成されました。
    証明書は無効化されたままですので後ほど有効化します。 なお「証明書が作成されました!」画面で「有効化」ボタンをクリックすると証明書を有効にできます。


    ポリシの設定

    1. AWS IoT Coreコンソールを表示します。

    2. 左のメニューで[安全性]-[ポリシー]の順に選択します。
    「作成」ボタンをクリックします。

    3. ポリシーの作成画面が表示されます。
    名前を入力します。
    「名前」は管理画面で表示する上の名前です。識別子しやすい名前がよいでしょう。
    使用できる文字は英数字と「+=.@-」です。(2021/3時点)
    ここでは「名前」を「Test-Policy-1」とします。
    「アクション」は「iot:*」を入力します。
    「リソース ARN」は入力済みの値を削除して「*」(ワイルドカード)のみの値にします。
    「効果」は「許可」を選択します。
    入力後「作成」をクリックします。

    4. ポリシが作成され、一覧が表示されます。

    5. 作成したポリシをモノに関連付けます。
    AWS IoTではポリシはモノにではなく、証明書に関連付けるようです。

    左のメニューで[安全性]-[証明書]の順で証明書を選択できますが、証明書の名称は自動生成されているため、複数あるとわかりにくいです。
    そこでモノから、証明書を選択して、ポシリーを関連付けます。

    左のメニューで[管理]-[モノ]の順でクリックして、右の一覧から「Test-Thing-1」をクリックします。
    右の「Test-Thing-1」画面で「セキュリティ」をクリックします。
    証明書が表示されますので、関連付けられている証明書をクリックします。

    6. 右に証明書画面が表示されますので、メニュー「ポリシー」をクリックします。
    右画面の右にある「アクション」クリックして「ポリシーのアタッチ」をクリックします。
    ポリシーの一覧が表示されますので、先ほど作成したポリシー「Test-Policy-1」を選択して「アタッチ」をクリックします。
    ポリシーがアタッチされ、

    ポリシーは正常にアタッチされました。
    と画面上部に表示されます。

    7. 最後に証明書を有効にして通信できるようにします。
    証明書画面の右にある「アクション」クリックして「有効化」をクリックします。
    証明書が有効化され、
    証明書は正常に有効化されました。
    と画面上部に表示されます。


    Pythonの設定

    Pythonのソースコード内の下記を設定します。

    ENDPOINT = "XXXXXXXXXXXXXXXXXX.iot.ap-northeast-1.amazonaws.com"
    PATH_TO_CERT = "certificates/XXXXXXXXXXXXXXXXXX-certificate.pem.crt"
    PATH_TO_KEY = "certificates/XXXXXXXXXXXXXXXXXX-private.pem.key"
    PATH_TO_ROOT = "certificates/AmazonRootCA1.pem"
    ENDPOINTは、AWS IoT Coreコンソールの、左側のメニュー「設定」をクリックし、「デバイスデータエンドポイント」の値を設定します。
    (メニュー「設定」は下のほうにあります。)

    PATH_TO_CERTは「このモノの証明書」ファイル、PATH_TO_KEYは「プライベートキー」ファイルをそれぞれ指定します。
    ファイルは「モノと証明書の作成」の「6」でダウンロードしたファイルで、「c:\iot-test\certificates」に配置したファイルです。

    PATH_TO_ROOTは「RSA 2048 bit key: Amazon Root CA 1」でダウンロードしたファイルのパスを指定します。

    これで設定は完了です。
    では、次に実際に動かしてみましょう。

    動かしてみる

    AWSの利用規約では画面キャプチャのネット掲載は許可されていなさそうなので、画面キャプチャは載せていないです。

    先にメッセージの受け手(Subscriber)を起動する。
    今回、SubscriberはAWS IoTのWEBコンソールで使用できる「MQTT テストクライアント」を使用する。

    1. AWS IoT Coreコンソールを表示します。
    2. 左画面のメニュー「テスト」をクリックします。
    3. 「MQTT テストクライアント」画面が表示されますので、タブ「トピックをサブスクライブする」を選択します。
    4. 「トピックのフィルター」に「replaceWithATopic/#」を入力し、「サブスクライブ」をクリックします。
    これで準備完了です。
    メッセージを受信すると画面の右側に表示されます。

    次にメッセージの送り手(Publisher)を起動します。
    PublisherはPythonの「publish.py」です。
    Visual Studio Codeで「publish.py」を選択して、[F5]をクリックします。
    「Debug Configuration」の選択が表示される場合は、「Python File」を選択します。

    接続に問題がある場合は下記のようなメッセージが表示されます。
    Screenshot

    エラーになった場合は一通り見直してください。特に下記が間違えやすいと思います。
    AWS IoTの管理画面の下記を見直してみてください。
    ・ポリシーが有効になっているか。
    ・ポリシーのアクションとリソースARNはあっているか。
    また、Pythonの、証明書とプライベートキーのファイルパスがあっているかを確認してみてください。

    成功すると下記のようなメッセージが表示されます。
    Screenshot
    ※デバイス名とトピックの値はサンプルコードと異なる値を設定しています。

    また、AWS IoTのWEBコンソールには、下記のようなメッセージが20件表示されます。

    {
      "message": "Hello World [20]"
    }

    セキュリティ対策

    今回は、AWSコンソールでポリシを作成したが、セキュリティはとくに考慮していない。
    ポリシーについては下記が参考になる。
    AWS IoT Core policies
     https://docs.aws.amazon.com/iot/latest/developerguide/iot-policies.html

    運用では、クライアント証明書とプライベートキーの受け渡し方や、失効方法など検討することは多い。
    また、AWS IoT は Pub/Subのため、余分なメッセージが配送されないよう(輻輳しないよう)トピックについても考慮が必要だ。

    これで、AWS IoTを試してみた、は終了。


ページのトップへ戻る