Amazon ECS で動作する OpenAI Realtime API を使った ChatBot に ユーザー認証を追加する

# 1. はじめに

アプリケーションにおいてユーザー認証は重要な要素ですが、実装の複雑さに頭を悩ませることも多い。AWS が提供する **Amazon Cognito** を活用すれば、ログイン／ログアウト機能や SNS 認証、多要素認証 (MFA) などを簡単に導入できるようになる。さらに、**Application Load Balancer (ALB)** と組み合わせることで、バックエンドのアプリケーションコードを大きく変更することなく認証を追加できる。
前回、 ChatBot を **ALB** を用いて TLS に対応させたが、今回はその **ALB** と **Cognito** を連携させて **ユーザー認証** に対応する

**前回の記事:**

https://qiita.com/rairaii/items/9d6670b8390680fa364d


# 2. Cognito について

[Amazon Cognito](https://us-east-1.console.aws.amazon.com/cognito/)  は、AWS が提供するユーザー認証やユーザー管理を簡単に実装できるサービスだ。ユーザープール (User Pool) を通じてアプリケーションのログイン／ログアウト機能、ユーザーアカウントの作成、SNS 認証、MFA（多要素認証）などを比較的容易に実装できる。さらに無料利用枠が用意されており、[Monthly Active Users (MAU) が　最初の 10,000 までが無料利用枠](https://aws.amazon.com/jp/cognito/pricing/)を利用できる。


Application Load Balancer (ALB) に Cognito を連携させることで、ALB を経由してアプリケーションにアクセスする際にログイン認証を必須化できる。具体的には、ALB のリスナー設定で Cognito の User Pool を OIDC（OpenID Connect）プロバイダとして設定することで、ログイン画面のリダイレクトなどが自動的に行われます。これにより、ALB の背後にあるアプリケーションコードを大きく変更することなく、ユーザーの認証・認可を行う。


# 3. Cognito の設定

[Cognitoのコンソール](https://us-east-1.console.aws.amazon.com/cognito/v2/home?region=us-east-1)で次の設定を行う


## (1) アプリケーションのリソースの設定

1. **[Amazon Cognito]** を選択し、「Amazon Cognito
アプリケーションの安全な ID およびアクセス管理」のページを表示する
1. **[5 分未満で無料で開始できます]** を選択し、[アプリケーションのリソースを設定する] のページに移動する
1. **[アプリケーションを定義]** で次の設定を行う 
    - **[アプリケーションタイプ]** - **[従来のウェブアプリケーション]**
    - **[アプリケーションに名前を付ける]** で任意の名前をつける
1. **[オプションを設定]** で次の設定を行う
    - **[サインイン識別子のオプション]** : **メールアドレス** を選択
1. **[リターン URL を追加]** で次の設定を行う
    - リターンURL を下記の形式で設定する
    - **/oauth2/idpresponse** を忘れずに設定すること
1. **[ユーザーディレクトリを作成する]** を選択


**Cognito のリターンURLの形式：**
```bash
https://<ALBのDNS名>/oauth2/idpresponse
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/abd3a9cc-353c-4349-aa20-12a9923c2152.png)



## (2) ユーザの作成

1. **[ユーザ管理]** - **[ユーザ]** を選択し **ユーザー** ページを表示する
1. **[ユーザーを作成]** を選択し **ユーザーを作成** ページに移動する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/2df2a15b-df1d-4f12-baf6-bc8a5a2d4e3c.png)

## (3) ユーザ情報を埋める

PoCで動作を確認したいだけなので、次のように設定した

| 項目               | 設定・内容                          |
|--------------------|-------------------------------------|
| 招待メッセージ     | 「招待を送信しない」  を選択                  |
| E メールアドレス   | <テスト用の E メールアドレス>        |
| 仮パスワード       | 「パスワードの設定」 を選択                    |
| パスワード         | <テスト用のパスワード>               |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/beafa961-4742-4ece-ad98-c97fa6823295.png)


## (4) セルフサービスのサインアップ無効

ユーザーが自らアカウントに登録できないように設定する

1. **[サインアップ]** - **[セルフサービスのサインアップ]** - **[自己登録]** - **[自己登録を有効化]** のチェックを外す

# 4. ALB に Cognito の認証設定

[ALBのコンソール](https://us-east-1.console.aws.amazon.com/ec2/home?region=us-east-1#LoadBalancers:)で設定を行う。下記のように、**ロードバランサー** の **リスナー** で **Cognito** を利用する設定を行うだけで、ユーザー認証が利用できるようになる。

## (1) ロードバランサーの選択

1. 作成した **ロードバランサー** を選択しロードバランサーの設定に移動する
1. **[HTTPS:443]** のリスナーの編集を行う
1. 編集する **[Protocol:Port]** を選択し **[リスナーの管理]** - **[リスナーの編集]** を選択し **リスナーの編集** のページに移動する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/0425c8cc-3fc2-410b-a1eb-758b1da12d86.png)

## (2) リスナーの編集 

1. **[リスナーの編集]** のページの **[リスナーの詳細]** - **[デフォルトアクション]** - **[認証]** - **[OpenID または Amazon Cognito を使用する]** にチェックマークを入れると設定項目が表示される
1. **[アイデンティティプロバイダー]** に **[Amazon Cognito]** を選択し、**その他の項目**(ユーザプールなど)を選択する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/140fd676-94fa-44c9-a944-0be8aaaf8e2f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/82c0ac35-f382-4725-84cb-f811d83cd8c1.png)


# 5. 認証の動作確認

**Cognite の認証を設定した ALB の DNS名** にブラウザでアクセスするとサインインのページが表示される。さきほど作成したユーザでログイン可能となる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/f7975e06-7cc3-4f39-b3c9-7742efe6064c.png)


# 明示的に再認証させる方法

**Cognito** によるユーザ認証に成功すると、トークンが Cookie に保存され Cookie が有効な間は、ブラウザからのリクエストに対して再度Cognitoに認証を問い合わせることなく、ALB自身が認証済みと判断する。ユーザーにとって便利な挙動だが、このままでは明示的にログアウトする手段が存在しない。

再度、**Cognito** のログイン画面で認証させたい場合は、**2つ** のサイトのCookieを削除する

1. **サインインページ** のサイト
1. **ALBのDNS名** のサイト

**Chrome ブラウザでの Cookie の削除方法**

1.	Chromeの右上にある 「︙（縦の三点）」 アイコンをクリック
2.	[設定] をクリック
3.	左側のメニューから [プライバシーとセキュリティ] を選択
4.	[サイトの設定] をクリック
5.	下にスクロールし、[すべてのサイトデータと権限を表示] をクリック
6.	検索ボックスにCookieを削除したい サイトのドメイン を入力
7.	対象のCookieを確認したら、右側の ゴミ箱アイコン をクリックして削除

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/f1344bc9-2ab0-4797-96d9-6ca5999d43a3.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1017489/ed405556-9edc-4987-9542-a6f716409400.png)


ログアウトする機能を Webアプリ に追加したい場合には下記のサイトのようにすれば良い

https://qiita.com/Bacchus/items/8fd7ddc481c58475ef4f


# 参考文献

https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/patterns/choose-an-amazon-cognito-authentication-flow-for-enterprise-applications.html


https://qiita.com/mkt1234/items/e580628afe167c826adf

https://d1.awsstatic.com/webinars/jp/pdf/services/20200630_AWS_BlackBelt_Amazon%20Cognito.pdf