AmazonCognitoのBlackbeltを見たのでメモ

Amazon Cognitoをそこそこ勉強しようと思ったので、とりあえずBlack beltの動画を見たので内容をメモしておく。
あと、それだけだとさすがにつまらないので、Cognitoのコンソール画面をスクショして載せておく。 動画で解説されていた機能をどのように使うのかをコンソール画面からなんとなく理解できると思う。

OAuthに関する知識があるとわかりやすい。用語を聞けばなんとなく何をしてくれるのか、何をCognitoで設定しないといけないのかがわかる。

Amazon Cognitoとは、「API ベースで実装されるモバイルアプリや Web アプリにユーザ認証機能を提供するサービス」である。 ユーザディレクトリ(ユーザ情報を管理するデータベースみたいなもの)によるサインアップ・サインイン機能、外部IDプロバイダ(IdP)でのサインイン(ソーシャルログイン)、それらサインインによって得られるアクセス権を示すトークンの発行をおこなうことができる。

特徴としては、

  1. サーバレスで認証・ユーザ管理
  2. サードパーティとの連携が充実:外部IdPとの連携
  3. 高セキュリティ:電話番号やEメールの検証・多要素認証・アダプティブ認証

概要

Amazon Cognitoの機能は3つある。

  1. ユーザプール:独自のユーザディレクトリまたは外部IdPでのログインにもとづいてCognitoトークン(JWT形式)を発行し、アプリのアクセスを可能とする。
  2. IDプール(フェデレーティッド・アイデンティティ):Cognitoユーザプールまたは外部IdPにもとづいてAWSにアクセスできるクレデンシャルを発行する。企業内のアプリ向け?
  3. Cognito Sync:AWS AppSyncへ移行。新規ではAppSyncを使うこと。アプリケーションに関連するユーザーデータをデバイス間で同期することを可能にする 。

最も使われるであろう、ユーザプールについて解説されていた。

ユーザプール

ユーザプールを使うには、まずユーザプールを作成する。

アプリごとに異なるユーザを作成させるなら、それぞれ作成する。 ユーザプールで管理するものとしては、管理するユーザ属性(Eメールアドレス、姓、名、ロケールなど)、利用する外部IdP、サインイン方法(ユーザ名+パスワード、MFA)の設定、ユーザプールを利用するアプリクライアントの情報など。

アプリクライアントの設定:Cognitoを利用するアプリの設定をおこなう。アプリクライアントIDとシークレットキー、利用できる機能・権限の設定、認証フロー、トークンの設定など。

ユーザは複数のグループに入れることができる。IDプールと連携させると、IAMロールの指定に利用できる。

APIは大きく分けて2種類

  1. Cognito Identity Provider API:アプリでサインインUIを用意し、APIでCognitoを呼び出す
  2. Cognito Auth APIとHosted UI:サインインUIをCognitoが用意、認可コード・トークンをアプリ使う

上記のAPIをどのように使い分けて自分のアプリに組み込むのかについては後述

Cognito Identity Provider API

Cognito Identity Provider APIAPIにはサインイン、サインアップなどのAPIがあるのでユーザの動作に合わせ、アプリが呼び出す。 Cognito Identity Provider APIは呼び出し元のアプリに応じてさらに2種類に分けることができる、とBlack beltの動画内で紹介されていた。

  1. Admin API:Adminという名称がついているAPI名(全てではない)、サーバから呼び出す、IAMロールを使って呼び出す
  2. 非Admin API:クライアント側(Webブラウザ上のJavaScriptなど)から呼び出す、アプリクライアントID(とシークレットキー)を使って呼び出す

サインインでは、後述の5つの認証フローのどれかにしたがっておこなう。

  • USER_SRP_AUTH:SRPプロトコル(チャレンジを発行してパスワードを平文のまま流さない方法)に基づくパスワード認証
  • CUSTOM_AUTH:Lambda関数で自由に定義する
  • USER_PASSWORD_AUTH:シンプルなパスワード認証
  • ADMIN_USER_PASSWORD_AUTH:Admin APIしか呼び出せない
  • REFRESH_TOKEN_AUTH:リフレッシュトークンによる認証

CUSTOM_AUTH(カスタム認証フロー)だと追加のチャレンジ・レスポンス(AWS Cognitoのカスタム認証フローを使って合言葉認証を作る - Qiita)を作れる。 カスタム認証フローでFIDO2のようなパスワードレス認証を実装できるかと思ったが、それはなさそう。

Cognito Auth APIとHosted UI

Cognito側がWeb UIを用意する(Hosted UI)。 ドメイン名、ロゴ、CSSはカスタマイズ可能だが、日本語対応しておらず、全て英語になる。

認証はOAuthフローに沿って、以下の2つが利用可能である。

  • 認可コードフロー:認可コードを発行し、トークンと引き換える。一般的なフロー。
  • インプリシットフロー:認可コードを使わないフロー。セキュリティ上の脆弱性がわかっており、非推奨。OAuthでも次の仕様からはなくなるとも言われている。

どのAPIを使って自分のアプリを実装するのか

