AWS再入門ブログリレー Amazon Cognito編

『AWS 再入門ブログリレー 2020』の 16 日目の『Amazon Cognito』編です。初学者には分かり辛いと思われる「ユーザープール」と「IDプール」の役割、それらをどのように組み合わせて利用できるのかについて、概要を説明したいと思います。
2020.08.26

みなさん、こんにちは!
AWS事業本部の青柳@福岡オフィスです。

当エントリは弊社コンサルティング部による『AWS 再入門ブログリレー 2020』の 16 日目のエントリです。

このブログリレーの企画は、普段 AWS サービスについて最新のネタ・深い/細かいテーマを主に書き連ねてきたメンバーの手によって、今一度初心に返って、基本的な部分を見つめ直してみよう、解説してみようというコンセプトが含まれています。

AWS をこれから学ぼう!という方にとっては文字通りの入門記事として、またすでに AWS を活用されている方にとっても AWS サービスの再発見や 2020 年のサービスアップデートのキャッチアップの場となればと考えておりますので、ぜひ最後までお付合い頂ければ幸いです。

では、さっそくいってみましょう。16 日目のテーマは『Amazon Cognito』です。

AWSにおける「認証・認可」のサービス

Amazon Cognito は「認証・認可」の機能を提供するAWSのサービスです。

「認証・認可」のサービスと言っても、AWSには他にもいくつか「認証・認可」に関するサービスがあります。
Cognitoについて話を進める前に、まずはそれらのサービスについて確認しましょう。

AWS Identity and Access Management (IAM)
マネジメントコンソール、CLI、SDK、APIを使ってAWSリソースを利用するユーザーやアクセス権限を管理するサービス
AWS Directory Service
マネージドな Microosft Active Directory (および互換ソフトウェアであるSamba) 環境を提供するサービス
AWS Single Sign-On (SSO)
複数AWSアカウント利用時の業務ソフトウェア、業務アプリケーションへのシングルサインオンを実現するサービス
Amazon Cognito
Webアプリケーションやモバイルアプリケーションに認証機能を提供するサービス

これらのうち、Cognitoを除く3つのサービスは「会社内 (組織内) のユーザー認証・ユーザー管理で用いる」ことを主に想定したサービスです。
一方、Cognitoは「不特定多数の一般ユーザーの認証・管理」を行うことができるサービスです。

例えば、IAMで考えてみましょう。

会社内で使うシステムであれば、予め管理者が従業員に対応したユーザーを作成しておくのが普通です。
一方、Webアプリケーションやモバイルアプリケーションでは利用者が自分で「ユーザー登録」を行えるのが一般的でしょう。
ところが、IAMでは「まだユーザーになっていない人」つまりアクセス権限を何も持っていない人がIAM上にユーザーを作成することはできません。

また、IAMには「ユーザーの上限数が5000」という制約があります。
Webアプリケーションやモバイルアプリケーションでは数万人、数十万人といった利用者がいるものも珍しくありませんが、このような規模のユーザー管理をIAMユーザーで実現することは不可能です。

Cognitoでは、利用者が自分でユーザーを登録できるのはもちろん、管理者が事前登録したり、CSVファイルからのインポートやLambdaを使ったユーザー移行などにも対応しています。
また、作成できるユーザーの上限数についてもデフォルトで「20,000,000」(二千万) と、不特定多数の一般ユーザーを管理するのに十分なものとなっています。

Cognitoは、Webにおける認証プロトコルの標準である「Open ID Connect (OIDC)」との接続・連係に対応した認証・認可のサービスであり、Webアプリケーションやモバイルアプリケーションで利用するのに最も適したサービスと言えます。

2020/08/26更新
記事初出時に「Cognitoは(略)『Open ID Connect (OIDC)』に準拠した認証・認可のサービス」との記述がありましたが、「OIDCの仕様の一部に沿っているが、準拠している訳ではない」との指摘を頂きました。訂正させて頂きます。

Q. Auth API は、OpenID Connect 1.0 と OAuth 2.0 に準拠しているという認識で合っていますでしょうか?
A. 準拠ではありませんが、これらの標準仕様の一部を沿った形でサービス提供しています。

[AWS Black Belt Online Seminar] Amazon Cognito 資料及び QA 公開 | Amazon Web Services ブログ

Cognitoのコンポーネント

Cognitoは、大きく以下の2つのコンポーネントから構成されています。

  • ユーザープール
  • IDプール

それぞれの機能について説明します。

ユーザープール

ユーザープールは ユーザー認証ユーザー管理 を行うコンポーネントです。

ユーザー認証の方式として、以下の2通りが用意されています。

  • (1) Cognitoユーザープールが提供する認証機能
  • (2) 外部IDプロバイダーと連係した認証

