AWS IoT JobsでS3からファイルを有効期限付きURLで配布してみた

Pocket

AWS IoT Jobsでファイルを有効期限付きURLで配布したい

デバイスのファームウェアのアップデートといった用途で、AWS IoT Jobsを使ってファイルをデバイスに配布できるか、またその配布に有効期限を付けられるかを確認したかったので調べてみました。しかし、AWSマネジメントコンソールで一連の操作を完結する記事を見つけられませんでした。そこで、これからAWS IoTを使う方向けに、この一連の操作をAWSマネジメントコンソールで行った場合の手順をお伝えします。

環境

以下の環境で試しました。

  • Windows 10 (お試しなのでデバイスを模して普段使うラップトップを使います)
  • Node.jsインストール済み (サンプルプログラムで使います)
  • ポート8883を開放済み (AWS IoT CoreとMQTTで通信するのに使用します)

SDKの準備

AWS IoT Coreサービスを開き、左ペインの「オンボード」の「開始方法」をクリックします。

「開始方法」をクリックします。

「開始方法」をクリックします。

プラットフォームの選択は「Windows」を、AWS IoT デバイスSDKの選択は「Node.js」を選択します。

任意の名前を入力します。

「Windows」をクリックして接続キットのダウンロードを開始します。

ダウンロードした圧縮ファイルを解凍します。圧縮ファイルには以下のファイルが含まれています。

ファイル名 説明
miso_things_1.cert.pem クライアント証明書
miso_things_1.private.key クライアント証明書の秘密鍵
miso_things_1.public.key クライアント証明書の公開鍵
start.sh メッセージを送受信するスクリプト

「次のステップ」をクリックすると、デバイスの設定とテストの画面になります。

接続キットを解凍したフォルダでPowerShellを開き、以下のコマンドで実行権限を付与します。

AWS IoT SDKをインストールします。

開始スクリプトstart.ps1を起動します。

デバイスからのメッセージが表示されます。ここで失敗する場合は、ファイアウォールのポート開放ができていないか、開発環境のセキュリティポリシーによりはじかれている可能性があります。

デバイスへメッセージを送信してみます。

送信したメッセージがPowerShell上に表示されます。

次の画面に進み、「完了」をクリックします。

モノが追加できたことを確認できます。

ここまででモノの追加、AWS IoT SDKのインストール、AWS IoT Coreとの送受信の確認ができました。

S3バケットの準備

S3バケットを準備します。このバケットには、AWS IoT Coreのジョブの内容を記載するジョブドキュメントとデバイスに配信するファイルを置きます。

S3のサービスを開き、「バケットを作成する」をクリックします。

任意のバケット名を入力します。バケット名はS3の既存バケットの中で一意の名前である必要があります。「次へ」をクリックします。

オプションの設定はデフォルトのまま「次へ」をクリックします。

アクション許可の設定はデフォルトのままにし、「次へ」をクリックします。

「バケットを作成」をクリックします。

バケットが作成されました。

IAMロールの準備

AWS IoT Coreサービスが、Amazon S3の特定のバケットからダウンロードできるようにするためのIAMロールを作成します。

ポリシーの作成

S3からのダウンロードを許可するIAMポリシーを作成します。IAMポリシーとは、AWSリソースにアクセスするための権限設定のことです。デフォルトでAWSが様々なポリシーを用意してくれていますが、特定のAmazon S3のバケットからのダウンロードだけを許可するポリシーがないため新たに用意してみます。

IAMサービスを開き、IAMサービスの左ペインの「ポリシー」をクリックします。

「ポリシーの作成」をクリックします。

「サービスの選択」をクリックします。

検索欄に「S3」と入力し、表示された「S3」をクリックします。

次にアクションを開き、検索欄に「ListBucket」と入力し、「ListBucket」をチェックします。

今度は検索欄に「GetObject」と入力し、「GetObject」をチェックします。

次にリソースを開き、「bucket」の「ARNの追加」をクリックします。

Bucket name *」の入力欄にアクセスを許可したいバケット名を入力し、「追加」をクリックします。

object」の「ARNの追加」をクリックします。

Bucket name *」に先程と同じバケット名を入力し、「Object name *」は「すべて」をチェックします。

「ポリシーの確認」をクリックします。

「名前」に任意の名前を入力します。「説明」にはポリシーの説明を設定します。その後、「ポリシーの作成」をクリックします。

ポリシーが作成されました。

ロールの作成

