AWS IoT Coreについて
AWS IoT Coreを触ってみたので、そのまとめです。
下記がAWSのIoTサービスの全体像です。
Blackeblet - AWS が提供する IoT ソリューションと ITS における活用
IoT Coreで持っている機能の一覧となります。
AWS IoT デバイス SDK: AWS IoT デバイス SDK を使用すれば、ハードウェアデバイスまたはモバイルアプリケーションを簡単かつすばやく AWS IoT Core に接続できます。
デバイスゲートウェイ: デバイスゲートウェイは IoT デバイスが AWS に接続する入口の役割を果たします。デバイスゲートウェイはすべてのアクティブなデバイスの接続を管理し、複数のプロトコルに対するセマンティックスを実装して、デバイスが AWS IoT Core と安全で効率的に通信できるようにします。現在、デバイスゲートウェイでは MQTT、WebSocket、HTTP 1.1 プロトコルがサポートされています。
メッセージブローカー: メッセージブローカーは高スループットの pub/sub メッセージブローカーで、ユーザーのすべての IoT デバイスとアプリケーションと低レイテンシーで安全にメッセージを送受信します。
認証と認可: AWS IoT Core では、接続するすべてのポイントでの相互認証と暗号化が提供されており、デバイスと AWS IoT Core 間では身元が証明されたデータのみが交換されます。
レジストリ: レジストリによって、デバイスの ID が確定され、デバイスの属性や機能といったメタデータが追跡されます。
デバイスシャドウ: AWS IoT Core では、それぞれのデバイスについて「シャドウ」、つまり永続的な仮想バージョンを作成できます。デバイスシャドウにはデバイスの最新の状態が保存されるため、アプリケーションや他のデバイスからのメッセージの読み出し、およびデバイスとの通信が実行できます。デバイスシャドウには、デバイスがオフライン状態のときでも、各デバイスについて最後に報告された状態と、希望する今後の状態が保持されます。
基本的には、MQTTを扱うためのPub/Subブローカーと、その仲間たちって感じです。
今回は、MQTTにてIoT Core向けにPublishして、Subscribeするまでの手順を確認してみます。
環境情報
認証・認可設定
認証
AWS IoTでは、MQTTを受け取るエンドポイントが、AWSアカウント単位で1つ勝手に作成されます。そのエンドポイントの認証にて、以下の方法がサポートされています。
- X.509証明書
- IAM User
- Cognito
- IDフェデレーション
- カスタム(Lambdaを利用して独自認証の作成)
IoTデバイスを対象とする場合、通常時であれば、 X.509証明書
を利用することになります。X.509証明書とは、公開鍵証明書のことらしいです。
暗号において、X.509とは、ITU-Tの公開鍵基盤 (PKI)の規格である。X.509は、公開鍵証明書の標準形式や証明書パス検証アルゴリズム(英語版)などを定めている。
自前の証明書をAWSにインポートすることもできるようですが、今回はIoT Coreの機能にて新規証明書を作成します。
以下のコマンドで、証明書一式を作成できます。
> aws iot create-keys-and-certificate \ --set-as-active \ --certificate-pem-outfile /tmp/certificate.pem.crt \ --public-key-outfile /tmp/public.pem.key \ --private-key-outfile /tmp/private.pem.key
AWS CLI - create-keys-and-certificate
作成された証明書は、Publish/SubScribeする時のConnection処理にて利用されます。
認可
認可(というかポリシー付与)の方法は、利用する認証方法により異なってきます。
プロトコル | ポート | SDK | 認証タイプ | 認可タイプ |
---|---|---|---|---|
MQTT over mutual authentication | 8883 443 |
AWS IoTDevice SDK | X.509証明書 | AWS IoTポリシー |
MQTT over WebSocket | 443 | AWS Mobile SDK | Cognito IAM User IDフェデレーション |
AWS IoT IDのCognitoポリシー 他のIDのIAM ポリシー |
HTTP over server authentication | 443 | AWS CLI | Cognito IAM User IDフェデレーション |
AWS IoT IDのCognitoポリシー 他のIDのIAM ポリシー |
HTTP over mutual authentication | 8443 | 未サポート | X.509証明書 | AWS IoTポリシー |
今回のMQTTプロトコルにて、X.509証明書を利用する方法では、AWS IoTポリシーがサポートされています。
IoTポリシーも、IAMポリシーのようにJSONベースでポリシーを定義することになります。AWS IoTコンソールより、「Secure」-「Policies」画面の、「Create」ボタンから作成できます。
以下が今回設定したIoTポリシー。ConnectできるClientIDを限定、Publishできるtopicを限定させています。topicについては後述。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:Connect" ], "Resource": [ "arn:aws:iot:ap-northeast-1:1234567890123:client/PC-0001" ] }, { "Effect": "Allow", "Action": [ "iot:Publish" ], "Resource": [ "arn:aws:iot:ap-northeast-1:1234567890123:topic/Ubuntu/CpuUtil" ] } ] }
IoTポリシーの書き方については、下記の公式ドキュメントを参考。
同様処理は下記コマンドからも実行できます。が、今回はポリシー定義をCLI内で書くのがあまりに面倒で、断念しました。。。
AWS CLI - create-policy-version
作成したポリシーを、その前に作成しているcertificate(証明書たち)にアタッチします。コマンドは下記。
aws iot attach-policy \ --target "arn:aws:iot:ap-northeast-1:1234567890123:cert/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ --policy-name "sample-policy"
Publish
Ubuntu上のCPU使用率を、AWS IoTに送信してみます。
topic
送信してみる前に、 topic
という概念について。AWS IoTでは、AWSアカウント単位でエンドポイントを1つ用意してくれます。送信するデータを振り分けるために、 topic
という概念が出てきます。
各データ毎にキューみたいなイメージでしょうか。
QoS
利用できるQoSについても。AWS IoTのMQTTプロトコルで用意されているQoSは「0」と「1」になります。
細かい解説は、公式のドキュメントにて。
Publishする際に指定することになります。
AWSIoTPythonSDK
で、実際にPublish処理をするスクリプトを作成します。今回、スクリプトをPythonで記述しており、 AWS IoT Device SDK for Python
というSDKを利用しています。スクリプトの書き方は、GitHub上にあるサンプルや、リファレンスを参考に。
GitHub - AWS IoT Device SDK for Python
$ sud0 apt-get update $ sudo apt-get upgrade $ sudo apt install python3-pip $ sudo pip3 install AWSIoTPythonSDK
CPU使用率を取得するにpsutilを利用するので、ライブラリをインポートしておきます。
$ sudo pip3 install psutil
コネクション時にルートCA証明書が必要となるため、AWS提供のものをダウンロードしておきます。
$ wget https://www.amazontrust.com/repository/AmazonRootCA1.pem
Amazon Trust Services Endpoints
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient from datetime import datetime import os import json import psutil import time CLIENT_ID = "PC-0001" IOT_ENDPOINT_URL = "xxxxxxxxxxxxxxxxxxx.iot.ap-northeast-1.amazonaws.com" IOT_ENDPOINT_PORT = 8883 PATH = os.getcwd() ROOT_CA_PATH = PATH + "/credentials/root.pem" PRIVATE_KEY_PATH = PATH + "/credentials/private.pem.key" CERTIFICATE_PATH = PATH + "/credentials/certificate.pem.crt" KEEP_ALIVE_TIME = 60 TOPIC = "Ubuntu/CpuUtil" myMQTTClient = AWSIoTMQTTClient(CLIENT_ID) myMQTTClient.configureEndpoint(IOT_ENDPOINT_URL, IOT_ENDPOINT_PORT) myMQTTClient.configureCredentials(ROOT_CA_PATH, PRIVATE_KEY_PATH, CERTIFICATE_PATH) myMQTTClient.configureOfflinePublishQueueing(-1) myMQTTClient.configureDrainingFrequency(2) myMQTTClient.configureConnectDisconnectTimeout(10) myMQTTClient.configureMQTTOperationTimeout(5) def GetTimeStamp(): return datetime.now().strftime("%Y/%m/%d %H:%M:%S") def GetCpuUtil(): return psutil.cpu_percent(interval=1) if __name__ == '__main__': myMQTTClient.connect(KEEP_ALIVE_TIME) while True: message = {} message['time'] = GetTimeStamp() message['cpu_util'] = GetCpuUtil() payload = json.dumps(message) myMQTTClient.publish(TOPIC, payload, 1) time.sleep(5)
エンドポイント名をちゃんと記載し、これまでに用意した各種証明書を配置したら、スクリプトを実行します。AWS IoTにデータが送信され始めます。
Subscribe
テスト用にAWSコンソール上でSubscribeできる機能を用意してくれています。Publish処理と同じくSDKで処理を記載することもできますが、疎通テストするだけであれば、こいつがすごい便利です。
AWSコンソール上の「Test」ページから、Subscribeしたいtopicを入力してSubscribeの実行。
正しくPublishされていれば、メッセージが表示されてきます。
Kinesisと違い、IoT Coreではメッセージをバッファしてくれる機能はないので、SubScribeできなかったメッセージは闇に消えることになります。
トラブルシューティング
設定時のトラシューで役立った情報を記載しておきます。
ログ
CloudwatchLogsにログ出力設定を実施できます。AWS IoTコンソールの、 setting
ページより設定できます。LogGroup AWSIotLogs
という名前でログが作成されるので、それを確認。
タイムアウト
エンドポイントとのコネクションを貼った際、タイムアウトのエラーとなる場合。
>>> myMQTTClient.connect() Connect timed out Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.6/dist-packages/AWSIoTPythonSDK/MQTTLib.py", line 513, in connect return self._mqtt_core.connect(keepAliveIntervalSecond) File "/usr/local/lib/python3.6/dist-packages/AWSIoTPythonSDK/core/protocol/mqtt_core.py", line 199, in connect raise connectTimeoutException() AWSIoTPythonSDK.exception.AWSIoTExceptions.connectTimeoutException
- 考えられる原因
- CertificateとIoT Policyが紐付いていない
- IoT Policyの権限に不足がある
証明書の確認
IoTエンドポイントへの接続テストを実施できます。以下が公式の手順です。
実行コマンドはこんな感じです。
$ openssl s_client \ -connect xxxxxxxxxxxxx.iot.ap-northeast-1.amazonaws.com:8443 \ -CAfile ./root.pem \ -cert ./certificate.pem.crt \ -key ./private.pem.key