日本語対応していないのでHosted UIを使わない、という方針のもとで以下のような考え方が紹介されていた。

  1. 独自のユーザディレクトリ:使う、外部IdP:使う
  2. UIを独自で作成する(Cognitoのユーザプールを利用したサインインのためのID・PW入力欄と外部IdPを利用したサインインのための外部IdPリンクロゴ)
  3. Cognitoのユーザプールを利用したサインインではCognito Identity Provider APIをコール
  4. 外部IdPではCognito Auth APIをコール
  5. 独自のユーザディレクトリ:使う、外部IdP:使わない
  6. UIを独自で作成する(Cognitoのユーザプールを利用したサインインのためのID・PW入力欄のみ)
  7. Cognito Identity Provider APIをコール
  8. 独自のユーザディレクトリ:使わない、外部IdP:使う
  9. UIを独自で作成する(外部IdPを利用したサインインのための外部IdPリンクロゴのみ)
  10. 外部IdPではCognito Auth APIをコール

実装には、SDKやLibrary(AWS Amplify Library:ブラウザ・モバイル向けライブラリ、日本語化も一部進んでいる)を活用する。

トーク

サインインに成功すると、ユーザにはトークンが発行され、これによってアクセス権が与えられる。 トークンはJWT形式になっており、以下の3種類が存在する。

  • IDトークン:ユーザ情報が含まれているトーク
  • アクセストークン:ユーザ情報の更新をおこなうAPI(Identity Provider API)はアクセストークンのみ
  • リフレッシュトークン:上記の2つのトークンと一緒に発行されることがある。上の2つのトークンの有効期限が切れたとき、リフレッシュトークンを利用した認証フローによって再度トークンを取得できる。

概ねIDトークンとアクセストークンは同じAPIを使うことができ、IDトークンのほうがユーザの情報が多い。

トークンの使い所

API GatewayやAppSyncではCognitoと連携し、自動的にトークンの検証をしてくれる。 また、ALBはトークン検証に加えてHosted UIへ誘導できる。よってこれらの背後にあるLambdaやEC2には認証済みとして処理をおこなうことができる。

トークンを使ってAWSAPIへのアクセスも可能である。クレデンシャルが発行され、ユーザの所属するグループに応じたIAMロールを付与できる。

メッセージ

CognitoはEメールやSMSで招待メッセージや確認メッセージをおくるように設定できる。 メッセージの指定(日本語化)やLambdaトリガーを使った動的メッセージに対応している。

その他サービスとの連携

Lambda

イベント発生時にLambdaを呼び出すように設定できる。

Pinpoint

ユーザ利用状況をリアルタイムに報告する。

  • サインアップ
  • サインイン
  • 失敗
  • アクティブユーザ(デイリー、マンスリー)

CloudTrail

Cognito Identity Provider APIだけログが残る。 監査に利用可能(ただしユーザ情報、セキュリティ情報はマスクされている)。

CloudWatch

APIがどの程度使われているか?を確認できる。 スロットリングとは、APIが叩かれすぎてレート制限を超えてしまい、失敗すること。CognitoのAPIにはレート制限(クォータ)が用意されている。

Cognitoのコンソール画面の確認

Cognitoのコンソール画面(ユーザプール作成、IDプール作成)の画面から、動画内で説明していたことを具体的に確認していく。

ユーザプール作成

ステップ1 サインインエクスペリエンスを設定

サインインに使うユーザIDをここで選ばないとならず、後で変更することができない。

ステップ1

ステップ2セキュリティ要件を設定

パスワードポリシー、MFA、パスワードを忘れたユーザの復旧方法について定義する。 「MFAを必須とする」が推奨になっていたのに驚いたが、多要素認証機能を独自開発する必要がないのはCognitoの売りかもしれない。

ステップ2

ステップ3 サインアップエクスペリエンスを設定

サインアップ、ユーザが新規登録するときの動作などを定義する。 ユーザが登録するときに設定しないといけない属性(Eメールアドレス、姓名、誕生日など)を設定する。独自にカスタム属性として使いすることもできる。 ユーザ属性はOAuthなどでも使われているSCIMに従っている模様。

ステップ3

ステップ4 メッセージ配信を設定

CognitoはEメールやSMSで招待メッセージや確認メッセージを送るので、その設定をここで実施する。

ステップ4

開発のためにとりあえずCognitoのデフォルト設定をつかうこともできる。

ステップ4(2)

ステップ5 アプリケーションを統合

以下のような設定をおこなう。

  • Hosted UIを使うか
  • アプリクライアントの設定
    • クライアントIDとシークレットID
    • アプリクライアントに使わせる認証フロー
    • トークンの設定
    • ユーザ属性に対する読み取り、書き込みの権限

ステップ5

IDプール作成

IDプールは非常にシンプルだった。

ステップ1 IDプールを作成する

IDプールが利用する外部IdPを設定する。

ステップ1(Cognito独自ユーザプール)

ステップ1(OIDC)

ステップ2 アクセス権限の設定

サインイン後のIAMロールを設定(もしくは新規作成)する。

ステップ2

料金体系

月間のアクティブユーザの数に応じた従量課金になっている。

ユーザープールを作成する Cognito Identity を使用している場合、月間アクティブユーザー (MAU) のみに基づいてお支払いいただきます。 その暦月に、サインアップ、サインイン、トークンの更新、パスワードの変更、またはユーザーアカウント属性の更新など、当該ユーザーに関わる ID 操作が発生した場合、そのユーザーは MAU としてカウントされます。後続のセッションに関して、またはその暦月に非アクティブなユーザーに関しては課金されません。

参考