左ペインの「ロール」をクリックし、「ロールの作成」をクリックします。

S3」のサービスをクリックします。

ユースケースの選択で「S3」を選択し、「次のステップ:アクセス権限」をクリックします。

検索欄に先程作成したポリシー名を入力し、表示されたポリシーをチェックします。その後、「次のステップ:タグ」をクリックします。

デフォルトのまま「次のステップ:確認」をクリックします。

ロール名とロールの説明に任意の内容を入力し、「ロールの作成」をクリックします。

ロールが作成されました。

ロールの信頼関係の編集

IoT Coreのモノは、ここで作成したロールの権限を取得することになりますので、IoT Coreのサービスを信頼するように設定する必要があります。

先程作成したロールをクリックします。

「信頼関係」タブを開き、「信頼関係の編集」をクリックします。

デフォルトでは以下のように信頼関係が設定されています。

信頼するサービスに「iot.amazonaws.com」を追加します。

「信頼ポリシーの更新」をクリックします。

信頼されたエンティティにIoT Coreのサービスが登録されました。

 

ロールエイリアスの作成

AWSのサービスを直接呼び出すデバイスは、 IoT Coreに接続するときにどのARNロールを使用するかを知る必要があります。ARNロールをハードコーディングすると、ロールのARNが変わるたびにデバイスを更新することになってしまい、手間です。そのため、ロールエイリアスを用意します。そうすることで、ロールのARNが変更された場合には、ロールエイリアスを更新するだけで済みます。

IoT Coreのサービスを開き、左ペインの「安全性」の「ロールエイリアス」を開き、「ロールエイリアスを作成」をクリックします。

名前に任意の内容を入力し、エイリアスのロールは先程作成したロールを選択します。その後、「ロールエイリアスを作成」をクリックします。

ロールエイリアスが作成されました。

デバイス証明書にポリシーをアタッチ

ポリシーをデバイス証明書にアタッチします。デバイス証明書にアタッチされているポリシーは、デバイスにロールを引き受ける権限を付与する必要があります。「iot:AssumeRoleWithCertificate」アクションへのアクセス許可をロールエイリアスに付与します。

AWS IoT Coreの左ペインの「安全性」>「ポリシー」をクリックし、「作成」をクリックします。

任意の名前を入力し、アクションに「iot:AssumeRoleWithCertificate」と入力します。リソースARNには自動で入力されます。ここに表示される数字列はAWSのアカウントIDです。

リソースARNの「topic/replaceWithATopic」を「rolealias/先程作成したロールエイリアス名」に変更します。「許可」をチェックし、「作成」をクリックします。

「ステートメントの追加」をクリックし、同様の手順で以下の表のアクションを追加します。※iot:AssumeRoleWithCertificateは上記手順で登録済み

アクション リソースARN
iot:AssumeRoleWithCertificate arn:aws:iot:ap-northeast-1:[AWSアカウントID]:rolealias/
iot:Connect

arn:aws:iot:ap-northeast-1:[AWSアカウントID]:client/miso*
※「miso*」の部分は接続を許可したいモノの名前を指定します。

iot:Publish

