Amazon Web Services ブログ

AWS IoT Greengrassとローカルデバイスの連携について

AWS IoT Greengrass は、エッジでのデバイスソフトウェアの構築、デプロイ、管理を支援するオープンソースのエッジランタイムおよびクラウドサービスです。AWS IoT Greengrass Version 2.2.0 には、MQTT を使用して AWS IoT Greengrass Core にローカルに接続するためのローカルクライアントおよび、デバイス (クライアントデバイス) のサポートが追加されました。クライアントデバイスは、MQTT(Message Queuing Telemetry Transport protocol) を使用してクラウド内の AWS IoT Core にメッセージを安全に送受信したり、IPC(Interprocess communication) を介して他のコンポーネントと通信したりできます。

これらの新機能は、AWS IoT Greengrass を使用したメッセージのセキュリティ、接続性、配信を簡単にします。これにより、認証で利用する X.509 クライアント証明書、MQTT 接続、および MQTT トピック名前空間をそのまま利用し、AWS IoT Coreを介して行われていた通信を、 AWS IoT Greengrass Coreに接続先を変えることで、クラウド経由の通信からローカルを利用した通信への移行が可能になります。

このブログ記事では、ローカルの AWS IoT Greengrass Core を使用して、IPC 対応コンポーネントとの接続、メッセージング、およびメッセージングを行うクライアントデバイスのユースケースについて説明します。MQTT 用の AWS IoT Greengrass コンポーネントの設定とデプロイのプロセス、設定されたトピックに関するクライアントデバイスの接続と通信の認証方法について説明します。次に、ローカルの MQTT メッセージング、AWS IoT Core へのメッセージング、クライアントデバイスの観点から IPC の相互運用性について説明します。

このブログ投稿の想定されている読者は、AWS IoT Greengrass Version2 のセットアップと運用に精通したエッジコンピューティングソリューションを作成するアーキテクトまたは開発者です。AWS IoT Greengrass を初めて使用している場合、または現在 AWS IoT Greengrass バージョン 1.x を使用している場合は、What is AWS IoT Greengrass (Version 2) を読み、AWS IoT Greengrass バージョン 2 の用語と操作に慣れるために、Getting startedチュートリアルの順を追ってご覧ください。

概要

クライアントデバイスとローカル MQTT ブローカーの機能を説明するために、次のアーキテクチャを使用してクライアントデバイスのインタラクションを示します。

このアーキテクチャでは、ローカル MQTT ブローカーに対して認証及び接続するように構成された、 2 つのクライアントデバイス thing1thing2 があります。AWS IoT Core でリソースを記述するときはこれらをthingと呼び、AWS IoT Greengrass に接続してやり取りするときはそれらをクライアントデバイスとします。AWS IoT Greengrass に接続すると、クライアントデバイスは、他のデバイスとの通信、ローカルシャドウ、クラウド内の AWS IoT コアトピックとシャドウへの通信など、さまざまなローカルユースケースの MQTT トピックをパブリッシュおよびサブスクライブできます。

さまざまな利用パターンを示すために、ローカル MQTT ブローカーを介して通信するクライアントデバイス thing1thing2 のコンポーネント構成、クライアントデバイスがクラウドでミラーリングされたトピックをパブリッシュおよびサブスクライブする方法、および IPC を介して他のコンポーネントとやり取りする方法を示します。

この説明のために使用されるポリシーは、非常に権限が広くなっております。本番環境のデプロイについては、AWS IoT Greengrass が必要とするアクセス許可を制限する方法については、Service role permissions for core devicesMinimal AWS IoT policy for AWS IoT Greengrass V2を参照してください。

クライアントデバイスコンポーネントをデプロイする

クライアントデバイスが接続して通信するためのローカル MQTT 環境を構成する 3 つのパブリックコンポーネントがあります。これらのコンポーネントを使用することで、クライアントデバイス thing1 および thing2 は AWS IoT Greengrass とローカルで通信することができ、クラウドの AWS IoT Core への MQTT 接続を必要としません。3 つのコンポーネントすべてを新規または既存のデプロイメントに追加します。ここからは、それぞれの使用と構成の詳細について説明します。

最初のコンポーネントはMoquette MQTT broker コンポーネント(aws.greengrass.clientdevices.mqtt.Moquette) です。これは、クライアントデバイスが MQTT 通信に使用するローカル MQTT ブローカーであり、MQTT bridgeコンポーネントによって IPC のパブリッシュおよびサブスクライブ機能との変換に使用されます。このコンポーネントは、オープンソースの Moquette Project MQTT 準拠ブローカーのフォークに基づいています。デフォルトの設定値では、Moquette がすべてのネットワークインターフェースにバインドされ、ポート 8883 でリッスンするデフォルトの MQTT セキュア SSL 通信のみが使用されます。これらの値は、デプロイ時のコンフィグのマージによって変更できます。