「(1) Cognitoユーザープールが提供する認証機能」では、ユーザー名 (設定によってメールアドレスや電話番号も使用可能) とパスワードを入力してログイン認証を行います。

ユーザーは、管理者が事前に作成しておくことも、ユーザー自身が「サインアップ」を行い登録することもできます。
サインアップによってユーザー登録を行う場合は、メールアドレスまたは電話番号を使った本人確認 (Confirm) が行われます。

「(2) 外部IDプロバイダーと連係した認証」では、Webアプリケーションやモバイルアプリケーションでユーザー名やパスワードの入力を求めるのではなく、外部のIDプロバイダーが提供するログイン画面を利用します。

連係可能な外部IDプロバイダーとしては「Facebook」「Google」「Amazon *1」「Apple」が提供する認証サービスが対応しています。 (これらは「ソーシャルIDプロバイダー」とも呼ばれます)
これら以外にも、認証プロトコルの標準である「SAML」や「OIDC (Open ID Connector)」に対応した認証サービスとの連係が可能です。

外部IDプロバイダーと連係した認証では、ユーザープールに対する明示的なユーザー登録は行わず、初めて認証が行われた時にユーザーが登録されます。

ユーザー名/パスワードで認証されたユーザー、外部IDプロバイダーと連係して認証されたユーザーは、共にユーザープール内で「ユーザー」として登録され、同列に扱われます。

(1行目が外部IDプロバイダーと連係して認証されたユーザー、2行目がユーザー名/パスワードでサインアップを行ったユーザー)

ユーザープールでユーザー認証が行われると、認証された証として「IDトークン」が発行されます。

このIDトークンを使って、アプリケーションがユーザーを特定したり、他のサービスとの連係を行ったりすることができます。

(IDトークンの利用方法については後で詳しく説明します)

IDプール

IDプールは、外部の「IDプロバイダー」によって認証されたIDに対して、AWSへのアクセス権限を持つ「一時クレデンシャル」を払い出すことができるコンポーネントです。

AWSへのアクセス権限を提供することから ユーザー認可 を行うコンポーネントと説明されることもあります。

IDプールが認証のために利用できるIDプロバイダーは、以下の通りです。

  • Cognitoユーザープール
  • Amazon
  • Facebook
  • Google
  • Twitter
  • OIDCに準拠したプロバイダー
  • SAMLに準拠したプロバイダー

IDプロバイダーとして「Cognitoユーザープール」が利用できるというのが、ちょっと不思議かもしれません。
(ユーザープールとの連係については、後ほど詳しく解説します)

また、ユーザープールの説明で登場したIDプロバイダーと一部差異があるのもポイントです。
(ユーザープールでは「Apple」がありましたが「Twitter」が無く、IDプールでは逆に「Twitter」があって「Apple」がありません)
これは、ユーザープールの「外部IDプロバイダー連係」とIDプールの「(外部) IDプロバイダー連係」は別々に実装された機能であるということを意味します。

IDプールと「IAMロール」

IDプールでは、認証されたIDに対してAWSの一時クレデンシャルを払い出すために「IAMロール」の定義を行います。

デフォルトでは「認証されたユーザーへアクセス権限を与えるためのIAMロール」が1つだけ用意されます。
このIAMロールに対してAWSリソースへのアクセス許可のポリシーを設定することにより、認証されたIDがAWSの一時クレデンシャルを使ってAWSリソースへアクセスすることができるようになります。

必要に応じて、割り当てるIAMロールを複数用意しておき、認証時の条件や属性値に応じてどのIAMロールに割り当てるのかを振り分けることもできます。
例えば「IDプロバイダーから取得したトークンに含まれる属性値『役職』に応じてIAMロールを振り分ける」といった具合です。

また、面白い概念として「認証されていないユーザーへアクセス権限を与えるためのIAMロール」を定義することもできます。
これは、「ユーザーがアプリケーションにアクセスしてログインを行う前の状態」や「ゲストユーザー」に対して一定のアクセス権限を与えるために用いられます。
「認証されていないユーザーへアクセス権限を与えるためのIAMロール」はオプショナルであるため、定義しないことによって「ログイン認証を行っていないユーザーには一切アクセスを許可しない」ということも可能です。

<IAMロール定義の例>

IAMロールアクセスポリシー
AuthRole
(認証されたユーザー)
DynamoDB:更新のみ可能
S3バケット:読み書き可能
AuthRole_Manager
(認証されたユーザー&管理職)
DynamoDB:フルアクセス
S3バケット:フルアクセス
UnauthRole
(認証されていないユーザー)
DynamoDB:読み取り専用
S3バケット:(アクセス権限なし)

その他のCognitoコンポーネント

