[AWS IoT] マルチアカウント登録で手元の証明書を登録してみました

2021.03.17

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

CX事業本部の平内(SIN)です。

AWS IoTでのレジストリへの証明書登録は、マルチアカウント登録により、別リージョンや、別アカウントの証明書を登録したり、CAなしで証明書だけを登録することが可能になっています。


参考:AWS IoT Core マルチアカウント登録で、IoT デバイス登録が簡素化し、AWS アカウント間のデバイス移動が簡単に

今回は、幾つかのパターンで証明書を登録してみました。

2 証明書の作成

最初に基本的な動作を確認するために、AWS IoTのコンソールから証明書を作成します。

作成された証明書は、有効化してダウンロードします。

証明書の有効性の確認作業のため、アタッチするポリシーはIoTフルアクセスにしています。

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

3 テスト用のコード

AWS IoT Device SDK v2 for Pythonのサンプルを元に、簡単に証明書を使用して、PublishとSubscribeを行うテスト用のコードを用意しました。

import time
import json
from awscrt import io, mqtt
from awsiot import mqtt_connection_builder

endpoint = "xxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com"
cert = "./85be9faffd-certificate.pem.crt"
key = "./85be9faffd-private.pem.key"
root_ca = "./root-CA.crt"

client_id = "client_id"
topic = "topic"

def on_message_received(topic, payload):
	print("Received: {}".format(payload.decode()))

if __name__ == '__main__':
	event_loop_group = io.EventLoopGroup(1)
	host_resolver = io.DefaultHostResolver(event_loop_group)
	client_bootstrap = io.ClientBootstrap(event_loop_group, host_resolver)

	mqtt_connection = mqtt_connection_builder.mtls_from_path(
		endpoint = endpoint,
		cert_filepath = cert,
		pri_key_filepath = key,
		client_bootstrap = client_bootstrap,
		ca_filepath = root_ca,
		client_id = client_id,
		clean_session = False,
		keep_alive_secs = 6)

	connect_future = mqtt_connection.connect()
	connect_future.result()
	print("Connected!")

	# Subscribe
	subscribe_future, _ = mqtt_connection.subscribe(
		topic = topic,
		qos = mqtt.QoS.AT_LEAST_ONCE,
		callback = on_message_received)
	subscribe_future.result()

	# Publish
	for i in  range(3):
		payload = {
			"counter": i,
			"message": "TEST"
		}
		mqtt_connection.publish(
			topic = topic,
			payload = json.dumps(payload),
			qos = mqtt.QoS.AT_LEAST_ONCE)
		time.sleep(1)

	disconnect_future = mqtt_connection.disconnect()
	disconnect_future.result()
	print("Disconnected!")

実行すると、AWS IoT コンソールの テストでmqttメッセージを確認できます。

自分でPublishしたトピックを受信できていることも確認できます。

Connected!
Received: {"counter": 0, "message": "TEST"}
Received: {"counter": 1, "message": "TEST"}
Received: {"counter": 2, "message": "TEST"}
Disconnected!

4 証明書削除

次に、作成した証明書をレジストリから削除して、接続できなくなることを確認しています。従来は、この時点で手元の証明書は、2度と利用できませんでした。

テスト用コードを実行すると、mqtt_connection.connect() がエラーとなります。

awscrt.exceptions.AwsCrtError: AwsCrtError(name='AWS_ERROR_MQTT_UNEXPECTED_HANGUP',\
 message='The connection was closed unexpectedly.', code=5134)

5 証明書の再登録

手元に残った証明書を再度、レジストリに登録してみます。

CAの登録は無しで、「次へ」へ進みます。

手元の証明書を選択して証明書の登録をクリックします。

レジストリに再び登録された事が確認できますが、ステータは無効となっています。

使用可能とするため「有効化」にして、「ポリシー」をアタッチします。

こうすることで、再び、接続可能になることが確認できます。

Connected!
Received: {"counter": 0, "message": "TEST"}
Received: {"counter": 1, "message": "TEST"}
Received: {"counter": 2, "message": "TEST"}
Disconnected!

6 別リージョンへ登録する

IoT Coreのエンドポイントは、リージョンごとに違います。

そしてレジストリも別となるため、エンドポイントだけを差し替えても先のテスト用コードでは接続できません。

# endpoint = "xxxxxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com"
endpoint = "xxxxxxxxxxxx-ats.iot.us-east-1.amazonaws.com"
awscrt.exceptions.AwsCrtError: AwsCrtError(name='AWS_ERROR_MQTT_UNEXPECTED_HANGUP',\
 message='The connection was closed unexpectedly.', code=5134)

先の「5 証明書の再登録」をこの別リージョンで行い、手元の証明書を登録すれば、接続可能となります。

7 別アカウントへ登録する

「5 証明書の再登録」の手順を、別のAWSアカウントで行っても、同じ手元の証明書で接続可能です。 テスト用コードでは、endpointだけを、別アカウントの当該リージョンに向けるだけです。

Connected!
Received: {"counter": 0, "message": "TEST"}
Received: {"counter": 1, "message": "TEST"}
Received: {"counter": 2, "message": "TEST"}
Disconnected!

8 キーチェーンアクセスで作成した証明書を登録する

CA登録が必須では無いため、手元で新しく証明書を作成してもレジストリへの登録は可能です。最後に、Macのキーチェーンアクセスで証明書を作成して試してみました。

※ 以下の作業(しくみ)は、証明書チェーンが無いため、証明書の信用は登録者の自己責任となります。あくまで、CA登録なしでのレジストリ登録が可能になった、マルチアカウント登録 を確認するために行った作業です。登録した証明書は削除しておくことをお勧めします。

キーチェーンアクセスのメニューから「証明書アシスタント」ー「証明書を作成」と辿ります。

証明書のタイプを「SSLクライアント」とし、適当な名前をつけ作成します。

「自分の証明書」で、作成した証明書を確認できます。

作成した証明書を右クリックして、「書き出し」を行います。

書き出しは、「証明書(.cer)」及び、「個人情報交換(.p12)」で2回に分けて行います。

p12のパスワードは、ここでは空にしています。

書き出された、「証明書(.cer)」及び、「個人情報交換(.p12)」です。

opensslコマンドで、AWSで利用可能なPEM形式に変換しています。

% openssl x509 -in MyCertSample.cer -inform DER -out cert.crt -outform PEM
% openssl pkcs12 -in MyCertSample.p12 -nocerts -nodes -out key.pem
Enter Import Password:

秘密鍵(key.pem)と証明書(cert.crt)を先のテスト用コードから使用します。また、証明書(cert.crt)の方は、「5 証明書の再登録」の手順で、レジストリに登録します。

登録された証明書の名前は、SHA-256のハッシュとなっているので、予めプレビュー等で確認しておくと、登録後に検索できます。

テスト用のコードで、問題なく接続できることが確認できます。

Connected!
Received: {"counter": 0, "message": "TEST"}
Received: {"counter": 1, "message": "TEST"}
Received: {"counter": 2, "message": "TEST"}
Disconnected!

9 最後に

今回は、AWS IoTのマルチアカウント登録について、幾つか試してみました。

CA登録が必要なくなると、証明書の信頼は自己責任となりますが、組み込みデバイスなどで、証明書を製造段階で生成する場合や、既に組み込まれている証明書セットを利用する場合の作業方法が、格段に広がっていると思います。

10 参考にさせて頂いたリンク


MacOS でクライアント証明書を発行してみる