次のコンポーネントは、クライアントデバイス、ローカル AWS IoT Greengrass パブリッシュ/サブスクライブ、および AWS IoT コア間で MQTT メッセージをリレーする MQTT bridgeコンポーネント (aws.greengrass.clientdevices.mqtt.Bridge) です。このコンポーネントを使用して、Moquette MQTT broker コンポーネント (localMqtt) と AWS IoT Core (IotCore) または IPC (Pubsub) の間でメッセージをルーティングします。以下に示すコンフィグのマージを使用して、ローカルクライアントデバイスが AWS IoT Core トピックにアクセスできるようにし、AWS IoT Core でパブリッシュされたメッセージが同じクライアントデバイスによってローカルに受信されるようにします。

{
  "mqttTopicMapping": {
    "ClientDevicesToCloud": {
      "topic": "from_local/hello/world",
      "source": "LocalMqtt",
      "target": "IotCore"
    },
    "CloudToClientDevices": {
      "topic": "from_cloud/hello/world",
      "source": "IotCore",
      "target": "LocalMqtt"
    }
  }
}

MQTT bridgeコンポーネントでコンフィグのマージに利用するこの JSON ドキュメントでは、ローカル MQTT ブローカーから from_local/hello/world トピックに関するメッセージをリッスンし、クラウド内の AWS IoT Core 上の同じトピックにそのメッセージをパブリッシュするマッピングをセットアップしました。2 番目のマッピングは、MQTT  bridgeが AWS IoT Core の from_cloud/hello/world トピックにサブスクライブするものです。そのトピックでメッセージを受信すると、MQTT  bridgeコンポーネントはそのメッセージをローカル MQTT ブローカーの同じトピックにパブリッシュします。

この設定を構成する場合、同じトピックに対してソースとターゲットのマッピングを構成しないように注意してください。もし設定すると、メッセージの無限ループが発生します。たとえば、上記の設定でトピックの hello/world が両方のマッピングに使用された場合、hello/world でローカル MQTT ブローカーにパブリッシュされたメッセージは AWS IoT Core でパブリッシュされます。これは AWS IoT Core で受信されたメッセージと見なされ、再びAWS Greengrass上の MQTT ブローカーにパブリッシュされ無限にメッセージがパブリッシュされ続けてしまいます。MQTT を使用したリクエスト/レスポンスパターンがある場合は、cmd/my_topic/request などのパブリッシュリクエストに 1 つのトピックを使用し、cmd/my_topic/response などの個別のレスポンストピックを使用してレスポンスをサブスクライブします。このパターンは IoT アトラスで説明されています。

MQTT  bridgeコンポーネントのマージ設定が適用されると、 Client device auth コンポーネントaws.greengrass.clientdevices.Auth)で、クライアントデバイスを認証し、クライアントデバイスのアクションを認可します。コンポーネントは、AWS IoT Core のモノの名前をクライアントデバイスと一致させ、クライアントデバイスが実行できる MQTT オペレーションとトピックについて MQTT ブローカーに通知するポリシーを適用することによってこれを実行します。以下のコンフィグのマージは thing1thing2 を参照し、トピックに関するローカル通信を許可します。また、from_local/hello/world および from_cloud/hello/world トピックへのアクセスも許可します。

{
  "deviceGroups": {
    "formatVersion": "2021-03-05",
    "definitions": {
      "MyDeviceGroup": {
        "selectionRule": "thingName: thing1 OR thingName: thing2",
        "policyName": "MyBlogPostPolicy"
      }
    },
    "policies": {
      "MyBlogPostPolicy": {
        "AllowConnect": {
          "statementDescription": "Allow connections with matching clientId",
          "operations": ["mqtt:connect"],
          "resources": ["mqtt:clientId:thing1", "mqtt:clientId:thing2"]
        },
        "AllowLocalPublish": {
          "statementDescription": "Allow client devices to publish on LOCAL test/topic",
          "operations": ["mqtt:publish"],
          "resources": ["mqtt:topic:test/topic"]
        },
        "AllowLocalSubscribe": {
          "statementDescription": "Allow client devices to subscribe to LOCAL test/topic/response",
          "operations": ["mqtt:subscribe"],
          "resources": ["mqtt:topicfilter:test/topic/response"]
        },
        "AllowSubscribeToCloud": {
          "statementDescription": "Allow client devices to subscribe to the AWS Cloud originated topic",
          "operations": ["mqtt:subscribe"],
          "resources": ["mqtt:topicfilter:from_cloud/hello/world"]
        },
        "AllowPublishToCloud": {
          "statementDescription": "Allow client devices to publish on a local topic that will be sent to the AWS Cloud",
          "operations": ["mqtt:publish"],
          "resources": ["mqtt:topic:from_local/hello/world"]
        }
      }
    }
  }
}

接続とローカルおよびクラウドメッセージングの検証

Client device authコンポーネントがデプロイされると、Moquette MQTT brokerコンポーネントに必要な設定が行われます。まず、SelectionRule に一致するthing名のリストを AWS IoT Core で作成します。この場合、thing1thing2 が含まれます。次に、クライアントデバイスとして含めるthingのリストを使用して、Client device authコンポーネントは、アタッチされた Thing 証明書を AWS IoT Greengrass Core に転送し、それらをmutual TLS 認証に使用するように Moquette MQTT brokerコンポーネントを設定します。最後に、Client device authポリシーが Moquette MQTT brokerコンポーネントに適用されます。これにより、ローカルの AWS IoT Greengrass Core Moquette MQTT broker (mqtt:connect 経由) に接続できるクライアントデバイスと、各thingがメッセージをサブスクライブまたはパブリッシュできる MQTT トピックが制限されます。

3 つのコンポーネントすべてがデプロイに追加および設定されると、AWS IoT Greengrass Core は新しく追加されたコンポーネントをダウンロードして設定します。デプロイのステータスを確認するには、$GG_ROOT/logs/greengrass.log ファイルを調べて、クライアントデバイスの接続、サブスクリプション、およびパブリッシュ操作を監視します。ログファイルからの次の出力を参照してください。

[INFO] (nioEventLoopGroup-3-8) com.aws.greengrass.device.DeviceAuthClient: Creating new session. {}
[INFO] (nioEventLoopGroup-3-8) io.moquette.broker.metrics.MQTTMessageLogger: C->B CONNECT <null>. {}
[INFO] (nioEventLoopGroup-3-8) com.aws.greengrass.mqttbroker.ClientDeviceAuthorizer: Retrieved client session. {clientId=thing1, sessionId=81843a7e-b7d7-4e23-b94a-7492d2039dd6}
[INFO] (nioEventLoopGroup-3-8) com.aws.greengrass.mqttbroker.ClientDeviceAuthorizer: Successfully authenticated client device. {clientId=thing1, sessionId=81843a7e-b7d7-4e23-b94a-7492d2039dd6}
[INFO] (nioEventLoopGroup-3-8) io.moquette.broker.metrics.MQTTMessageLogger: C->B SUBSCRIBE <thing1> to topics [MqttTopicSubscription[topicFilter=test/topic/response, option=SubscriptionOption[qos=AT_LEAST_ONCE, noLocal=false, retainAsPublished=false, retainHandling=SEND_AT_SUBSCRIBE]]]. {}
[INFO] (nioEventLoopGroup-3-8) io.moquette.broker.metrics.MQTTMessageLogger: C<-B SUBACK <thing1> packetID <36810>, grantedQoses [1]. {}
[INFO] (nioEventLoopGroup-3-8) io.moquette.broker.metrics.MQTTMessageLogger: C->B SUBSCRIBE <thing1> to topics [MqttTopicSubscription[topicFilter=from_cloud/hello/world, option=SubscriptionOption[qos=AT_LEAST_ONCE, noLocal=false, retainAsPublished=false, retainHandling=SEND_AT_SUBSCRIBE]]]. {}
[INFO] (nioEventLoopGroup-3-8) io.moquette.broker.metrics.MQTTMessageLogger: C<-B SUBACK <thing1> packetID <36811>, grantedQoses [1]. {}

ログからわかるように、thing1 は Moquette MQTT brokerに接続し、ローカルレスポンストピックtest/topic/response、および AWS IoT Core からメッセージを受信するトピック from_cloud/hello/world にもサブスクライブします。クライアントデバイスのエントリに加えて、パブリッシュ、接続、切断など、すべての MQTT 操作がログに記録されます。

今回は、テストを実行するために、thing1 の MQTT 設定を使用して Node-Red フローを作成し、ローカルのtest/topicfrom_local/hello/world トピックの両方に同時にメッセージを発行します。各ボックスは、左から右への流れで、実行されている操作を表します。白のノードはコメント用で、2 つの異なるセクションを説明しています。

