この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちはCX事業本部のさかじです。
サンプルでよく見るAWS IoTのポリシーを変更したところ正常にデータをpublishできなくなったので何が悪かったかを調査修正しました。
環境
- MacBook Pro(macOS Mojave 10.14.6)
前提条件
$ python3 --version
Python 3.7.6
testThing
という名称でモノ作成、同様に証明書もダウンロード済み
ソース
以下のように、カウントアップデータをpublish
import os
import os.path
import time
import json
class IotMqttClient:
# AWS IOTと接続するときの設定
###############
### 要確認 ###
###############
ROOT_CA_PATH = os.path.join(os.path.dirname(__file__), 'certs/rootCA.pem')
CERTIFICAT_PATH = os.path.join(os.path.dirname(__file__), 'certs/cert.pem')
PRIVATE_KEY_PATH = os.path.join(os.path.dirname(__file__), 'certs/private.key')
IOT_HOST = 'a1caabg5j4yl8w.iot.ap-northeast-1.amazonaws.com'
IOT_PORT = 8883
IOT_CLIENT_ID = 'test_client'
__my_iot_mqtt_client = None
__is_connected = False
def __init__(self):
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTClient
# クライアントの設定
self.__my_iot_mqtt_client = AWSIoTMQTTClient(self.IOT_CLIENT_ID)
self.__my_iot_mqtt_client.configureEndpoint(self.IOT_HOST, self.IOT_PORT)
self.__my_iot_mqtt_client.configureCredentials(self.ROOT_CA_PATH, self.PRIVATE_KEY_PATH, self.CERTIFICAT_PATH)
# 接続情報の設定
self.__my_iot_mqtt_client.configureAutoReconnectBackoffTime(1, 32, 20)
self.__my_iot_mqtt_client.configureOfflinePublishQueueing(-1) # Infinite offline Publish queueing
self.__my_iot_mqtt_client.configureDrainingFrequency(2) # Draining: 2 Hz
self.__my_iot_mqtt_client.configureConnectDisconnectTimeout(10) # 10 sec
self.__my_iot_mqtt_client.configureMQTTOperationTimeout(5) # 5 sec
def on_offline(): self.__is_connected = False
def on_online(): self.__is_connected = True
self.__my_iot_mqtt_client.onOffline = on_offline
self.__my_iot_mqtt_client.onOnline = on_online
# 接続開始
self.__my_iot_mqtt_client.connect()
def publish(self, IOT_TOPIC, unpacked_data):
if not self.__is_connected:
self.__my_iot_mqtt_client.connect()
self.__my_iot_mqtt_client.publishAsync(IOT_TOPIC, str(unpacked_data), 1, ackCallback=None)
def main():
iot_mqtt_client = IotMqttClient()
count = 1
while True:
print(count)
count += 1
time.sleep(1)
send_data = {'key':count}
json_data = json.dumps(send_data)
iot_mqtt_client.publish('test_topic', json_data)
if __name__ == '__main__':
main()
よくサンプルで出てくるポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:Publish",
"iot:Subscribe",
"iot:Connect",
"iot:Receive"
],
"Resource": "*"
}
]
}
改善したい点
- 機能別に許可するモノを分けたい
- 今回は
testThing
のPublishのみを許可したい
ポリシー例
開発者ガイド>パブリッシュ/サブスクライブポリシーの例参考に作成してみました
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iot:Connect"
],
"Resource": [
"arn:aws:iot:ap-northeast-1:123456789012:client/testThing"
]
},
{
"Effect": "Allow",
"Action": [
"iot:Publish"
],
"Resource": [
"arn:aws:iot:ap-northeast-1:123456789012:topic/testThing/*"
]
}
]
}
動かしてみた
$ ./shadow.py
Connect timed out
Traceback (most recent call last):
File "./shadow.py", line 74, in <module>
main()
File "./shadow.py", line 57, in main
iot_mqtt_client = IotMqttClient()
File "./shadow.py", line 46, in __init__
self.__my_iot_mqtt_client.connect()
File "/usr/local/lib/python3.7/site-packages/AWSIoTPythonSDK/MQTTLib.py", line 513, in connect
return self._mqtt_core.connect(keepAliveIntervalSecond)
File "/usr/local/lib/python3.7/site-packages/AWSIoTPythonSDK/core/protocol/mqtt_core.py", line 199, in connect
raise connectTimeoutException()
AWSIoTPythonSDK.exception.AWSIoTExceptions.connectTimeoutException
接続できないので確認してみた
- SDK
MQTT Modules
clientID - String that denotes the client identifier used to connect to AWS IoT. If empty string were provided, client id for this connection will be randomly generated n server side.
クライアントIDはAWS IoTへ接続するためのの文字列なのでIOT_CLIENT_ID = 'test_client'
としているとtestThing
を許可しているので接続できませんので修正しましょう。
IOT_CLIENT_ID = 'testThing'
再度動かしてみた
1
2
3
4
5
6
Connect timed out
Traceback (most recent call last):
File "./shadow.py", line 74, in <module>
main()
File "./shadow.py", line 67, in main
iot_mqtt_client.publish('test_topic', json_data)
File "./shadow.py", line 50, in publish
self.__my_iot_mqtt_client.connect()
File "/usr/local/lib/python3.7/site-packages/AWSIoTPythonSDK/MQTTLib.py", line 513, in connect
return self._mqtt_core.connect(keepAliveIntervalSecond)
File "/usr/local/lib/python3.7/site-packages/AWSIoTPythonSDK/core/protocol/mqtt_core.py", line 199, in connect
raise connectTimeoutException()
AWSIoTPythonSDK.exception.AWSIoTExceptions.connectTimeoutException
少し動いたように見えてタイムアウトエラーします。実際AWSマネジメントコンソールからsubscribeしてもデータは取得できませんでした。
確認してみた
- 一旦
pubulish
側の"Resouce"
をワイルドカードにしてみたところpublishできるようになった - と言うことは
pubulish
側の"Resouce"
に問題がある - プログラムの
topic
の書式に間違いがある? - 以下の変更を加えた
iot_mqtt_client.publish('testThing/test_topic', json_data)
- 無事publish成功
AWSマネジメントコンソールからsubscribeしてもデータは取得できることも確認できました。
参考サイト
https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/pub-sub-policy.html
最後に
ついついサンプルのままポリシーを使っているので、痛い目に合いそうなので修正したところ見事はハマってしまった内容でした。細かい記載ミスでしたので原因を見つけるのに時間がかかりましたが、同じような問題に対して参考になれば幸いです。