ラズパイとAWS IoTを使った見守りシステム自作で学んだこと（４）cliでAWS IoTに新しいモノを登録し証明書を発行

[ラズパイとAWS IoTを使った見守りシステム自作で学んだこと（３）ラズパイ物理構成とパッケージ導入](https://qiita.com/nsaito9628/items/528ab7ccd0a62515463b)からの続きです。

今回はラズパイをAWS IoT coreにモノとして登録して、証明書にモノとポリシーを紐づけて、ラズパイとAWS IoTでpub/subが出来るようにします。

簡潔に言うと、モノ（ラズパイ）に名前を付けてAWS IoTに登録する手順を説明します。

## AWS IoT core

AWS IoT coreはmqttsで外部のモノとAWSリソース間でpub/subする際にBroker（中継サーバー）をしてくれるサービスです。  

IoT coreの機能はBrokerに留まりませんが今回はmqtt Brokerとして使います。

AWS IoTを使ったことが無い方はこちらの記事等をご参考ください。

* [AWS IoT Core(公式)](https://aws.amazon.com/jp/iot-core/?nc=sn&loc=2&dn=3)
* [【入門】AWS IoT Coreを理解するために必要な6つのポイント](https://dev.classmethod.jp/articles/aws-iot-core-introduction/)

また、一度マネジメントコンソールから設定するのもお奨めです。公式のハンズオンページは分かり易いです。

* [AWS IoT Core 初級ハンズオン 3.1 AWS IoT Core の設定](https://catalog.us-east-1.prod.workshops.aws/workshops/b3e0b830-79b8-4c1d-8a4c-e10406600035/ja-JP/phase3/step1)

## 証明書によるセキュリティの確保
少し乱暴な説明というか正確さを欠きますがご容赦を。

暗号化通信の下でラズパイとAWSが常に行っているのは
* AWSに接続してきたラズパイが事前に登録した本物か（**クライアント証明書**チェック）
* 登録先だと思って通信してる宛先が間違ってないか（**サーバー証明書**チェック）

の二つの確認です。この確認が出来た時に安全と見なされてデータのpub/subが実行されます。

#### クライアント証明書
AWS IoTが発行します。

接続時にサーバーからラズパイに対して
* クライアント証明書は自分自身に埋め込まれている鍵(公開鍵)の片割れの鍵（秘密鍵）を持っていることを確認
* クライアント証明書自体が怪しいものではありませんと認証局からお墨付き（認証局の署名）をもらっているかrootCA証明書で確認
* 上述の2つが確認できた時に「このクライアントは登録された本物のラズパイ」なことが認められる

という３要素認証的なチェックが入ります。

ラズパイがAWS IoTに接続するとAWS側から「お前ニセモノじゃないよな証拠を出せ」と言われて、この３点が確認できるとヨシ！ということになります。
[参考：X.509 クライアント証明書](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/x509-client-certs.html)

#### サーバー証明書

ラズパイがエンドポイントに接続しに行くと
* user固有のエンドポイントからラズパイに対してサーバー証明書が提示される
* サーバー証明書自体が怪しいものではないことを認証局からお墨付き（認証局の署名）をもらっていることをrootCA証明書で確認する

というチェックをします。

エンドポイントとrootCA証明書の組合せが符合した場合に、宛先間違ってなかったことの証明になります。
[参考：サーバー認証](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/server-authentication.html)

#### AWS IoTとのセキュア通信に必要なもの
今説明したクライアント証明書とサーバー証明書のクロスチェックをする為に、ラズパイ側では以下の情報が必要になります。
* AWS IoTのエンドポイント：AWS IoTの接続先
* クライアント証明書：そもそもAWS IoT登録済みであることの証明
* 秘密鍵：クライアント証明書に埋め込まれた鍵が本物であることの証明
* rootCA証明書：クライアント証明書とサーバー証明書の署名が本物であることの証明

ラズパイへのダウンロードは不要ですがクライアント証明書がラズパイに対して有効化されるためには、AWS内での行動許可書にあたるIoT policyの作成が必須です。

ここまでの証明書の作成と動作の相関図を無理やり図にすると以下のようになるかと思います。

<img width= 1200 src = https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565396/ebaf6628-a5d0-41f8-97fe-ee80616a664c.png>



## モノの登録と証明書の発行

前置きが長くなりましたがラズパイのコマンドラインから登録と証明書の発行をしたいと思います。

ちなみに、こちらの記事にお世話になりました。正規表現については別途書籍含めて必要なことを雑多に確認しています。
* [Creating an AWS IoT Thing from Command Line](https://gist.github.com/noahcoad/d2ac692b487200559a6a0a0b8762a690)
* [AWS IOT を AWS CLI で設定](https://qiita.com/ekzemplaro/items/a95df050833204c266fb)

途中でjsonからARNを抜きたい箇所があるので事前に[jq](https://qiita.com/takeshinoda@github/items/2dec7a72930ec1f658af)のインストールとupdateをかけます。
```sh
sudo apt install jq -y
sudo apt update -y
sudo apt upgrade -y
```

もう一つ事前準備として、[(2)](https://qiita.com/nsaito9628/items/da402829316549853d0f#srccertiot_prov_config)で設定ファイルに出力したモノの名前とAWSアカウントIDを文字列として抜き取ります。
```sh
THING_NAME=$(cat ./iot_prov_config | grep THING_NAME | awk -F'=' '{print $2}')
AccountId=$(cat ./iot_prov_config | grep AWS_AccountId | awk -F'=' '{print $2}')
```

ここからawscliでAWS IoTリソースを作ります。

まずラズパイをモノとして登録します。
```sh
aws iot create-thing --thing-name ${THING_NAME} | tee create-thing.json
```

次にクライアント証明書、公開鍵、秘密鍵を作成してダウンロードします。
```sh
aws iot create-keys-and-certificate --certificate-pem-outfile ${THING_NAME}-certificate.pem.crt --public-key-outfile ${THING_NAME}-public.pem.key --private-key-outfile ${THING_NAME}-private.pem.key --set-as-active | tee create-keys-and-certificate.json
```

証明書のARNを証明書情報の入ったjsonから抜き取り、モノの名前をクライアント証明書に紐づけます。
```sh
CERT_ARN=$(jq -r '.certificateArn' < create-keys-and-certificate.json)
aws iot attach-thing-principal --thing-name ${THING_NAME} --principal ${CERT_ARN}
```  

IoT policyをつくります。
~~このポリシーはany状態でガバガバですので実運用では問題があります。
きちんとリソースで縛る手順を組み込みたいと思います。~~
**【2022.10.25修正】**  
Region、AWSアカウント、topicで明示されたResource名で縛られたpolicyに修正しました。[必要な項目にたどり着くまでの紆余曲折]()は別途記録に残します。
```sh
policy_stm="\"Statement\": [
      {
        \"Effect\": \"Allow\",
        \"Action\": \"iot:Connect\",
        \"Resource\": \"arn:aws:iot:ap-northeast-1:${AccountId}:client/\${iot:Connection.Thing.ThingName}\",
        \"Condition\": {
          \"Bool\": { \"iot:Connection.Thing.IsAttached\": \"true\" }
        }
      },
      {
        \"Effect\": \"Allow\",
        \"Action\": \"iot:Publish\",
        \"Resource\": \"arn:aws:iot:ap-northeast-1:${AccountId}:topic/\${iot:Connection.Thing.ThingName}/*\"
      },
      {
        \"Effect\": \"Allow\",
        \"Action\": \"iot:Subscribe\",
        \"Resource\": \"arn:aws:iot:ap-northeast-1:${AccountId}:topicfilter/\${iot:Connection.Thing.ThingName}/count\"
      }
    ]"

aws iot create-policy --policy-name "${THING_NAME}_subscribe" --policy-document "{\"Version\": \"2012-10-17\",${policy_stm}}"
```

IoT policyをクライアント証明書に紐づけます。
```sh
aws iot attach-policy --policy-name ${THING_NAME}_subscribe --target ${CERT_ARN}
```  

Amazonの自社認証局(Amazon Trust Services)からrootCA証明書をダウンロードします。
```sh
wget https://www.amazontrust.com/repository/AmazonRootCA1.pem
```
以上でAWS IoTとmqtts通信する為のラズパイ側準備は完了です。

## 次回
[(5) paho.mqttでセンサーデータをラズパイからAWS IoTにPublish](https://qiita.com/nsaito9628/items/db43b1e854a3cc95df1a)に続きます。

## 追記

#### 修正　2022.10.25
IoT policyをRegion、AWSアカウント、topicで明示されたResource名で縛られたpolicyに修正しました。