AWS-IoT-Core

AWS IoTで独自CAで発行した証明書を自動登録するようにしてみた

はじめに

こんにちは、omkです。
前回は独自のCAで発行した証明書を手動でAWS IoTに登録して利用できるところまでを実現しました。
AWS IoTにEasy-RSAで作った自己証明書で接続してみた

今回は認証機関側で証明書の自動登録を有効にした上で、デバイスからのリクエスト時に自動でアクティブにするところまでを実現しようと思います(これがJITRというやつなんですかね?)。

やってみた

前回の続きからやります。
以下の公式ブログを参考しながら進めます。
https://aws.amazon.com/jp/blogs/iot/just-in-time-registration-of-device-certificates-on-aws-iot/

前回はとりあえず自動登録をオフにした状態でCA証明書を登録していました。

アクションからオンにできます。

これでこのCA証明書を使用して接続があった際にAWS側で証明書の登録をしてくれます。
ただし、「保留中のアクティベーション」というステータスで登録されるのでこのまま即クライアントが接続出来るようになるわけではありません。

新規にクライアント証明書を発行して再度接続してみます。
その際にクライアント証明書にCA証明書の内容を含めておく必要があります。

$ cat client.crt ca.crt > client_ca.crt

接続をリクエストしたところ、証明書が登録されました。

このとき、 $aws/events/certificates/registered/<caCertificateID> のトピックに対して以下の形式でメッセージがパブリッシュされます。

{
  "certificateId": "<certificateID>",
  "caCertificateId": "<caCertificateId>",
  "timestamp": "<timestamp>",
  "certificateStatus": "PENDING_ACTIVATION",
  "awsAccountId": "<awsAccountId>",
  "certificateRegistrationTimestamp": "<certificateRegistrationTimestamp>"
}

MQTTテストクライアントで対象トピックをサブスクライブしておくと後々進めやすくなりました。

このトピックを対象にメッセージのルーティングルールを設定します。
以下のSQLで設定します。

SELECT *
FROM '$aws/events/certificates/registered/<caCertificateId>'
WHERE certificateStatus = "PENDING_ACTIVATION"

アクションをLambdaにして以下のPythonを実行します。

import json
import sys
import boto3

def lambda_handler(event, context):

    try:

        client = boto3.client('iot')

        # 証明書のアクティベーション
        client.update_certificate(
            certificateId = event['certificateId'],
            newStatus = 'ACTIVE'
        )

        cert = client.describe_certificate(
            certificateId = event['certificateId']
        )
        # ポリシーの作成

        doc =  {
                  "Version": "2012-10-17",
                  "Statement": [
                    {
                      "Effect": "Allow",
                      "Action": "*",
                      "Resource": "*"
                    }
                  ]
                }

        policy = client.create_policy(
            policyName = event['certificateId'] + "-policy",
            policyDocument = json.dumps(doc)
        )

        # ポリシーのアタッチ
        response = client.attach_principal_policy(
            policyName = policy['policyName'],
            principal = cert['certificateDescription']['certificateArn']
        )

    except Exception as e:
        print(e)
        sys.exit(1)

ポリシーのドキュメントは実際の用途に合わせていい感じに修正してください。
また、Lambdaには必要なIAM権限を付与する必要があります。

この状態でクライアントから接続リクエストを投げます。

証明書が登録され、作成されたポリシーがアタッチされています。
この時点では接続できませんが、もう一度接続リクエストをしなおしたら接続可能です。

おわりに

これで証明書を自動で登録してクライアントが接続できるようになりました。
メーカーなどで多くの端末を製造しているケースではこういった対応が必要なのですかね。
ここから更にモノの登録も行ってすべて自動で管理されるようにするのが理想的なあり方のように思います。

以上、最後までお付き合いありがとうございました。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA