この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、hagiwaraです。 AWS IoTでデバイス(モノ)を初回接続時に自動登録することができます。その方法が2種類あります。Just-in-Time Registration (JITR)とJust-in-Time Provisioning (JITP)です。今回は後者のJITPを試してみました。 前者のJITRについては、高橋さんのブログを参照してください。
AWS IoTを使用しているので「デバイス」ではなく「モノ」という単語を使うべきとも思いましたが、個人的に「モノ」が脳内でゲシュタルト崩壊?してしまったので、「デバイス」で統一しています。
JITRとJITPの違い
両者の異なる点は、デバイスをAWS Lambdaを使用して登録するのか、JSON形式のプロビジョニング用テンプレートを元に登録するのかという点です。CA証明書および検証用証明書をAWSに設定する点は同じです。
上の図は、オフィシャルブログに記載されているものを元に記載しました。 どちらを採用するかの判断は、Lambdaで細かいカスタマイズをする必要がある場合はJITR、テンプレートで事足りる場合はJITPといった感じでしょうか。
セットアップ
JITPの設定を行なっていきます。
1. 独自のCA証明書および検証用証明書の作成
ここは、JITRと同様です。
1-1 CA証明書作成
# キーペア作成
openssl genrsa -out rootCA.key 2048
# 証明書作成
CA_SUBJ="/C=JP/ST=Tokyo/L=Tokyo/O=MyOrg/OU=MyOU/CN=RootCA"
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem -subj "$CA_SUBJ"
1-2 検証用証明書作成
# キーペア作成
openssl genrsa -out verificationCert.key 2048
# AWS IoTのユーザーCA登録コード取得
CODE=`aws iot get-registration-code --output text`
# コモンネームに登録コードを設定してCSRを作成
VC_SUBJ="/C=JP/ST=Tokyo/L=Tokyo/O=MyOrg/OU=verification/CN=${CODE}"
openssl req -new -key verificationCert.key -out verificationCert.csr -subj "$VC_SUBJ"
# 証明書を作成
openssl x509 -req -in verificationCert.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out verificationCert.pem -days 500 -sha256
2. デバイスを自動登録するロールの作成
JITPを行うIAM Roleを作成します。
2-1 IAM ロール一覧
IAM の画面から [ロールの作成] を選択。
2-2 信頼されたエンティティの種類およびユースケースの選択
信頼されたエンティティはAWSサービス、ユースケースにIoTを選択して次へ。
2-3 アクセス権限
必要に応じアクセス権限の境界を設定しますが、今回はなにもせずデフォルトのまま次へ。
2-4 タグ
お好みでタグを追加し次へ。
2-5 確認
ロール名を入力し作成。今回はJITPRole
という名前にしました。
3. デバイスにアタッチするポリシーの作成
テンプレートからポリシーを作成することも可能ですが、そうするとデバイスごとに別のポリシーが作成されてしまいます。今回は共通で使用するポリシーをあらかじめ作成しておきます。
AWS IoT Coreコンソール画面をブラウザで開き、[安全性] → [ポリシー] → [作成] → [アドバンストモード] を選択し、以下を入力して作成しました。
名前 :
jitp-things-policy
ステートメント :
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "iot:Connect",
"Resource": "arn:aws:iot:ap-northeast-1:<アカウントID>:client/${iot:Connection.Thing.ThingName}",
"Effect": "Allow"
},
{
"Action": [
"iot:Publish",
"iot:Receive"
],
"Resource": "arn:aws:iot:ap-northeast-1:<アカウントID>:topic/$aws/things/${iot:Connection.Thing.ThingName}/shadow/*",
"Effect": "Allow"
},
{
"Action": "iot:Subscribe",
"Resource": "arn:aws:iot:ap-northeast-1:<アカウントID>:topicfilter/$aws/things/${iot:Connection.Thing.ThingName}/shadow/*",
"Effect": "Allow"
}
]
}
4. テンプレートの作成
4-1 プロビジョニングの設定をテンプレートに記述
以下のようなテンプレートを作成しました。
パラメータの内容についてこちらを参照してください。ポイントはThingName
にデバイス証明書のコモンネームを代入している点と、先ほど作成したポリシーを指定しているところです。
今回は設定していませんが、タイプやグループも指定可能です。その場合はあらかじめそれらを作成しておく必要があります。
{
"Parameters": {
"AWS::IoT::Certificate::CommonName": { "Type": "String" },
"AWS::IoT::Certificate::Country": { "Type": "String" },
"AWS::IoT::Certificate::Id": { "Type": "String" }
},
"Resources": {
"thing": {
"Type": "AWS::IoT::Thing",
"Properties": {
"ThingName": { "Ref": "AWS::IoT::Certificate::CommonName" },
"AttributePayload": { "version": "v1", "country": { "Ref": "AWS::IoT::Certificate::Country" } }
}
},
"certificate": {
"Type": "AWS::IoT::Certificate",
"Properties": {
"CertificateId": { "Ref": "AWS::IoT::Certificate::Id" },
"Status": "ACTIVE"
}
},
"policy": {
"Type": "AWS::IoT::Policy",
"Properties": {
"PolicyName": "jitp-things-policy"
}
}
}
}
4-2 テンプレートとロールを統合
上記テンプレートを文字列にしてtemplateBody
に、先ほど作成したロールをroleArn
に設定したファイルを作成します。今回はprovisioning-template.json
という名前で作成しました。
{
"templateBody": "{\"Parameters\":{\"AWS::IoT::Certificate::CommonName\":{\"Type\":\"String\"},\"AWS::IoT::Certificate::Country\":{\"Type\":\"String\"},\"AWS::IoT::Certificate::Id\":{\"Type\":\"String\"}},\"Resources\":{\"thing\":{\"Type\":\"AWS::IoT::Thing\",\"Properties\":{\"ThingName\":{\"Ref\":\"AWS::IoT::Certificate::CommonName\"},\"AttributePayload\":{\"version\":\"v1\",\"country\":{\"Ref\":\"AWS::IoT::Certificate::Country\"}}}},\"certificate\":{\"Type\":\"AWS::IoT::Certificate\",\"Properties\":{\"CertificateId\":{\"Ref\":\"AWS::IoT::Certificate::Id\"},\"Status\":\"ACTIVE\"}},\"policy\":{\"Type\":\"AWS::IoT::Policy\",\"Properties\":{\"PolicyName\":\"jitp-things-policy\"}}}}",
"roleArn": "arn:aws:iam::<アカウントID>:role/JITPRole"
}
JSON→文字列の変換は、ブラウザのコンソールから雑に...
JSON.stringify({templateBody:JSON.stringify(JSON.parse(`<ここにコピペ>`))})
5. CA証明書およびテンプレートの登録
上記で作成したCAを登録し、自動登録の設定を追加します。
# AWSに独自CA証明書を登録
aws iot register-ca-certificate --ca-certificate file://rootCA.pem --verification-cert file://verificationCert.pem
# 以下、上記で返却される証明書ID(certificateId)を使用
# 登録した証明書をアクティブに変更
aws iot update-ca-certificate --certificate-id <証明書ID> --new-status ACTIVE
# テンプレートを指定して自動登録を有効化
aws iot update-ca-certificate --certificate-id <証明書ID> --new-auto-registration-status ENABLE --registration-config file://provisioning-template.json
以上で設定は終了です、次はデバイスの登録を行なっていきます。
デバイスを接続する
先ほど作成した独自のCA証明書から、デバイスごとにデバイス証明書を作成し、それを使用して接続します。 AWS IoT は登録されていない証明書でのアクセスがあった場合、その証明書を検証します。登録されたCAに基づくものであれば、自動で証明書の登録を行い、テンプレートの内容に従ってデバイスの登録を行います。
1. デバイスごとにデバイス証明書を作成
MyJITPThing
という名前にして証明書を作成しました。接続に使用する証明書にはCA証明書を含める必要があるので、デバイス証明書とCA証明書を統合します。
# 名前
THING_NAME="MyJITPThing"
# キーペア作成
openssl genrsa -out deviceCert.key 2048
# コモンネームに名前を設定してCSRを作成
DE_SUBJ="/C=JP/ST=Tokyo/L=Tokyo/O=MyOrg/OU=device/CN=${THING_NAME}"
openssl req -new -key deviceCert.key -out deviceCert.csr -subj "$DE_SUBJ"
# 証明書作成
openssl x509 -req -in deviceCert.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out deviceCert.crt -days 365 -sha256
# デバイス証明書とCA証明書を統合
cat deviceCert.crt rootCA.pem > deviceCertAndCACert.crt
2. AWSサーバー接続用の証明書を取得
AWSサーバー認証用の証明書をダウンロードしておきます。AWS ドキュメント
curl https://www.amazontrust.com/repository/AmazonRootCA1.pem > root.cert
3. AWS IoT に接続する
mosquitto_sub
を使って未登録の証明書で接続してみます。
END_POINT=`aws iot describe-endpoint --endpoint-type iot:Data-ATS --output text`
mosquitto_sub --cafile root.cert \
--cert deviceCertAndCACert.crt \
--key deviceCert.key \
-h $END_POINT \
-p 8883 \
-q 1 \
-i MyJITPThing \
--tls-version tlsv1.2 \
-t '$aws/things/MyJITPThing/shadow/update/delta' \
-d
以下のような感じで出力されました、無事接続はできてそうです。
$ mosquitto_sub --cafile root.cert --cert deviceCertAndCACert.crt --key deviceCert.key -h $END_POINT -p 8883 -q 1 -i MyJITPThing --tls-version tlsv1.2 -t '$aws/things/MyJITPThing/shadow/update/delta' -d
Client MyJITPThing sending CONNECT
Client MyJITPThing sending CONNECT
Client MyJITPThing sending CONNECT
Client MyJITPThing sending CONNECT
Client MyJITPThing sending CONNECT
3. 確認
コンソールからも無事登録されてることが確認できました!
記載はしていませんが、詳細画面から自動登録された証明書と、前もって作成しておいたポリシーがアタッチされていることが確認できます。
まとめ
以上、テンプレートを使用したデバイス登録を試してみました。デバイス登録時の設定がテンプレートで事足りる場合は、Lambdaを実装しなくていいのでこちらのほうがよさそうです。
参考 URL
ジャストインタイムのプロビジョニング Setting Up Just-in-Time Provisioning with AWS IoT Core AWS IoTの証明書自動登録でクライアント証明書の運用を楽にする