クライアントデバイスから Moquette MQTT brokerに接続して検証するときは、MQTT の設定を理解することが重要です。Moquette MQTT brokerによって使用される X.509 サーバー証明書には、クライアントデバイスが接続するエンドポイントを検証するために使用する特別な属性と、署名認証局があります。この機能は AWS IoT デバイス SDK に含まれていますが、Node-RED などの他の MQTT クライアントを使用する場合は、さらに理解する必要があります。詳細については、AWS IoT Greengrass ドキュメントの「 Interact with local IoT devices」セクションを参照してください。

同じノードレッドフロー内に、[ローカルレスポンスをサブスクライブ...] セクションもあります。ここでは、thing1test/topic/response (ローカル) および from_cloud/hello/world (AWS クラウド) トピックにサブスクライブされます。一番上のフローは、メッセージの公開方法を示し、下部のフローはサブスクライブ済みトピックからのメッセージを受信して処理します。

thing1 が接続されている状態で、publish hello world messageノードをクリックすると、Moquette MQTT broker上の 2 つのトピックにサンプルメッセージが送信されます。test/topicへのメッセージは Moquette MQTT brokerコンポーネントによって処理され、ローカルコンポーネントに配信されます (図の中では表示されていませんが、processed by componentノードからの矢印で示される操作です)。このローカルコンポーネントは、thing1 がサブスクライブされているtest/topic/responseのトピックへの応答を公開します。デバッグウィンドウの [受信メッセージ] テキストは、メッセージが受信され、ローカルコンポーネントによって処理され、thing1 に戻されたことを確認します。

並行して、from_local/hello/world トピックへの 2 番目のメッセージは、MQTT bridgeコンポーネントによって AWS IoT Core に転送されます。AWS IoT Core へのメッセージの送受信を確認するには、AWS コンソールAWS IoT CoreテストMQTT テストクライアントに移動し、from_local/hello/world トピックをサブスクライブし、publish hello world messageノードを再度クリックします。AWS コンソールでトピックのサブスクリプションを見ていると、Moquette MQTT brokerコンポーネントにパブリッシュされ、MQTT bridgeコンポーネントで処理されたメッセージが AWS IoT Core に配信されたことがわかります。

AWS IoT Core からローカルの AWS IoT Greengrass MQTT ブローカーへの逆メッセージフローをテストするには、[Topic name] フィールドに from_cloud/hello/world と入力し、[Message payload] テキストボックスに応答を作成し、最後に [Publish] ボタンを選択してメッセージを送信します。AWS IoT Greengrass Core の Moquette MQTT brokerの同じトピックにサブスクライブした thing1 のNode-RED設定内の [Debug messages] ペインにそれが届きます。

ローカルからローカル、ローカルからクラウド、およびクラウドからローカルとメッセージが届いているのが確認できました。これで、Moquette MQTT brokerを使用してクライアントデバイスを設定、認証、および認可できるようになりました。

IPC とローカル MQTT トピックのブリッジング

MQTT bridgeコンポーネントは、双方向通信のための IPC と Moquette MQTT brokerの間にマッピングを作成することもできます。MQTT bridgeコンポーネントを使用する代わりに、AWS IoT Core トピックのみに IPC コンポーネントの通信が必要な場合は、代わりに AWS IoT Core MQTT messaging IPC serviceを使用します。

たとえば、上記の例では、processed by componentノードについて説明しています。これは、MQTT ではなく IPC 経由でtest/topicをサブスクライブするローカルコンポーネントです。メッセージを受信すると、コンテンツがコピーされ、起動後からカウントしている回数とともに、test/topic/responseのトピックにパブリッシュされます。

ローカルコンポーネントとのこのクライアントデバイスの双方向通信を実現するために、MQTT bridgeコンポーネントの設定を更新して、カスタムコンポーネントで使用される Pubsub マッピングとの間でトピックをマッピングします。ここでは、topic/test用にlocalMqtt から Pubsub の MQTT bridgeコンポーネントのコンフィグの設定と、Pubsub から localMqtt へのトピックtopic/test/responseを追加した更新を示します。

{
  "mqttTopicMapping": {
    "ClientDevicesToCloud": {
      "topic": "from_local/hello/world",
      "source": "LocalMqtt",
      "target": "IotCore"
    },
    "CloudToClientDevices": {
      "topic": "from_cloud/hello/world",
      "source": "IotCore",
      "target": "LocalMqtt"
    },
    "DevicesToIpc": {
      "topic": "test/topic",
      "source": "LocalMqtt",
      "target": "Pubsub"
    },
    "IpcToDevices": {
      "topic": "test/topic/response",
      "source": "Pubsub",
      "target": "LocalMqtt"
    }
  }
}

