BFT名古屋 TECH BLOG

日々の業務で得た知識を所属するエンジニアたちがアウトプットしていきます。

【AWS・IoT】Pythonを使って作業PCからIoT CoreへMQTT接続しようとしたらエラー対応に追われた話(Resolved)

はじめに

こんにちは!
友人から貰ったキャラメルソースが美味しすぎて高カロリー街道まっしぐら、
BFT名古屋支店・インフラ女子(?)のやまぐちです。

今回は絶賛サービス実装中である「混雑状況可視化サービス」について、IoTデバイスラズベリーパイ)からAWS IoT Coreにメッセージを送る前に、自分のPCをIoTデバイスのように扱ってテストしようというところでつまづいた内容を共有します。

クラウド側の想定構成図はこちらです。
全体像はこれなのですが、そもそも最初のラズパイからIoT Coreまで届かない状態のお話です。
f:id:bftnagoya:20210616202435p:plain:w550

Windows PCからIoT CoreへMQTTでメッセージを送る

とにかくいろいろと触りたくさんのサイトを確認したので仕組みが少しずつ見えてきました。
今回はWindows 10の作業PCからIoT Coreに接続します。

前提の状態

  • 作業PCの情報

  • AWS IoT Core ポリシーを作成済

    • 実はこのポリシーで投稿できるトピックや接続するクライアントを制限しているので、どこかからコピーしてきた場合は自分が実行するpythonの内容に合っているかは確認した方がよい
    • 最初の手順でやっていくと 何でもできる権限(iot:*)をすべてのリソースに対して付けるので後からちゃんと絞る検討をしないといけない
    • ここではあくまでもテスト用としてのポリシーで「トピック」と「送信元のクライアントID」に制限をかけたものを使う
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:Publish",
        "iot:Receive"
      ],
      "Resource": [
        "arn:aws:iot:ap-northeast-1:XXXXX:topic/test/topic"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:Subscribe"
      ],
      "Resource": [
        "arn:aws:iot:ap-northeast-1:XXXXX:topicfilter/test/topic"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:Connect"
      ],
      "Resource": [
        "arn:aws:iot:ap-northeast-1:XXXXX:client/test-*"
      ]
    }
  ]
}
  • IoTモノを作成済

    • IoT モノを登録すると、登録名がMQTTのClientIDになる。ポリシーを分けたい場合はグループごとに同じ頭文字にするとか工夫するとよい。
  • IoTモノに証明書とポリシーをアタッチ済

    • 証明書は1:1でIoTモノにアタッチできるが、1つのモノに対して複数の証明書を登録することもできる(使いどころはまだ想像できていない)。
    • 厳密には証明書にポリシーがアタッチされていて、その証明書がIoTモノと紐づいている。
  • IoT Coreの管理コンソールで学習メニューから「AWS IoT の仕組み」「AWS IoTに接続する」のチュートリアルは実施済

    • Anaconda入ってるしいらないかなーと思っていたが、結局新たにPythonをインストール(python3.9.5)(2021/06/16最新)
    • チュートリアルでstart.ps1を実行すると作業ディレクトリに「aws-iot-device-sdk-python」フォルダができる
      • これは旧SDKで新しいV2が動かなかったら使うらしい

サンプルアプリケーション(pubsub.py)を実行してみよう

