🐕

AWS IoT Immersion Day ワークショップでIoT Core学び直し

2024/03/18に公開

はじめに

過去に業務でIoT Core周りの一部に触れたことがありますが、改めて過去に触れてこなかったIoTサービスも含めIoT Coreを学び直すことにしました。

AWS IoT Immersion Day ワークショップはそんな私にぴったりのワークショップで、IoT CoreだけじゃなくてGreengrassやTimestream、Analyticsなども触れて学べそうなので、このワークショップをやりながらIoTサービスへの理解を深めていきたいと思います。

AWS IoT Core

AWS IoT Coreでは、3つのことが学べました。
IoTデバイスとMQTT通信できるようになること、Device Shadowを使ってIoT機器の状態を変更できるようになること、MQTTのLWTを使ってデバイスの切断を検知してログ出力できることです。

IoTデバイスとMQTT通信できるようになること(Lab 1.1)

Thing作成ウィザードでThingを作成し、秘密鍵とクライアント証明書を発行してThingに紐付け、クライアント証明書にセキュリティポリシーを設定してアクセス制御を設定し、デバイスからその秘密鍵とクライアント証明書を使って接続するというもの。

今回、私は手元に古いRasberry Piがあったので、Raspberry PiをIoT Coreと繋げてMQTT接続しました。

セキュリティポリシーを最小権限に変更してみる

証明書に設定するポリシーは、MQTTメッセージブローカーに接続してメッセージを送受信するために必要最低限のアクションを許可するポリシーになっていました。
リソースはこの後さまざまなトピックを使いたいためなのか制限はないモノでした。

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

そこで最小権限のポリシーに変更してアクセス制御の振る舞いを確認してみました。
各アクションに指定するリソースは決まっているので、こちらを参考に設定しました。

AWS Account ID: 123456789012、AWS IoT Thing name: ratchetの場合のセキュリティーポリシー例です。
許可するトピックは接続テストのサンプルコードから持ってきています。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:Connect"
      ],
      "Resource": [
        "arn:aws:iot:us-east-1:123456789012:client/ratchet"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:Publish"
      ],
      "Resource": [
        "arn:aws:iot:us-east-1:123456789012:topic/device/ratchet/data"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:Receive"
      ],
      "Resource": [
        "arn:aws:iot:us-east-1:123456789012:topic/app/data"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:Subscribe"
      ],
      "Resource": [
        "arn:aws:iot:us-east-1:123456789012:topicfilter/app/data"
      ]
    }
  ]
}

注意点としては、iot:Subscribeアクションの場合はリソースタイプはtopicfilterであること。

ポリシーを更新すると新バージョンが作られますが、activeにしないと新バージョンは使われません。デバイスがすでに接続中であってもこのバージョン切り替えは即座に反映され、activeになったセキュリティポリシーに従って動作することがわかりました。
一方、証明書をdeactiveにした場合、すでに接続済みのデバイスは即座にアクセスが拒否されるわけではないようでした。接続時に証明書を検証しているはずなので、接続後に証明書が失効しても即座に反映されないのだと思います。

Device Shadowを使ってIoT機器の状態を変更できるようになること(lab5.1)

温度メトリックを送るデバイスをClassic Shadowを作ってデバイスの状態を変更し、振動メトリックも送るようにするといった内容。
デバイスはDevice ShadowのDesired statusを監視して、期待するステータスと現在のステータスに差異が生じたら状態を変更してReported stateに通知する。その状態によってdata/vibrationにメトリックを送ったり送らなかったりする。

desiredだけを更新してみる

手順ではAWS IoT コンソール->管理-->モノ-->ラチェット-->デバイスシャドウ-->クラシックシャドウでdesiredステートをONにすることでdata/vibrationトピックにメトリックが送られることを確認するんですが、このコンソール上でクラシックシャドウを変更すると、desiredだけでなくreportedも変更ないけど更新されてしまうようでした。
基本的にreportedはデバイスが更新する属性なのでユーザが変更すべきではなイノで、MQTT test clientを使ってクラシックシャドウに対して以下のようにdesiredステートだけを更新することができました。

topic: $aws/things/ratchet/shadow/update

{
  "state": {
    "desired": {
      "MOTOR": "ON"
    }
  }
}

今回気づいたんですが、マネコンのDevice Shadowから各トピックへのMQTT test clientリンクが用意されててとても便利でした。こういうの地味に助かる。

権限を確認してみる

各アクションにDevice Shadowのトピックをリソースとして追加することで、Device Shadowに対する操作が通った。
つまり、MQTT経由でのDevice Shadow操作は他のMQTTトピックと同等の扱いだといえる。
iot:GetThingShadowiot:UpdateThingShadowなどDevice Shadow操作のアクションはREST API経由でのみ有効なアクションだということがわかった。

また、python SDKでpublishした結果を取得する場合、iot:Receiveアクションにもトピックをリソース追加しないと失敗した。結果取得のために必要だと思われる。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:Connect",
      "Resource": "arn:aws:iot:us-east-1:123456789012:client/ratchet"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Publish",
      "Resource": [
        "arn:aws:iot:us-east-1:123456789012:topic/data/temperature",
        "arn:aws:iot:us-east-1:123456789012:topic/data/vibration",
        "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/ratchet/shadow/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "iot:Receive",
      "Resource": [
        "arn:aws:iot:us-east-1:123456789012:topic/data/temperature",
        "arn:aws:iot:us-east-1:123456789012:topic/data/vibration",
        "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/ratchet/shadow/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": "iot:Subscribe",
      "Resource": [
        "arn:aws:iot:us-east-1:123456789012:topicfilter/app/data",
        "arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/ratchet/shadow/*"
      ]
    }
  ]
}

MQTTのLWTを使ってデバイスの切断を検知してログ出力できること(Lab6.1)

MQTTのLWTを使うと、切断時に特定のトピックにメッセージを通知することができます。
そのトピックへの通知をトリガーにしてログをCloudWatchに出力する操作を学ぶことができます。

コネクションを切ると即座にトピックにメッセージがpublishされた。コネクションを切らなくてもデバイスの通信を一時的に切断することでメッセージがpublishされることを確認できました。

ライフサイクルイベントでも切断をトリガーすることができますが、接続時のメッセージによってアクションを分けたいようなケースではLWTが使えるなと思いました。

おわりに

IoT CoreでデバイスとMQTT通信するための設定や操作を学ぶことができました。
証明書に紐付けるセキュリティポリシーを検証することで、IoT Coreのアクションやリソースの理解が深まりました。
ワークショップの残りは後日記事にしたいと思います。

GitHubで編集を提案

Discussion