この設定を AWS IoT Greengrass Core にデプロイすると、クライアントデバイスは MQTT を使用してメッセージの送受信を行い、ローカルコンポーネントは IPC 機能を使用して MQTT 接続を必要とせずにメッセージを処理できます。

クライアントデバイスのベストプラクティス

新しい Moquette MQTT broker、MQTT bridge、およびClient device authコンポーネントによって提供されるクライアントデバイス機能により、MQTT デバイス(クライアントデバイス)とローカル MQTT ブローカー、AWS IoT Core トピック、および IPC を介したカスタムコンポーネントとの間で、安全で柔軟な通信が可能になります。以下にクライアントデバイスを実装する際のベストプラクティスをいくつか示します。

クライアントデバイスにはパブリック AWS IoT Greengrass エンドポイントへのアクセスが必要

クライアントデバイスが AWS IoT Greengrass Core に接続するには、MQTT ブローカーが使用するサーバー証明書に署名したローカル IP アドレス、ホスト名、および認証局を知る必要があります。これを実現するには、クライアントデバイスがパブリックエンドポイントに認証された呼び出しを行い、必要な情報を返す必要があります。

この検出プロセスは、API 呼び出しを行うときにクライアントデバイスの X.509 証明書と秘密キーを使用して認証します。これは通常の RESTful  APIを通じて実行できますが、 AWS IoT Device SDKs、モバイル SDK、および AWS IoT Device Client には AWS IoT Greengrass Core ディスカバリ機能が組み込まれています。クライアントデバイスにこれらの SDK を使用すると、一般的な MQTT 機能だけでなく、完全な検出プロセスも提供されます。独自の MQTT ライブラリを使用している場合、詳細については、Interact with local IoT devices を参照してください。

可能な場合は、コンポーネント通信に IPC を使用

X.509 証明書を持つクライアントデバイスは通信に MQTT を使用できますが、AWS IoT Greengrass コンポーネントはすべてのパブリッシュおよびサブスクライブ操作に IPC メソッドを使用する必要があります。IPC は、コンポーネントごとにきめ細かいセキュリティコントロールをサポートし、MQTT プロトコルスタックのオーバーヘッドを必要としません。IPC は、MQTT bridgeコンポーネントとパブリッシュ/サブスクライブ IPC サービスを経由したローカル Moquette MQTT broker、および AWS IoT Core MQTT メッセージング IPC サービスを介して AWS IoT Core との相互連携をサポートします。

クライアントデバイスパターンを使用する唯一のケースは、コンポーネントが AWS IoT デバイス SDK が存在するプログラミング言語で記述されている場合だけです。その場合、コンポーネントをクライアントデバイスとして動作させることができますが、AWS IoT Core でthingと証明書の作成を管理する必要があります。

Moquette MQTT broker、IPC、および AWS IoT Core 間のすべてのトピックインタラクションをモデル化し、テストする

クライアントデバイスとMoquette MQTTブローカーや、他のAWSサービスとの連携を実装する場合には、事前にメッセージをどの様にルーティングさせるかをよく確認してください。メッセージのルーティングを視覚化(ドキュメントなどで)することで、問題点をあきらかにすることができます。この作業は、Moquette MQTT brokerと AWS IoT Core 間のメッセージループが発生しないようにするためにも役立ちます。

すべてのメッセージングの設定をおこなった後は、自らテストケースを作成し、テストをすることでClient device authコンポーネントの権限が適切に設定されていることを確認できます。

まとめ

このブログ記事では、AWS IoT Greengrass の新しいクライアントデバイス機能について説明し、使い方の例を挙げました。この例では、クライアントデバイスが Moquette MQTT brokerコンポーネントを使用してローカルで相互に通信するか、AWS IoT Greengrass Core 経由で通信する方法を示しています。また、Moquette MQTT broker、AWS IoT Core、および IPC を使用するコンポーネント間のローカルメッセージをルーティングして処理する方法についても説明しました。

この概要により、既存の AWS IoT を新規または既存の AWS IoT Greengrass バージョン 2 デプロイに組み込むことができるはずです。クライアントデバイスおよび使用するコンポーネントとのインタラクション方法の詳細については、次のドキュメントページを参照してください。

他の AWS IoT Greengrass の機能と機能に慣れるために、ドキュメントとワークショップへの追加リンクをいくつか紹介します。


この記事はSolution Architectの市川が翻訳しました。原文のブログはこちらになります。