😊

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

3 min read

ここを参考に進める

https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/creating-a-virtual-thing.html

前提

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

概要

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

image

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

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のファイルをつくる。Pilicyは複数の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 クライアント

各種証明書とキーを使う。エンドポイントは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}}"]

Discussion

ログインするとコメントできます