AWS公式資料で挑むSCS認定(13)-Cognito

[前回] [AWS公式資料で挑むSCS認定(12)-AuditManager](https://qiita.com/mingchun_zhao/items/0705c84cca7623f57627)

## はじめに

「道に迷うのは目標を見失ったからだ」、3/19の認定試験、意識しなくちゃ。。。

今回も「Security, Identity & Compliance」に分類されるサービスシリーズです。
Amazon Cognito は、モバイル・Webアプリ向けのユーザ認証を提供してくれるようです。

## 教材を選ぶ

変わらず、AWS Black Belt Online Seminar資料[Amazon Cognito](https://d1.awsstatic.com/webinars/jp/pdf/services/20200630_AWS_BlackBelt_Amazon%20Cognito.pdf)を使用します。

ユーザ認証の全体像から入り、Amazon Cognitoの機能/位置づけを体系的に解説。
ユーザ認証の実装に必要なAPI選定、実装方法まで盛り込まれている、感謝感謝。

## ユーザ認証の選択肢

アプリの特性、対象ユーザ、認証要件などに応じた選択肢。
ユーザ認証の「森」(全体像)を一望できるこの一枚、自分の中では本資料のベストスライドでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/487e25ef-d073-7bba-fac7-9a81e8b242fb.png)

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

## Amazon Cognito とは

API ベースで実装されるモバイルアプリや Web アプリにユーザ認証機能を提供するサービス。
アクセス先がアプリかAWSかにより、

- ユーザプール
    - アプリへのアクセスに利用できるトークンを提供
    - 独自のユーザディレクトリに加え、外部 ID プロバイダでのログインに基づく
- ID プール(フェデレーティッド アイデンティティ)
    - AWS にアクセスできるクレデンシャルを提供
    - Cognito ユーザプールに加え、外部 ID プロバイダでのログインに基づく

## ユーザプール

### ユーザ

ユーザは管理者が作成、またはユーザ自身でサインアップ。
外部IDプロバイダのユーザは初回サインイン時に情報を自動登録。

#### ユーザ属性

- Cognito固有のユーザ情報
    - Username
    - UserStatus
    - PreferredMfaSetting
    - roles
- 標準属性 (OIDC仕様)
    - email
    - phone_number
    - preferred_username
    - name
- カスタム属性
    - 頻繁に参照・変更・検索する情報については DB に保存する方が望ましい
- サインインに使用したデバイス情報(有効時のみ記録)
    - デバイスキー
    - 名前
    - 最後の IP
    - SDK
    - 最後の利用日時

#### ユーザのステータス

- サインアップ時
    - UNCONFIRMED(=サインインはまだ不可)
    - CONFIRMED
    - RESET_REQUIRED
    - FORCE_CHANGE_PASSWORD
    - DISABLED
    - (Deleted)

- 外部IDプロバイダから初回サインイン時
    - EXTERNAL_PROVIDER
    - DISABLED
    - (Deleted)

#### ユーザグループ

- ユーザは複数のグループに入れることが可能
- グループは属性としてアプリケーションから確認できる
- Cognito ID プールとの連携で利用できる IAM ロールやその優先順位の指定に使用できる

## アプリクライアント

### アプリクライアントとは

- アプリケーションは、「API 呼び出し、Hosted UI の利用、OAuth による認可」を行うためにユーザプールにアクセスする
- アプリクライアントは、ユーザプールにアクセスするこれらのアプリケーションを登録し、利用できる機能や権限を設定
- 登録されたアプリケーションは IAM クレデンシャルを利用せずにアクセスできる

### アプリクライアントの識別

アプリクライアントID、シークレットでアプリケーションを識別

### アプリクライアントの種類

- パブリッククライアント
    - シークレットを割り当てないクライアント
    - ブラウザ上の JavaScript などシークレットを保護できない環境の場合
- プライベートクライアント
    - シークレットを割り当てるクライアント
    - サーバなどの環境

## サインインの実装

### 利用できる2種類のAPI 

- Cognito Identity Provider APIを利用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/f2ef84a9-ed7f-b6ac-1503-9d5f742e4b26.png)

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

    - 呼び出し元によって異なる API
        - 管理者としてサーバ側から呼び出す前提の Admin API
            - IAM ロールのクレデンシャルを使用
        - ユーザとしてサーバ側からもクライアン側からも呼び出せる API
            - アプリクライアントID(+ シークレット)を使用 
    - サインインは下記認証フローを指定して API を呼び出す
        - USER_SRP_AUTH
            - SRPプロトコルに基づき、パスワードを基にしたチャレンジレスポンスで認証する
            - サーバ側でも元のパスワードは不明な状態になるなど安全な方法
        - CUSTOM_AUTH
            - 認証時に Lambda ファンクションがトリガーされる
            - ファンクション次第で追加の認証を行って認証などができる
        - USER_PASSWORD_AUTH
            - SRPプロトコルを使用せず、パスワード自体を送って認証する
            - クライアントからは USER_SRP_AUTH の利用を推奨
        - ADMIN_USER_PASSWORD_AUTH
            - USER_PASSWORD_AUTH と似ているがサーバ用 API からのみ呼び出せる
        - REFRESH_TOKEN_AUTH
            - 更新トークンから新しいトークンをもらう。

- Cognito Auth API とHosted UI を利用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/55e54928-f780-a139-4c58-3b89cf2e817a.png)

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

    - Cognito がマネージドサービスの一部として、サインアップ、サインイン、パスワード忘れの対応が行えるWeb UIを提供
        - 多要素認証（MFA）に対応
        - カスタム認証フローのような仕組みはなし
        - ドメイン名、UI のロゴ、CSS のカスタマイズが可能だが、日本語対応は不可
        - 外部 ID プロバイダーを使ったサインインには Auth API が必須
        - OAuth を使ったサードパーティアプリへの認可には Auth API と Hosted UI が必須
    - 認証は OAuth 2.0 で定義されているフローに沿って行う
        - 認証後アプリには認可コードあるいはトークンを URL パラメータなどに付けてリダイレクトされる
            - Authorization Code Grant(認可コード許可)
            - Implicit Grant(暗黙的許可)
                - Authorization Code Grant の方がセキュアで推奨

