opensslとmosquittoでAWS IoT Coreの "CAを登録せずにクライアント証明書を登録する" を試す

AWS IoT EduKitの動作を理解するためには、 2020年4月に一般提供開始となった「[マルチアカウント登録による複数の AWS アカウントでの X.509 クライアント証明書の使用](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/x509-client-certs.html#multiple-account-cert)」で使えるようになった機能「**CAを登録せずにクライアント証明書を登録する**」を知っておく必要があったので、opensslとMQTTクライアントである[mosquitto](https://mosquitto.org/)を使って動作を確認してみました。

## 論よりコード

### 独自CAのプライベートキーと証明書の作成

```console
$ openssl req -x509 -newkey rsa:2048 -sha256 -nodes -keyout CA.key -out CA.crt -subj "/CN=example.com" -days 3650
$ ls CA.*
CA.crt  CA.key
```

### クライアント用のプライベートキーと証明書(CSR経由)の作成 

```console
$ openssl genrsa -out device1.key 2048
$ openssl req -new -key device1.key -out device1.csr -subj "/CN=device1"
$ openssl x509 -req -in device1.csr -CA CA.crt -CAkey CA.key -CAcreateserial -days 365 -sha256 -out device1.crt
$ ls device1.*
device1.crt  device1.csr  device1.key
```

### AWS IoT Core への登録

(CLIを使用、Webコンソールの方法は[こちら](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/manual-cert-registration.html#manual-cert-registration-console-noca))

※ `$certificateId` と `$certificateArn` は `aws iot register-certificate-without-ca` の返却値を利用。

<details><summary>※ AllowAll" ポリシーは作成済み</summary><div>

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:*",
      "Resource": "*"
    }
  ]
}
```
</div></details>


```console
$ aws iot register-certificate-without-ca --certificate-pem file://device1.crt
$ aws iot update-certificate --certificate-id $certificateId --new-status ACTIVE
$ aws iot attach-policy --target $certificateArn --policy "AllowAll"
```

### AWS IoT Core への接続

※ `endpointAddress` は `aws iot describe-endpoint --endpoint-type IoT:Data-ATS` で入手

```console
$ curl -O https://www.amazontrust.com/repository/AmazonRootCA1.pem
$ mosquitto_sub -d --cert device1.crt --key device1.key --cafile AmazonRootCA1.pem -h $endpointAddress -p 8883 -t my/topic
```

### 片付け

※ いきなり delete-certificate しても動きますが、まあお作法として。

```console
$ aws iot detach-policy --target $certificateArn --policy "AllowAll"
$ aws iot update-certificate --certificate-id $certificateId --new-status INACTIVE
$ aws iot delete-certificate --certificate-id $certificateId
```


## 手元にクライアントのプライベートキーがある場合の AWS IoT Core に MQTTS 接続する方法

AWS IoT Core へMQTTS接続する際に必要なのは以下の情報です。

- 証明書(クライアント毎)
- プライベートキー(クライアント毎)
- TLS通信に使用するサーバー証明書
- AWS IoT Core のエンドポイントアドレス

この情報をmosquittoに当てはめると以下のようになります。

```console
$ mosquitto_pub \
  --cert 証明書(クライアント毎) \
  --key プライベートキー(クライアント毎) \
  --cafile TLS通信に使用するサーバー証明書 \
  -h AWS IoT Core のエンドポイントアドレス \
  -p 8883 -t TOPIC -m MESSAGE        
```

クライアントのプライベートキーが手元にある状態においてAWS IoT Coreに接続する場合、本機能ができる前までは以下のような選択肢がありました。

- A: クライアントのプライベートキーからCSRを作成し、AWS IoT Coreの "証明書" > "CSR による作成" [create-certificate-from-csr] で登録しつつ、証明書をダウンロード
- B: 「独自CA」の証明書をAWS IoT Coreに登録 [register-ca-certificate] しておき、証明書(クライアント毎)の登録 [register-certificate] の際に登録済みの独自CAを選択

本機能はAとBの中間に位置するようなものです。
Aはクライアント証明書の作成はAWS IoT Coreが行いますが、本機能はクライアント証明書は作成済みであることを前提としています。
Bはクライアント証明書に署名したCAをAWS IoT Coreに登録の必要がありますが、本機能はCAの登録は不要です。プライベートキーが手元にあるなら、証明書もあるよね、、、という前提ですが。

[AWS IoT サービス アップデートのご紹介 / P25](https://www.slideshare.net/AmazonWebServicesJapan/aws-iot-238410946/25)でも解説されている通り、CA登録をしなくともクライアント証明書さえあればAWS IoT Coreに登録できるのがポイントです。
※実際の登録には IAM ポリシーの `iot:RegisterCertificateWithoutCA` 権限も必要となるため、むやみやたらに登録できるわけじゃありません、ご安心を。

## おわりに

[AWSブログ](https://aws.amazon.com/jp/about-aws/whats-new/2020/04/simplify-iot-device-registration-and-easily-move-devices-between-aws-accounts-with-aws-iot-core-multi-account-registration/)にも書かれている通り、この機能は証明書とプライベートキーが格納されているセキュアエレメントを搭載したデバイスで活用できます。

AWS re:Invent 2020 で発表となったAWS IoT EduKitは[Microchip ATECC608A](https://devices.amazonaws.com/detail/a3G0L00000AAOCcUAP/ATECC608a-CryptoAuthentication-Secure-Element)を搭載しており、本機能を使うことでプライベートキーをネットワークに流すことなくAWS IoT Coreに登録できるようになっています。

ということがわかり、元々AWS IoT EduKitについて書いていたら、この話だけで1エントリーできてしまったのでかき揚げたという次第です。
AWS IoT EduKitについては別途書きます。

### 参考資料

- [RSA鍵、証明書のファイルフォーマットについて / Qiita](https://qiita.com/kunichiko/items/12cbccaadcbf41c72735)
- [AWS IoT 証明書のJust In Time登録 / Qiita](https://qiita.com/TakashiKOYANAGAWA/items/b3b679e2a7d56f144a8e)
- [AWS IoT Deep Dive #1 2020 上半期 AWS IoT アップデート 資料と録画、Q&Aを公開 / AWSブログ](https://aws.amazon.com/jp/blogs/news/aws-iot-deep-dive-1/)
- [register-certificate-without-ca / AWS CLI 2.1.15 Command Reference](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iot/register-certificate-without-ca.html)

EoT