AWS IoT Message BrokerのMQTTでpub/subをやってみた #reinvent

2015.10.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

re:Invent 2015 キーノートで発表された AWS のマネージド MQTT(MQ Telemetry Transport)サービス AWS IoT Message Broker で Pub/Sub してみました。

作業の流れ

以下の手順で作業します

  1. MQTT クライアントのインストール
  2. AWS CLI のアップグレード
  3. 認証設定
  4. IAM Role 設定
  5. 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 さん、やり過ぎじゃないでしょうか?