Azure IoT Hubへのサービス側のアクセスにAzure ADが使えるようになりました

# はじめに
https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-dev-guide-azure-ad-rbac

こちらの内容の理解を補助できるように書きました。
実際にサンプルも動作させてみました。

# 結論
他のサービスと同様にAADを利用したRBACによるアクセス制御ができるようになりましたよ。
デバイス側じゃなくてサービス側ですよ。
というお話です。

# 1. AzureはAADとRBACでセキュアにしましょう
"ネットワークで囲ってあるから安全だ" という考え方はやめましょう。
ネットワークの内側に何らかの方法で入られたら、もうどこから何をされているのかワケがわからなくなります。
そもそも内部犯はやりたい放題です。

Azure上のPaaS系サービスの多くはパブリックネットワーク上でセキュリティを保つ方向で動いています。
方法は簡単に言いますと、ネットワークで縛るのではなく、個で縛る方向になっています。
対象サービスを適切な権限で利用できる仕組みを、以下の２つの動きで実現しています。

- そのサービスの利用を誰に許可するのかを指定しておく
- サービス利用時は、自分が何者であるかを証明する

この２つの動きにより、"誰が何をできるのか？""誰が何をしたのか？"をハッキリさせています。
具体的には、**AAD(Azure Active Directory)**と**RBAC(Role Based Access Control)**で実現します。

AADには、人であったりVirtual MachineやWebAppsのようなリソースであったりを登録します。
サービスを利用したいときは、ここで登録した情報を元に認証処理を実施し、何者であるかを特定します。

RBACには、登録権限や読み取り権限等、"何を許可するのか"を登録します。
サービスを利用したいときは、認証情報に基づいて認可処理が実施され、要求を許可もしくは拒否します。

AADには、上述の通りリソースが登録できます。
例えば"〇〇というWebAppsから△△というSQLDBへの読み取りアクセスを許可する"みたいな時の"〇〇"や"△△"もAADとRBACの組み合わせで制御可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/98d9b63f-37ff-fd92-8beb-cad89d8fad68.png)
※絵がざっくり過ぎますが、とりあえず雰囲気を覚えましょう


# 2. IoT Hub も流行りに乗りました

## 今までのやり方
IoT Hubでは、SASキーを使って制御しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/e2092a05-4318-295b-fec5-785d805790b6.png)
普段どこまで意識しているかはわかりませんが、本来は適切なリソースからのアクセスであることを証明する必要があります。
適切なリソースだけがアクセスできるように設定する場合、今までですとKeyVaultの併用等が必要でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/41d58c3b-dc14-030a-10b5-954d91ea8006.png)
※正しいKeyVaultの動作イメージはこちらを参照ください。
[Azure Key Vault の認証 - 認証を伴う Key Vault 要求操作フロー](https://docs.microsoft.com/ja-jp/azure/key-vault/general/authentication#the-key-vault-request-operation-flow-with-authentication)

## AADを使ったやり方
AADで制御する場合、誰に何を許可するのかを登録することで制御します。
まずはこちら(ID)で、AADの利用を"ON"にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/973616d7-ea0b-0ef5-b561-b31c806ed061.png)
次にこちら(アクセス制御(IAM) )で、許可する相手と範囲を登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/b07b5645-2210-3993-29c3-b11ac81b04a3.png)
細かい話はこのあと実際にやっていきます。

# 3. 実際にやってみた
参考にしたのは冒頭でもリンクしています
[Azure Active Directory を使用して IoT Hub へのアクセスを制御する](https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-dev-guide-azure-ad-rbac)
です。

## 全体図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/2f54c836-1434-2bf0-186d-02d9a8862275.png)
①サンプルプログラムを動かすVMを作成する
②制御するIoT Hubを作成し、デバイスを１つ登録する
③IoT HubのAADの利用を"ON"にする(上述のとおり)
④IoT Hubのアクセス制御に①で作成したVMを登録する
⑤サンプルプログラムを動かす

## 3-① VMの作成
Windows VMを作成しました。
Public IPをさらすのは危険ですよね？なので "Bastionを使おう" と思っていただけた方は、こちらを参照してください。
[クイックスタート: ブラウザーを使用してプライベート IP アドレスで VM に安全に接続する](https://docs.microsoft.com/ja-jp/azure/bastion/quickstart-host-portal)

作成後、VisualStudio2019をインストールしました。
また、あとで利用するので参考ドキュメント最下部にあるリンクを辿り、サンプルプログラムを取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/896c8127-2a27-9c42-3a60-4f00fd406cb5.png)
実際には、こちらのページからダウンロードするなり、Gitを入れてCloneするなりしてください。
https://github.com/Azure-Samples/azure-iot-samples-csharp

## 3-② IoT Hubの作成
省略。デフォルト設定で作成しました。
今回はS1で作成しましたがFreeでも大丈夫だと思います。
IoT Hubができたら、デバイスを１つ登録してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/21878247-ec42-766f-a9c0-6e43f26eae46.png)
デバイスIDだけ入れて、あとはデフォルトで問題ありません。
今回は**"device001"**といういつもの安直な名前にしました。