arn:aws:iot:ap-northeast-1:[AWSアカウントID]:
topic/$aws/things/${iot:Connection.Thing.ThingName}/jobs/*

iot:Subscribe

arn:aws:iot:ap-northeast-1:[AWSアカウントID]:
topicfilter/$aws/things/${iot:Connection.Thing.ThingName}/jobs/*

iot:Receive

arn:aws:iot:ap-northeast-1:[AWSアカウントID]:
topic/$aws/things/${iot:Connection.Thing.ThingName}/jobs/*

ポリシーが作成されました。

証明書をアタッチするモノを開きます。

「セキュリティ」を開きます。

証明書を開きます。

「ポリシー」を開き、「ポリシーのアタッチ」をクリックします。

先程作成したポリシーをチェックし、「アタッチ」をクリックします。

ポリシーがアタッチされました。

ジョブ

ファイルダウンロードのジョブを準備し、実際にジョブを実行してみます。

S3にファイルを作成

S3のバケットを開き、「アップロード」をクリックします。

ファームウェアのファイルを模したファイルを用意します。お試しなのでファイルの中身は以下のようにしました。

S3にドラッグアンドドロップします。

「アップロード」をクリックします。

ファイルのアップロードができました。

次にジョブドキュメントを以下のように作成します。ジョブドキュメントは、UTF-8 でエンコードされた JSON ドキュメントで、デバイスがジョブを実行するために必要な情報を含みます。ジョブドキュメントは、S3 バケットに格納することも、ジョブを作成するコマンドにインラインで含めることもできます。ジョブドキュメントの例は、AWS IoT SDK for JavaScriptのjobs-agent.js が参考になります。

  • operation
    • AWS IoT SDKにどういうジョブを実行するのか指定できます。プログラムの中でジョブごとにやらせたいことを定義できます。
  • version
    • バージョン番号を想定した項目です。このようにAWS IoT SDKに通知したい項目を自由に追加できます。
  • url
    • デバイスをセキュリティで保護し、ジョブドキュメント自体に含まれるデータ以外のデータに時間制限付きでアクセスできるようにするために、署名付きAmazon S3 URLを使用します。データをAmazon S3 バケットに配置し、ジョブドキュメント内のデータにプレースホルダーリンクを追加することができます。AWS IoT Coreのジョブサービスが、ジョブドキュメントのリクエストを受け取ると、このジョブドキュメントを解析してプレースホルダーリンクを探し、それを署名付きAmazon S3 URLに置き換えます。

以下の形式で使用します。

bucketはS3バケット名、keyはオブジェクト名を指定します。デバイスに通知される署名付きAmazon S3 URLは以下のような形になります。

先程の要領で作成したジョブドキュメントをS3バケットにアップロードします。

ジョブの作成

実際にジョブを作成して、ジョブを実行してみます。

IoT Coreサービスの「ジョブ」を開き、「ジョブを作成する」をクリックします。

「カスタムジョブの作成」をクリックします。

「ジョブID」と「説明」に任意の内容を入力し、「更新するデバイスの選択」の「選択」をクリックします。

対象のモノをチェックし、「ジョブファイルの追加」の「選択」をクリックします。

先程作成したジョブドキュメントを選択します。

「事前署名リソースURL」を「ジョブファイルは構成済みでありURLの事前署名を行う」を選択し、S3読み込み用のロールを選択します。その後、「次へ」をクリックします。

高度な設定はデフォルトのまま「作成」をクリックします。

ジョブの作成が完了しました。もしもここで失敗する場合は、IAMロールの信頼関係の設定誤りの可能性があります。作成したジョブを開きます。

現在のジョブの状況が表示されます。

ジョブを実行するNode.jsのプログラム

署名付きAmazon S3 URLからダウンロードするプログラムを以下のように作成してみました。

プログラムを起動する時の引数は –help で確認できます。

-H は AWS IoT Coreの左ペインの「設定」で確認できるエンドポイントを指定します。

作成したプログラムを起動してみます。

ジョブの完了がAWS IoT Coreに通知され、無事にジョブが完了しました。ここで失敗する場合は、デバイス証明書にアタッチしたポリシーに誤りがある場合や、ジョブドキュメントの内容に誤りがあることが考えられます。

プログラムを実行したフォルダに生成されている download.txt を開いてみます。ファイルの中身がS3バケットのファイルと一致しており、正しくダウンロードできたことを確認できました。

おわりに

無事にファイルダウンロードのジョブを実行することができました。これでデバイスのファームウェアの更新や設定ファイルの送信といった用途に使うことができます。今回はお試しでしたので、本番環境では以下のようなことをきちんと検討する必要があると考えています。

  • rootユーザーで一連の操作をしましたが、運用ではIAMユーザーで操作することになるので、少し操作内容が変わるはず
  • モノのグループをうまく活用することで、多くのデバイスに少ない操作でまとめてファイルダウンロードの実行を通知できるようになるはず

また、今回はファイルダウンロードでしたが、IAMロールのポリシーのGetObjectといった部分をPutObjectといった書き込みの内容にすれば、S3へのファイルアップロードもすんなりと実現できるでしょう。それを使ってログファイルをアップロードすれば、遠隔地からログの解析もできるようになります。

最後に、今回はジョブの記事を書かせていただきましたが、また機会があればデバイスシャドウを試した記事を書いてみたいです。というのも、今回の記事は情報量が多く、デバイス証明書にアタッチするポリシーの説明ができなかったためです。どうぞ次回をお楽しみに!

お問い合わせ先

執筆者プロフィール

Satou Fumiaki
Satou FumiakiTDIPS ソリューション開発部
IoTの製品企画を担当。IoTを使ってお客様に価値を提供できるように奮闘中。
最近はこれまでのIoT製品と組み合わせた分析ソリューションを企画中。
Pocket