AWS IoT Device SDK for Embedded Cを使って、443番経由でIoT CoreにMQTT Pubする


どんなときに必要か

C言語で開発しているアプリケーションから、MQTTのPubSubを行いたい場合、MQTTSのポート8883を使うとファイアウォールで通信できない可能性があるので、443を使いたい
詳細: https://aws.amazon.com/jp/blogs/news/mqtt-with-tls-client-authentication-on-port-443-why-it-is-useful-and-how-it-works/

手順

基本的なやり方は、以下の流れに従います。
https://docs.aws.amazon.com/iot/latest/developerguide/iot-embedded-c-sdk.html

  1. ラズパイが手元に無い&自分のPC環境を汚したくないので、Cloud9を立ち上げて、ラズパイ代わりに使います。
  2. 上記URLをもとに、aws-iot-device-sdk-embedded-c をクローン
  3. mbedtls をダウンロードして、クローンしたソースコードの external_libs/mbedTLS 下に置く(※2020/03/10時点で最新のMasterをクローンするとビルドが通りません。こちらの修正が必要です)
  4. AWS IoTでThingを作成し、証明書、ポリシーをアタッチ ※やり方:(https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/register-device.html)
  5. デバイス証明書、 ルートCAの証明書、秘密鍵を certフォルダ下に置く
  6. それらのファイル名を、 aws_iot_config.h にセットする
/aws-iot-device-sdk-embedded-C/samples/linux/subscribe_publish_sample/aws_iot_config.h
// Get from console
// =================================================
#define AWS_IOT_MQTT_HOST              "a3gevvffsj7zer-ats.iot.ap-northeast-1.amazonaws.com" ///< Customer specific MQTT HOST. The same will be used for Thing Shadow
#define AWS_IOT_MQTT_PORT              443 ///< default port for MQTT/S
#define AWS_IOT_MQTT_CLIENT_ID         "tls-test" ///< MQTT client ID should be unique for every device
#define AWS_IOT_MY_THING_NAME          "tls-test" ///< Thing Name of the Shadow this device is associated with
#define AWS_IOT_ROOT_CA_FILENAME       "rootCA.crt" ///< Root CA file name
#define AWS_IOT_CERTIFICATE_FILENAME   "cert.pem" ///< device signed certificate file name
#define AWS_IOT_PRIVATE_KEY_FILENAME   "privkey.pem" ///< Device private key filename
// =================================================

AWS_IOT_MQTT_CLIENT_ID, AWS_IOT_MY_THING_NAME には、AWS IoT で作成したThing名を入れます。
7. subscribe_publish_sample_appディレクトリで、make -f Makefile
8. ./subscribe_publish_sample で実行

結果

AWS IoTのテストでメッセージが受信できていることが確認できました。

本当に443で送られているのか

パケットを確認してみます。Cloud9上で、別ターミナルを開いて以下を実行します。

sudo yum install tcpdump
sudo tcpdump -i eth0 not host <ssh接続先のIP>

ログ

15:59:51.152221 IP ip-xxx.ap-northeast-1.compute.internal.39344 > ec2-xxx.ap-northeast-1.compute.amazonaws.com.https: Flags [.], ack 6760, win 296, options [nop,nop,TS val 243019003 ecr 2556610739], length 0

試しにポートを8883(MQTTS)にして、再度makeします。

#define AWS_IOT_MQTT_PORT              8883 

ログ

16:26:51.128650 IP ip-xxx.ap-northeast-1.compute.internal.32862 > ec2-xxx.ap-northeast-1.compute.amazonaws.com.secure-mqtt: Flags [.], ack 343, win 295, options [nop,nop,TS val 1114204944 ecr 214004673], length 0

ログを見比べると、 .httpsが、.secure-mqtt に変わっていることがわかります。outboudのポートを制限して試したいところですが、一旦ここまで。。