Cognitoには前述の「ユーザープール」「IDプール」の他に「Cognito Sync」というコンポーネントも存在します。

Cognito Syncは、Cognitoを使ってログインしたユーザーのプロファイルデータやアプリケーションデータを複数のデバイス間で共有することができる機能を提供します。

現在は、同じ機能を提供する AWS AppSync サービスの利用が推奨されているため、Cognito Syncについての解説は割愛します。

Cognitoの利用シナリオ

Cognitoの2大コンポーネント「ユーザープール」「IDプール」の概要を説明しましたが、いまいちピンと来ないところがあるかもしれません。

特に、ユーザープールとIDプールの両方に「外部IDプロバイダー連係」の機能があるという点は、どのような違いがあるのか? どちらを使えばよいのか? という点が気になるのではないでしょうか。

そこで、WebアプリケーションやモバイルアプリケーションでCognitoを利用する際のいくつかのシナリオを見てみることで、ユーザープール・IDプールがどのように使われているのかを追ってみたいと思います。

※ シナリオのパターンは下記のAWSドキュメントを参考に、追加や整理をして構成しました。
一般的な Amazon Cognito シナリオ - Amazon Cognito

シナリオ 1: ユーザープールのみを利用するパターン

1-(1) アプリケーション利用開始の認証

ユーザープールのみを利用する場合、以下の図のようなイメージとなります。

Webアプリケーションやモバイルアプリケーションの利用開始時に、ユーザープールを使ったログイン認証を行います。(①②)
(ユーザー名/パスワードを使った認証、または、外部IDプロバイダーとの連係による認証)

認証が行われると、認証した証としてユーザープールから「IDトークン」が払い出されます。(③)

IDトークンには以下のような要素が含まれています。

  • ユーザーを特定する一意な識別子 (OIDCで規定されている「subject」(sub) と呼ばれるID)
  • トークンの発行者 (IDプロバイダーのURL)
  • トークンの有効期限
  • トークンの改竄を検出するための署名

Webアプリケーション/モバイルアプリケーションのクライアントまたはサーバーは、これらの情報を検証することでトークンの正当性を確認します。(④⑤)
そして、IDトークンから取り出したユーザー識別子に基いて、ユーザーに対して適切な振る舞いを行います。(⑥)

1-(2) 特定のAWSリソースへのアクセスのための認証

一部のAWSリソースには、Cognitoユーザープールと連係して認証を行うことができるものがあります。

  • Application Load Balancer (ALB)
  • API Gateway
  • AppSync

それぞれ、AWSリソース側の設定で「Cognito認証の利用」「連係するCognitoユーザープール」を指定することで、AWSリソースに認証機能を組み込むことができます。

ALBとAPI Gatewayについて、Cognitoユーザープールを使った認証機能の利用方法を説明したブログエントリがありますので、参考にしてみてください。

シナリオ 2: IDプールのみを利用するパターン

2-(1) 外部IDプロバイダーを使った認証と認可

AWSリソースを利用するWebアプリケーションやモバイルアプリケーションのログイン認証を、FacebookやGoogleなどのソーシャルIDプロバイダーを使って行うパターンです。

最初にIDプロバイダーを使って認証を行い、IDトークンを取得します。(①②③)

取得したIDトークンはIDプールによって検証され、正当性が確認されると、定義されたIAMロールに割り当てられたAWS一時クレデンシャルが発行されます。(④⑤⑥)

Webアプリケーション/モバイルアプリケーションは、一時クレデンシャルを使うことによって、アクセスが許可されているAWSリソースに対してアクセスすることができます。(⑦)

2-(2) 認証を行わない「匿名」を前提としたAWSリソースへのアクセスの提供

IDプールの解説で出てきた「認証されていないユーザーへアクセス権限を与えるためのIAMロール」のみ を利用するパターンです。

例えば、Webサイトの利用者からAWSリソースへアクセスさせたいが「認証を行わせたくない」「認証を行うまでもない」という場合に用いることができます。

下記のブログエントリでは、静的WebサイトにJavaScriptベースで作成した「お問い合わせフォーム」からの入力データをS3バケットに保存する仕組みを構築しています。

CognitoのIDプールを作成していますがIDプロバイダー連係に関する設定は一切行っておらず、Webサイトにはログイン画面へのリンクもありません。

Webサイトにアクセスした時点でIDプールによって「認証されていないユーザーへアクセス権限を与えるためのIAMロール」に割り当てられたAWS一時クレデンシャルが払い出されて、S3バケットへのアクセス権限が与えられます。

シナリオ 3: ユーザープールとIDプールを組み合わせて利用するパターン

