AWS IoT Message BrokerのMQTTでpub/subをやってみた #reinvent
re:Invent 2015 キーノートで発表された AWS のマネージド MQTT(MQ Telemetry Transport)サービス AWS IoT Message Broker で Pub/Sub してみました。
作業の流れ
以下の手順で作業します
- MQTT クライアントのインストール
- AWS CLI のアップグレード
- 認証設定
- IAM Role 設定
- Pub/Sub 通信
MQTT クライアントのインストール
MQTT プロトコルの通信は OSS の MQTT 実装 mosquitto のクライアントを利用します。 Amazon Linux のパッケージには含まれていないため、CentOS 向けのパッケージを利用してみました。
$ sudo curl http://download.opensuse.org/repositories/home:/oojah:/mqtt/CentOS_CentOS-6/home:oojah:mqtt.repo -o /etc/yum.repos.d/mqtt.repo % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 272 100 272 0 0 321 0 --:--:-- --:--:-- --:--:-- 321 $ sudo yum install -y mosquitto-clients
- /usr/bin/mosquitto_pub (メッセージ送信)
- /usr/bin/mosquitto_sub (メッセージ受信)
がインストールされます。
AWS CLI のアップグレード
IoT Message Broker を操作するには AWS CLI 1.8.12 以上が必要です。 CLI を最新にしましょう。
$ sudo pip install awscli --upgrade ... $ aws --version aws-cli/1.8.12 Python/2.7.10 Linux/4.1.7-15.23.amzn1.x86_64
IoT サービスの API では KMS と同じく最もセキュアな「署名バージョン 4」が利用されています。
http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
認証設定
AWS IoT Message Brokwer の MQTT プロトコルでは X.509 の certificate based authentication が利用されています。
こちらを次の Quickstart ドキュメントに従って設定します(certificate の provisioning)。
Secure Communication Between a Thing and AWS IoT - AWS IoT (Beta)
iot create-keys-and-certificate API で
- Certificate ID
- Certificate
- Public Key
- Private Key
を一発で生成します。
$ aws iot create-keys-and-certificate --set-as-active { "certificateArn": "arn:aws:iot:us-west-2:111111111111:cert/SNIP", "certificatePem": "-----BEGIN CERTIFICATE-----SNIP-----END CERTIFICATE-----\n", "keyPair": { "PublicKey": "-----BEGIN PUBLIC KEY-----SNIP-----END PUBLIC KEY-----\n", "PrivateKey": "-----BEGIN RSA PRIVATE KEY-----SNIP-----END RSA PRIVATE KEY-----\n" }, "certificateId": "ASDF" }
このレスポンスボディーを cert.json というファイル名で保存していれば
$ cat cert.json | jq .keyPair.PublicKey -r > thing-public-key.pem $ cat cert.json | jq .keyPair.PrivateKey -r > thing-private-key.pem $ cat cert.json | jq .certificatePem -r > cert.pem
のようにして各情報を保存出来ます。
証明書の有効期限を確認して見ると、2049年末まで有効でした。
$ openssl x509 -in cert.pem -noout -dates notBefore=Oct 8 21:31:11 2015 GMT notAfter=Dec 31 23:59:59 2049 GMT
また、ルート CA もシマンテックサイトから取得します。
$ curl -o rootCA.pem https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem
IAM Role の設定
次に MQTT ブローカーに pub/sub するための IAM Role を Certification に設定します。
まずはiot サービスを操作できる "PubSubToAnyTopic" という名前のポリシーを作成します。
$ cat iot-policy.json { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action":["iot:*"], "Resource": ["*"] }] } $ aws iot create-policy --policy-name "PubSubToAnyTopic" --policy-document file://iot-policy.json { "policyName": "PubSubToAnyTopic", "policyArn": "arn:aws:...", "policyDocument": "{\n \"Version\": \"2012-10-17\", \n \"Statement\": [{\n \"Effect\": \"Allow\",\n \"Action\":[\"iot:*\"],\n \"Resource\": [\"*\"]\n }]\n}\n", "policyVersionId": "1" }
このポリシーをプリンシパルにひも付けます。 プリンシパルとなるのは aws iot create-keys-and-certificate コマンドを実行した時の certificateArn です。
$ aws iot attach-principal-policy --principal ""arn:aws:iot:us-west-2:111111111111:cert/SNIP" --policy-name "PubSubToAnyTopic"
Pub/Sub 通信
これまでで準備は整いました。
MQTT エンドポイントの確認
次のコマンドで MQTT エンドポイントを確認します。 このエンドポイントは AWS アカウントごとに存在します。
$ aws iot describe-endpoint { "endpointAddress": "DUMMY.iot.us-west-2.amazonaws.com" }
Subscribe してみる
このエンドポイントにむけて subscribe します。
$ mosquitto_sub --cafile rootCA.pem --cert cert.pem --key thing-private-key.pem -h "DUMMY.iot.us-west-2.amazonaws.com" -p 8883 -q 1 -d -t topic/test -i clientid1 Client clientid1 sending CONNECT Client clientid1 received CONNACK Client clientid1 sending SUBSCRIBE (Mid: 1, Topic: topic/test, QoS: 1) Client clientid1 received SUBACK Subscribed (mid: 1): 1 ...
各オプションは以下の通りです。
- --cafile でルートCAファイルを指定します。
- --key で秘密鍵ファイルを指定します
- -h でエンドポイントを指定します
- -q は QoS レベルです
- -d はデバッグオプションです
- -t はトピックです
- -i はクライアントIDです
Publish してみる
$ mosquitto_pub --cafile rootCA.pem --cert cert.pem --key thing-private-key.pem -h DUMMY.iot.us-west-2.amazonaws.com -p 8883 -q 1 -d -t topic/test -i clientid2 -m "Hello, World" Client clientid2 sending CONNECT Client clientid2 received CONNACK Client clientid2 sending PUBLISH (d0, q1, r0, m1, 'topic/test', ... (12 bytes)) Client clientid2 received PUBACK (Mid: 1) Client clientid2 sending DISCONNECT
新規オプション -m がペイロードです。
subscriber クライアントに
$ mosquitto_sub ... ... Client clientid1 received PUBLISH (d0, q1, r0, m1, 'topic/test', ... (12 bytes)) Client clientid1 sending PUBACK (Mid: 1) Hello, World
というように Publisher が送信したメッセージ(Hello, World)が表示されていれば成功です。 おめでとうございます!
トラブルシュート
Error: The connection was lost....
エラーが発生
publish 時に以下の様なエラーが発生する場合、クライアント証明書がポリシーにアタッチされていないことが疑われます。
$ mosquitto_pub --cafile rootCA.pem --cert cert.pem --key privateKey.pem -h … Client DUMMY sending CONNECT Error: The connection was lost....
次のドキュメントに従い、アタッチしてください。
https://docs.aws.amazon.com/iot/latest/developerguide/secure-communication.html
まとめ
MQTT ブローカーを自前で立てることなく MQTT 通信出来ました。
Pub/Sub メッセージは mosquitto プロジェクトのクライアント mosquitto_sub/mosquitto_pub プログラムで行っており、Cert ファイルを渡すのみで、AWS のクレデンシャルは渡していません。
Message Broker へ publish したメッセージは、AWS のサービスと連携させることもできます。
Amazon さん、やり過ぎじゃないでしょうか?