## 3-③ "ID"タブでAADの利用を"ON"にする
スクリーンショット再掲。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/973616d7-ea0b-0ef5-b561-b31c806ed061.png)
上述のとおり、画面でONにして保存したらできます。

## 3-④ アクセス制御
上述の"ロールの割り当ての追加"を押下すると画面右側に**"どんな権限(役割)"**を**誰(選択したメンバー)**に割り当てるのかを決めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/a42b838d-748a-66b2-92a7-22975704172b.png)
今回は
役割：IoT Hub Data Contributor
割当先：仮想マシン
として①のVMを選択し"保存"ボタンを押下しました。

IDタブでAADを使ったアクセス制御の利用を開始し、アクセス制御タブでAADで認証された誰が何をするのかを制御しています。

あとで利用する"クライアントID"というものを取得しておきます。
"ロールの割り当て"タブをクリックし、登録したVMの名前をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/493eb446-f806-6a0b-c4e9-400a609aba5f.png)
下のような画面が出てきますので、アプリケーションIDを取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/5139f94f-db55-ef98-850f-804176935238.png)


## 3-⑤ サンプル起動
まず、サンプルを開きます。具体的には以下をVisualStudioで開き、RoleBasedAuthenticationSampleを使います。

> azure-iot-samples-csharp\iot-hub\Samples\service\IoTHubServiceSamples.sln

サンプルプログラムは起動時の引数を求めるように作られていますので入れていきたいと思います。
少なくとも、"ホスト名"、"デバイスID"、"クライアントID"、"テナントID"を指定する必要があります。
どんなパラメーターを希望しているのか、RoleBasedAuthenticationSampleのParameters.csファイルを確認ください。

ホスト名：IoT Hubの"概要"タブの基本情報に"ホスト名"があります。"～～～～.azure-devices.net"みたいな文字列です。
デバイスID：先ほど②で作成した"device001"
クライアントID：先ほど④で取得したアプリケーションID
テナントID：利用中のAzureADのテナントID([Azure Active Directory のテナント ID を見つける方法](https://docs.microsoft.com/ja-jp/azure/active-directory/fundamentals/active-directory-how-to-find-tenant))

ソリューションエクスプローラーでRoleBasedAuthenticationSampleを右クリック、プロパティを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/cffe4a1e-f1af-cd22-57d8-6ca44edc6352.png)
"デバッグ"の"アプリケーション引数"に入れていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/d18bbc5e-da45-1f32-037d-c87dd0eb7521.png)

> -h ～～～.azure-devices.net -d device001 --clientId 43000000-0000-0000-0000-000000000000  --tenantId 77777777-7777-7777-7777-777777777777

↑こちらをコピペして、各値を修正いただけたらと思います。

実行がうまくいくと、こちらのようなメッセージが出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/52417999-2266-668d-dc05-7d0964f276ae.png)
IoT Hub側でもメッセージを受け取ったか確認しましょう。
概要タブの下の方で情報を確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/78389325-8de7-8d4e-b48e-7d9afccf4afb.png)

※本気で確認する場合は、対象となるデバイスもご準備ください



うまくいかないときは、こちらのようなメッセージが出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/ffef2043-d9e0-71a2-6f42-17cc138df9e4.png)
認証で失敗している模様です。
たとえば

- アクセス制御で割り当てられている環境外での実行（ローカルPCなど）
- アクセス制御の割り当てを削除した

このような状態を作り出すと認証で失敗します。
これは、正しい動作です。

SASキーを利用した場合と、AAD＆RBACを利用した場合のサンプルコードの差異を確認する場合、さきほどの"RoleBasedAuthenticationSample"と"ServiceClientSample"の差異をご覧ください。
ServiceClient生成時に前者はトークンを収集して利用しており、後者は接続文字列(SASキー)を利用しています。

# まとめ
今回は、IoT Hubへの接続にAADを利用しました。
この機能を使えば、アクセス制御をソースコードから分離できますし、間違って本番に繋いでしまうようなことも起きないのではないでしょうか。
開発者は接続先に注意を払う必要がありませんので、開発に注力できます。

冒頭にリンクしたドキュメントの最初に注意事項が記載されていますのでご確認ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/35e2ffc6-e040-5995-6cf6-0a8c13af8be1.png)

- マイクロソフトはAzure ADの利用をお勧めしています
- この認証はデバイスではサポートされていない(まぁ当たり前と言えば当たり前かもしれませんが)

"デバイスAPI？？"という方はこちらをご確認ください。
[リファレンス - IoT Hub エンドポイント - IoT Hub の組み込みエンドポイントの一覧](https://docs.microsoft.com/ja-jp/azure/iot-hub/iot-hub-devguide-endpoints#list-of-built-in-iot-hub-endpoints)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439826/678a2953-6609-4525-b1c6-f5702481fc4e.png)
簡単に書くと、こちらの図の左がデバイスAPI、右がサービスAPI、今回の対象は右側です。