LoginSignup
1
3

More than 5 years have passed since last update.

AWS IoTへport:443/ALPNを使ってmqtt publishする

Last updated at Posted at 2018-02-25

はじめに

(update 2018/6/29: ALPN対応がpython SDK1.4.0で対応されました)

先日、AWS IoTでmqttをport:443を使って利用できるupdateがリリースされました。
ブログには、TLS標準のALPN機能を使うことで実現できるとの記載があるので、こちらを試してみました。

前提条件と投稿で使った環境について

ご利用されるsslライブラリなどによりALPNの実装方式が異なります。また、ご利用される言語によりalpn設定用の関数なども異なりますので、ご自分の環境や言語での実装方式はご確認をお願いします。
本投稿で確認した環境では、

  • python version : Python 2.7.13
  • OpenSSLのversion : OpenSSL 1.0.2k-fips 26 Jan 2017

です。
python2.7としては、alpn設定ためのSSLContext.set_alpn_protocols()が2.7.10以降でサポートされています。OpenSSLのalpnは、OpenSSL 1.0.2以降でサポートされていますので、この辺はご自分の環境を確認してください。またalpnで通知するプロトコル名は"x-amzn-mqtt-ca"と規定されています。

追記:
Python3.6でも下記のソースのまま動作確認しました。Python3系では、3.5以降でset_alpn_protocolsがサポートされています。

mqtt clientとしてはpahoを使っています。pahoのinstallは以下
(pyenvや、特定directoryなどinstall先は各自の環境に合わせてください。以下の参考は実行するpythonプログラムのローカル環境へinstallしています。)

sudo pip install paho-mqtt -t [サンプルプログラムのdir]

pythonが使っているOpenSSLのバージョンは以下で確認出来ます。


import ssl
print ssl.OPENSSL_VERSION

また、テストコードを実行する際に証明証が必要になるのでAWS IoTからThingの作成や証明書の作成、ダウンロード、証明書activate、policyのattachを行ってください。詳細手順はこちら

コードの流れ

  • ssl_contextへalpnの設定
  • 同じくssl_contextへ証明書の設定
  • ssl_contextを使ってmqqt clientへtls option設定
  • mqtt接続

となります。

サンプルコード

本sampleを動かすディレクトリとしては以下の環境となっています。
sample-dir
├ alpn_mqtt.py
├ paho/ (dir)
├ paho_mqtt-1.3.1-py2.7.egg-info/ (dir)
└ certs/ (dir)
 └ root_ca / certificate / private

certificate と private はAWS IoTで生成した証明書

alpn_mqtt.py

from __future__ import print_function
import sys
import ssl
import time
import datetime
import logging, traceback
import paho.mqtt.client as mqtt

IoT_protocol_name = "x-amzn-mqtt-ca"
aws_iot_endpoint = "AWS IoTのエンドポイント" # <random>.iot.<region>.amazonaws.comの形式
url = "https://{}".format(aws_iot_endpoint)

ca = "root_caの相対/絶対path付きfailname"
cert = "certificateの相対/絶対path付きfailname"
private = "privateの相対/絶対path付きfailname"

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler(sys.stdout)
log_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(log_format)
logger.addHandler(handler)


def ssl_alpn():
    try:
        #debug print opnessl version
        logger.info("open ssl version:{}".format(ssl.OPENSSL_VERSION))
        ssl_context = ssl.create_default_context()
        ssl_context.set_alpn_protocols([IoT_protocol_name])
        ssl_context.load_verify_locations(cafile=ca)
        ssl_context.load_cert_chain(certfile=cert, keyfile=private)

        return  ssl_context
    except Exception as e:
        print("exception ssl_alpn()")
        raise e

if __name__ == '__main__':
    topic = "test/date"
    try:
        mqttc = mqtt.Client()
        ssl_context= ssl_alpn()
        mqttc.tls_set_context(context=ssl_context)
        logger.info("start connect")
        mqttc.connect(aws_iot_endpoint, port=443)
        logger.info("connect success")
        mqttc.loop_start()

        while True:
            now = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
            logger.info("try to publish:{}".format(now))
            mqttc.publish(topic, now)
            time.sleep(1)

    except Exception as e:
        logger.error("exception main()")
        logger.error("e obj:{}".format(vars(e)))
        logger.error("message:{}".format(e.message))
        traceback.print_exc(file=sys.stdout)

動作確認

動かしているホストがlinuxであれば、 tcpdump port 443 としていただけば 443で一秒ごとにpublishしていることがわかるかと思います。また、 tcpdump port 8883 をみても8883で送信していないことが確認できます。
AWS IoTへの到達確認は AWS IoTのテスト画面から # or test/date をsubscribeしてください。
毎秒毎に時刻が送信されていることがわかります。

スクリーンショット 2018-02-25 11.22.14.png

免責

本投稿は、個人の意見で、所属する企業や団体は関係ありません。
また掲載しているsampleプログラムの動作に関しても保障いたしませんので、参考程度にしてください。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3