こちらのサイトを参考に進めます。Windowsコマンドプロンプトを使うことを想定したコマンドなので、PowerShellではなくコマンドプロンプト(管理者権限)で実行しています。
Windows または Linux PC または Mac を AWS IoT デバイスとして使用する - AWS IoT Core

  • 1.gitとpythonのインストール

    • ggitは公式サイト(https://gitforwindows.org/)からWindows版をインストール
    • pythonは公式サイト(https://pythonlinks.python.jp/)から最新版をインストール
      • インストールする時に環境変数PATHにパスを追加するにチェックを忘れずに
    • where gitコマンドを実行し、どこにインストールされたのか確認しておくとよい
    • 参考サイトにあるようにgit --versionpython -Vで問題なく出力されていればパスが通っていることの確認にもなる
  • 2.AWS IoT Device SDK for Pythonをインストールする

    • python -m pip install awsiotsdkコマンドでawssdkモジュールをインストールする
      • pipの最新版があるとアップグレードしろと出てくるのでpython -m pip install --ugrade pipを実行する
      • 「C:\Users\<ユーザ名>\AppData\Local\Programs\Python\Python39\Lib\site-packages」以下にawsiotフォルダがあることを確認する
    • 以下のコマンドでGitHubからpython用のSDKv2をクローンする
    • クローンしたら「C:\Users\<ユーザ名>」以下にaws-iot-device-sdk-python-v2フォルダがあることを確認する
echo %USERPROFILE%
cd %USERPROFILE%
git clone https://github.com/aws/aws-iot-device-sdk-python-v2.git


  • 3.サンプルアプリケーションの実行準備を行う①(クライアント証明書と秘密鍵を格納)

    • ここでは%USERPROFILE%以下にcertsフォルダを作成し、クライアント証明書と秘密鍵を格納
    • AWSのルートCA証明書の格納は任意。どうやらWindowsではちゃんと信頼されたストアに証明書をインストールしておかないとTLSのnegociationで失敗する
      f:id:bftnagoya:20210617113627p:plain:w550

  • 4.サンプルアプリケーションの実行準備を行う②(AWSのルートCA証明書のインストール)

    • AWSのルートCA証明書をダブルクリックすると証明書が表示されるので、「証明書のインストール」を押し、作業PCにインストールしていきます。ポイントは自動的にインストールせず、「信頼されたルート証明機関」の証明書にインストールすること
  • 5.サンプルアプリケーションの実行準備を行う③(サブスクライバの設定)

    • IoT Coreの管理コンソールでテスト用にパブリッシュされたトピックへサブスクライブし、送信されたメッセージを確認することができる
    • スクリプトでは「test/topic」に対して送信されるのでサブスクライブするトピックに「test/topic」と入力
      f:id:bftnagoya:20210617131959p:plain:w550

      br>

  • 6.サンプルアプリケーションを実行する

    • cd %USERPROFILE%\aws-iot-device-sdk-python-v2\samplesコマンドでディレクトリを移動
    • 以下のコマンドでメッセージ(Hello, World!)を10回送信
python pubsub.py --endpoint XXXX-ats.iot.ap-northeast-1.amazonaws.com --cert %USERPROFILE%\certs\XXXX-certificate.pem.crt --key %USERPROFILE%\certs\XXXX-private.pem.key

元々参考にしていたサイトに記載されたコマンドから--root-ca <AWSのルートCA CA証明書パス>を削除することを忘れないようにする。--root-caオプションは信頼されたストアに証明書を入れていない時に使うオプションらしく、このオプションのままだと証明書が信頼できないものとして以下のエラー(TLSネゴシエーション)で失敗するため。

awscrt.exceptions.AwsCrtError: AWS_IO_TLS_ERROR_NEGOTIATION_FAILURE: TLS (SSL) negotiation failed
実行結果を見る

AWS IoT Coreでの結果はこちらの図の通り、「指定された形式で表示できません」とは言われていますが、受信できていることを確認できます。
f:id:bftnagoya:20210617133544p:plain:w550

コマンドを実行した側の標準出力はこちらです。赤枠の部分でメッセージを出力し、かつサブスクライブ(受信)を10回繰り返しているのがわかります。
f:id:bftnagoya:20210617134129p:plain:w550

終わりに

恐らくあまりWindowsから送信する人が少なく情報がネット上になかったため、エラー解消まで時間がかかってしまいました。。。
また証明書マネージャで信頼されたストアに証明書をインストールしても、コマンドからは抜かないといけない(必須だと思っていた)のでとあるサイトで「信頼ストアにない場合に使うオプション」という文言を見て助かりました。

あと、この資料がトラブルシュートに役立ちました。
AWS IoT におけるデバッグ方法

今日もたくさん悩み一歩一歩混雑状況可視化サービスを作り上げていっています。
ここまで読んでいただきありがとうございました~^ ^