### 要件に応じたAPI選択

- ユーザプール独自のユーザを利用する場合
    - 外部 IDプロバイダを利用する場合
        - Cognito Identity Provider API &
        - Cognito Auth API
    - 外部 IDプロバイダを利用しない場合
        - Cognito Identity Provider API
- ユーザプール独自のユーザを利用しない場合
    - Cognito Auth API

### サインイン実装には SDK や Library を利用する

API 呼び出しを直接実装する必要はない

## サインイン後の実装

### 発行されるトークン

- 各トークンはJWT形式(OAuth/OIDC同様)
- トークンの署名は以下の公開鍵で検証できる
    - https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json

### トークンの種類と用途

- ID トークン
    - Cognito ID プールにアクセス
    - ユーザの属性が含まれる(カスタム属性含む)
- アクセストークン
    - Identity Provider API にユーザとしてアクセス
    - 一部のユーザ情報に加えスコープなどが含まれる
- 更新トークン
    - IDトークン・アクセストークンを更新
    - サインインの方法によっては更新トークンは発行されない

### トークンをアプリケーションの API アクセスに利用

- トークンを利用してアプリAPIのサーバへアクセス
    - 公開キーでトークンの署名を検証
- API Gateway経由でLambdaへアクセス
    - COGNITO_USER_POOLSオーソライザー
- AWS AppSync経由でDynamoDB, Lambdaへアクセス
    - AMAZON_COGNITO_USER_POOLS認証
- ALB(Application Load Balancer)経由でEC2へアクセス
    - Cognito認証
    - Cognito Auth API & Hosted UI 前提
    - APIベースでは無いWebアプリへのアクセスにCognito のサインインを条件にできる

### トークンをAWSのAPIアクセスに利用

処理の流れ:

1. クライアントからユーザプールへリクエストし、ID トークンが発行される
2. クライアントから 1.の IDトークンを使って Cognito IDプールへリクエストし、AWS一時クレデンシャルが発行できる
    - クレデンシャルが発行される IAM ロールを指定できる
    - クレデンシャルには cognito-identity.amazonaws.com:sub などの変数が設定される
3. AWS一時クレデンシャルを使って、S3などへアクセス

## サインアウト

共用端末でユーザ本人以外が同じクライアントを利用できないように、サインアウトを実装。
どのようにトークンを使っているかによって、行うべき対処が異なる:

- 共通
    - トークンをアプリやSDKでクライアントから破棄
    - アクセストークン・ID トークン自体は最大1時間の有効期限内は利用可能
- Identity Provider API(ユーザとしての呼び出し(更新トークンの利用を含む))
    - グローバルサインアウトで無効化
- Auth API(Hosted UI からの再サインイン)
    - ログアウトエンドポイントで無効化

## サインインに利用できる外部 ID プロバイダ

Auth API を使うと、外部 ID プロバイダでのサインインに基づいて、Cognito ユーザプールにサインインできる。
ユーザ登録や新たなパスワードの記憶などの手間を省くことができる。

- Facebook
- Google
- Login with Amazon
- Sign In with Apple
- SAML (SP-Initiated限定)
- OpenID Connect (OIDC)

※ SAML や OIDC を使うと数多くのIDプロバイダに対応できる

## Cognitoのセキュリティ強化機能

- 電話番号と Email の検証
- 多要素認証（MFA）の利用
    - SMS テキストメッセージ
    - TOTP ソフトウェアトークン
- クライアントデバイスの追跡
- アドバンスドセキュリティの機能
    - 侵害された認証情報が使われていないか確認
    - アダプティブ認証
        - リスクに応じて MFA の利用を求めたり、ブロックしたりする

## Cognitoの監視

- Amazon CloudTrailによるログ記録
    - Cognito API 呼び出しログが記録され、監査やトラブルシューティングに使用
    - APIの記録可否
        - 〇 Cognito Identity Provider API
        - ☓ Cognito Auth API や Hosted UI
        - △ サインインしたユーザの情報やセキュリティ情報は記録されないが
            - Lambdaトリガー内で出力する事で実現できる

- Amazon CloudWatchによるモニタリング
    - CloudWatch メトリックにイベントの発生が記録
    - ユーザによる使用状況やスロットリング(制限超過)の発生を確認できる
    - 一部の API を対象にユーザプール、アプリクライアントごとに以下が記録
        - サインアップの成功/スロットリング
        - サインインの成功/スロットリング
        - トークン更新の成功/スロットリング
        - フェデレーションの成功/スロットリング

## ユーザプールの特徴まとめ

- サーバーレスで認証とユーザ管理
    - サーバについて心配することなく、サインアップ、サインイン機能を実現
- サードパーティとの連携が充実
    - 外部 ID プロバイダを使ったサインイン機能
    - OAuth を使ってサードパーティアプリへの認可も実現
- 強力なセキュリティ機能
    - 電話番号やEmailアドレスの検証や多要素認証を実現
    - アダプティブ認証も実現

## おわりに

Amazon Cognitoが提供する豊富な認証機能から、認証の重要性が窺えます。
次回は、Amazon Detectiveです。お楽しみに。

[次回] [AWS公式資料で挑むSCS認定(14)-Detective](https://qiita.com/mingchun_zhao/items/1d15c7c25c8f405b9ef9)