💎

AWS IoTにRubyのMQTTクライアントから接続

2021/10/31に公開

ここを参考に進める
https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/creating-a-virtual-thing.html

前提

  • EC2にVM立てておく。これをThingとして使う。
  • AWS CLIが使える
  • jqを入れておく
  • rubyを入れておく

概要

設定の流れとしては以下のようになる。作業のほとんどは安全な接続を確立するためのセキュリティ関連の設定である。デバイスを接続するためにmTLSを使うので証明書やキーの設定が必要になる。

  1. ThingCertificatePolicyの3つのオブジェクトを作ってcertificateArnで関連付け
  2. Certificateから証明書やキーのファイルを得る
  3. AWSからルート証明書をダウンロード
  4. 得たファイルをMQTTクライアントで使う

image

AWSのルート証明書AmazonRootCA1.pemはサーバー(IoT Core)認証に使う。ブラウザがWebブラウズの際にTLSでサーバー認証を行うがあれと同じ。一方でdevice.pem.crtはクライアント認証に使う。

EC2のVMでの設定

この部分はやや長いのでスクリプトにしました

Thing毎にディレクトリを作成する。あとでいくつかファイルを置く。

mkdir t1 && cd t1

Thing t1 をつくる

aws iot create-thing --thing-name t1
{
    "thingArn": "arn:aws:iot:us-west-2:<account-id>:thing/t1", 
    "thingName": "t1", 
    "thingId": "769f4f7b-190f-489g-a261-e84e184d99a6"
}

ちなみにARNは以下のように定義されるらしい
arn:partition:service:region:account-id:resourcetype/resource

以下で作ったThingを確認できる

aws iot list-things

Amazon 認証機関 (CA) 証明書のコピーをダウンロード

wget https://www.amazontrust.com/repository/AmazonRootCA1.pem

クラウド側にプライベートキー、パブリックキー、および X.509 証明書ファイルを作成。以下のコマンドの出力に後に必要な証明書やキーがはいっている。一部はオプションでファイルに書き出しつつ、全体をcerts-and-keys.jsonに書いている。

aws iot create-keys-and-certificate \
    --set-as-active \
    --certificate-pem-outfile "./device.pem.crt" \
    --public-key-outfile "./public.pem.key" \
    --private-key-outfile "./private.pem.key" \
    > certs-and-keys.json

作った証明書をthingに対応づける

aws iot attach-thing-principal \
    --thing-name t1 \
    --principal $(jq -r .certificateArn certs-and-keys.json)

Policyのファイルをつくる。Policyは複数のThingで共通のものになると思うので、t1より一段上のディレクトリにでも置いておく。

policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iot:Publish",
                "iot:Subscribe",
                "iot:Receive",
                "iot:Connect"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

上記のJSONを使ってポリシーp1を作る

aws iot create-policy \
    --policy-name "p1" \
    --policy-document "file://../policy.json"

証明書にポリシーを関連づける

aws iot attach-policy --policy-name p1 --target $(jq -r .certificateArn certs-and-keys.json)

Ruby MQTT クライアント

各種証明書とキーを使う。デバイスが接続するエンドポイントは複数あるが、MQTTのやりとりなどデータプレーンのエンドポイントは以下で得ることができる。

aws iot describe-endpoint --endpoint-type iot:Data-ATS

クライアントのサンプルはこんな感じ。

pub.rb
require 'rubygems'
require "mqtt"
require "json"

msg = JSON.generate({
  "d" => {
    "test_data" => 10
  }
})

endpoint = `aws iot describe-endpoint --endpoint-type iot:Data-ATS | jq -r .endpointAddress`.chomp

MQTT::Client.connect(
  host: endpoint,
  port: 8883,
  ssl: true,
  cert_file: "device.pem.crt",
  key_file: "private.pem.key",
  ca_file: "AmazonRootCA1.pem") do |client|
  client.publish("topic/test", msg)
end
sub.rb
require "mqtt"

endpoint = `aws iot describe-endpoint --endpoint-type iot:Data-ATS | jq -r .endpointAddress`.chomp

MQTT::Client.connect(
  host: endpoint,
  port: 8883,
  ssl: true,
  cert_file: "device.pem.crt",
  key_file: "private.pem.key",
  ca_file: "AmazonRootCA1.pem") do |client|
  client.subscribe("topic/test")
  topic,message = client.get 
  p [topic, message]
end

sub.rbを実行した状態でpub.rbを動かすとsub側でメッセージを確認できる

$ ruby sub.rb 
$ ["topic/test", "{\"d\":{\"test_data\":10}}"]

QoSの設定

Method: MQTT::Client#subscribe

String: subscribe to one topic with QoS 0
Array: subscribe to multiple topics with QoS 0
Hash: subscribe to multiple topics where the key is the topic and the value is the QoS level

For example:

client.subscribe( 'a/b' )
client.subscribe( 'a/b', 'c/d' )
client.subscribe( ['a/b',0], ['c/d',1] )
client.subscribe( 'a/b' => 0, 'c/d' => 1 )

Discussion