ユーザープールとIDプールをそれぞれ作成して、IDプールのIDプロバイダーとしてユーザープールを指定します。
なお、ユーザープールの認証方式は「Cognitoユーザープールが提供する認証機能 (ユーザー名/パスワードによる認証)」「外部IDプロバイダーと連係した認証」のいずれでも構いませんし、両方を有効にすることもできます。

まず、ユーザープールを使ってユーザーの認証を行います。(①②)
認証が行われた証としてIDトークンが払い出されます。(③)

このIDトークンをIDプールに渡して、IDトークンの正当性が確認されると、定義されたIAMロールに割り当てられたAWS一時クレデンシャルが発行されます。(④⑤⑥)

Webアプリケーション/モバイルアプリケーションは、一時クレデンシャルを使うことによって、アクセスが許可されているAWSリソースに対してアクセスすることができます。(⑦)

シナリオの選定

上に挙げたシナリオの中で、「2-(1) 外部IDプロバイダーを使った認証と認可」と、「3 ユーザープールとIDプールを組み合わせて利用するパターン」の外部IDプロバイダーを使うパターンは、いずれも「外部IDプロバイダーを使って認証を行う」「認証したユーザーに対してAWSリソースへのアクセス権限を与える」という点で共通しています。

さて、どちらのパターンを用いるのが良いのでしょうか?

個人的な見解ですが、そのような要件の場合には「3 ユーザープールとIDプールを組み合わせて利用するパターン」を用いる方が良いのではないかと思います。

その理由について、いくつか挙げてみます。

歴史的経緯

Cognitoの歴史を紐解くと、Cognitoサービスの初期リリース時 (2014年7月) には「IDプール」(当時は「フェデレーテッドアイデンティティ」と呼ばれていた) と「Cognito Sync」のみが提供されていました。
リリースから2年後の2016年7月に「ユーザープール」が追加機能として提供され、Cognito自体でユーザー名/パスワードによる認証を行うことができるようになりました。
そして、更に1年後の2017年8月に、ユーザープールに「外部IDプロバイダーと連係した認証」の機能が追加されたという経緯があります。

これは想像ですが、認証 (Cognito自体あるいは外部IDプロバイダーとの連係による) の機能をユーザープールに集約することもできたと思いますが、互換性のためにIDプールにも外部IDプロバイダーとの連係機能を残しているのではないかと思うのです。

ユーザープールを利用すると「ユーザー管理」が行える

ユーザープールには、ユーザーを「ユーザーディレクトリ」に登録して、管理する機能が備わっています。
例えば、「パスワードリセット」「SMSを使った多要素認証 (MFA)」「ユーザーの無効化・再有効化・削除」などです。

また、ユーザーを「グループ」で分類して、異なるIAMロール (=アクセス権限) を割り当てる機能もあります。

これらの機能を利用したい場合は、IDプールの「外部IDプロバイダー認証」ではなくユーザープールの「外部IDプロバイダー認証」を利用することになります。

SDK/ライブラリや「Amplify」サービスとの連係

プログラムからCognitoを利用・制御するためのSDK/ライブラリには「AWS SDK for JavaScript」「Amazon Cognito Identity SDK for JavaScript」「AWS Mobile SDK」などいくつかの種類がありましたが、後者2つは「Amplify Libraries」に移行しつつあるようです。

「Amplify Libraries」にはCognitoを使った認証・認可を行うための「Auth」クラスがありますが、AuthクラスはユーザープールとIDプールを組み合わせて利用することが前提となっています。

また、「Amplify CLI」はメニューベースで設定を選択することでサーバーレスアプリケーションのバックエンドで必要となるAWSリソースを自動的に構築してくれる機能ですが、このAmplify CLIを使ってCognitoのリソースを自動作成する場合も、ユーザープールとIDプールを組み合わせた構成で作成されます。

これらのように、Cognitoを使った開発を行う際の各種サービスやツールが前提とする構成が「ユーザープールとIDプールを組み合わせた構成」となりつつあるため、IDプールのみを利用するパターンでは開発がしづらくなるものと思われます。

おわりに

Cognitoの2大コンポーネントである「ユーザープール」と「IDプール」の持つ機能、および、それらを単体あるいは組み合わせて利用するシナリオを通して「ユーザープール」と「IDプール」をどのように使えばよいのかについて、概要が掴めたでしょうか?

今回はCognitoを使って認証・認可を行う具体的な手順やコードを用意することができませんでしたが、別の機会にご紹介できればと思います。

* * *

以上、『AWS 再入門ブログリレー 2020』の 16 日目のエントリ『Amazon Cognito』編でした。

明日 (8/26) は Toda さんの「Amazon EC2」の予定です。お楽しみに!!

脚注

  1. AWSのことではなく、Amazon.comやAmazon.co.jpのアカウントのことです。