はじめに

OSS の IAM (Identity and Access Management) ソフトウェアであるKeycloak を AWS 環境上に構築する機会がありましたので紹介します。
⻑くなったので 3 つの記事に分割し、まずは Keycloak を選定した経緯について取り上げます。

  1. 選定 (これ)
  2. コンテナのビルド
  3. 実装とデプロイ

最終的な実装サンプルはこちらになります。

なぜ Cognito ではないのか

今回 Keycloak のユースケースとして、Web アプリケーションに対する認証認可機能やソーシャルログイン
機能の実装を想定しています。これは Amazon Cognito の守備範囲です。
アプリケーション⾃体は APIGateway や Lambda を駆使したサーバーレスアーキテクチャであるため、検
討の初期段階では Amazon Cognito が俎上に上がりました。

要因 1: 規模

背景として、⼤規模にスケールするアプリケーションを想定する必要があり、最終フェーズではかなり厳し
い性能要件が提⽰されていました。
その中でも特に Cognito ユーザープールにおいて、以下のクォータを超過することが懸念されました。

カテゴリ 対象 API デフォルトクォータ クォータの緩和
UserAuthentication InitiateAuth RespondToAuthCh allenge AdminInitiateAuth AdminRespondTo AuthChallenge 120RPS (RPS: 秒間リクエスト数) 100 万 MAU を追加するごとに 40RPS(MAU: ⽉間アクティブユーザー数)

デフォルトではユーザー認証の制限値は秒間 120 回までとなります。どこまで緩和できるかについては公式ドキュメントに以下の注釈がありました。

リクエスト率の上昇は、MAUが100万から1,000万になったときに検討されます。クォータ増加リクエストは、現在の利⽤率、既存または予想されるMAU、および最適化のベストプラクティスの実装に基づいて評価されます。Amazon Cognitoは、不正使⽤を防⽌し、すべてのお客様のサービスの可⽤性を保護するために、クォータ増加リクエストを拒否する権利を有します。1,000万以上のMAUをお持ちの場合、AWSソリューションアーキテクトと協⼒して、Amazon Cognitoのクォータに最適化された⽅法でソリューションを設計することをお勧めします。AWSアカウントチームまでお問い合わせください。

この内容から以下が読み取れます。

  • ベストプラクティスに基づいて最適な実装を⾏なっている場合、かつ MAU が 1,000 万を超えるような場合は Amazon Cognito の利⽤は推奨されない
  • ベストプラクティスに基づいて最適な実装を⾏なっている場合、かつ MAU が 100 万〜 1,000 万以内である場合は 100 万 MAU ごとに 40RPS ずつ制限緩和できる

また、120RPS というのは最初の 200 万 MAU に対するクォータであることが記載されています。

アプリケーションが500万MAUまで成⻑しているシナリオを例にとって考えてみましょう。UserAuthenticationカテゴリのオペレーションにおける現在の平均利⽤率は60%と⾼く、現在のクォータ120に対して72リクエスト/秒となっています。200万⼈を超える300万⼈のMAUに対して、1秒あたり40リクエストのUserAuthenticationクォータ増加を要求することができ、クォータの最⼤値は
1秒あたり240リクエストになります。

ここまでを整理すると以下表のような計算になり、1,000 万 MAU かつ 440 RPS が限界値になると解釈で
きます (間違っていたらごめんなさい)

MAU RPS 上限
200万 120
300万 160
400万 200
500万 240
600万 280
700万 320
800万 360
900万 400
1,000万 440

今回、アプリの特性としてログインが特定の時間帯に集中することがわかっていたため、フェーズが進んでアプリが⼤規模化した際にこの制限に触れる可能性がありました。これが Cognito を選定しなかった主な要因です。

補⾜ですが、UserAuthentication のうち RespondToAuthChallengeAdminRespondToAuthChallengeは、同カテゴリ制限の 3 倍の別のクォータが適⽤されるようです。
ただし、認証の開始 (InitiateAuth) のクォータは上記の通りなので、懸念点であることに変わりはないという判断になります。

UserAuthenticationカテゴリには、4つのオペレーションが含まれます:AdminInitiateAuth,InitiateAuth, AdminRespondToAuthChallenge, RespondToAuthChallenge。InitiateAuthおよびAdminInitiateAuthオペレーションは、カテゴリクォータごとに測定され、強制されます。マッチング操作である RespondToAuthChallenge と AdminRespondToAuthChallenge には、UserAuthentication カテゴリ制限の 3 倍の別のクォータが適⽤されます。この増加したクォータは、開発者のアプリで設定された複数の認証チャレンジに対応します。このクォータは、⼤半のユースケースをカバーするのに⼗分です。1回につき3回の認証呼び出しの閾値を超えると、超過分はUserAuthenticationカテゴリのクォータにカウントされます。

要因 2: マルチテナント対応

次に課題となったのが、マルテテナントの実現難易度でした。今回のアプリケーションではエンドユーザー(主に B to B を想定) ごとにログイン時のポリシーを選択可能にする必要がありました。これはつまり MFA有無、パスワードポリシーなどの属性をユーザーが選択できるようにしなければならないということです。
これらは Cognito ユーザープールごとの属性であるため、ユーザープールベースのマルチテナンシーを実装する必要があります。
具体的には以下のように、ユーザープールに対する CRUD を実装する必要がありそうです。

機能 処理内容
テナント登録 ユーザーの⼊⼒したパラメータに応じてユーザープールを作成する処理
テナント参照 作成したユーザープールの属性値をテナント情報として画⾯に返す処理
テナント更新 MFA 設定やパスワードポリシーの更新など、ユーザーの⼊⼒に基づいてユーザープールの属性を編集する処理
テナント削除 退会時にユーザープールを削除する処理

公式ドキュメントにこのアプローチが⾼難度であると明記されていること、および検討時にこのような⾼難度なテナント分離を想定していなかったことも Cognito を断念した要因となりました。
前述の通り、ログインが特定の時間帯に集中することがわかっていたため、ユーザープールがテナントごとにある程度分散したとしてもユーザー認証のクォータに達しない保証はありませんでした。

なぜ Keycloak か

Keycloak は OSS であるため導⼊コストがかからず、また以下の条件をすべて満たしていました。

  • マルチテナントが実装できる
  • OIDC サポート
  • OAuth2.0 サポート
  • SAML サポート
  • ソーシャルログインサポート
  • 公式のクライアントライブラリがある
  • ⽐較的新しく開発が継続されている

Auth0 など他の SaaS も検討しましたが、規模的に⾦額感が⾒合わなかったため、今回は⾒送っています。

Pros/Cons

マネージドサービスではなく OSS を導⼊するので、考えなければならない点も変わります。プロコンを以下のように整理しています。

Pros

  • ECS on Fargate でも動作するため OS レベルの運⽤はする必要がない
  • AWS から Keycloak の構築を抽象化した CDK コンストラクトライブラリが公開されている
  • OSS のため、マネージドサービスと⽐較して柔軟性がある
  • インフラの性能さえ維持すればクォータ制限などはない
  • インフラ以外の導⼊コストがかからない

Cons

  • Cognito では ID プールを使えばよかった AWS サービスへの認可を⾃前で実装する必要がある
  • インフラ (Amazon ECS) の運⽤が必要になる
  • インフラのスケーリングや監視が必要になる
  • インフラコストがかかる
  • OSS のバージョンアップに追随する必要がある

Cons の 1 点⽬について補⾜すると、例えばエンドユーザーに対して S3 バケットに格納されたマニュアルなどをダウンロードさせたい場合に S3 への⼀時的なクレデンシャルを渡すようなことを想定しています。

Cognito から移⾏する場合

もちろん、まずは Cognito で実装し、アプリケーションが⼤規模化する最終的なフェーズになったときに
Keycloak に移⾏するというプランもありました。しかし移⾏コストがかなり⾼いことがわかったため断念し、最初から Keycloak で実装する⽅針となりました。

想定される移⾏タスク

  1. Keycloak インフラセットアップ
  2. Keycloak セットアップ
  3. Cognito ID プールで実装された認可設定を Keycloak で実装し直す
  4. ユーザーの移⾏ (パスワードの再設定が必要となる)
  5. アプリケーションの認証認可ロジックを改修
  6. テスト
  7. 切り替え
  8. Amazon Cognito を切り離す

おわりに

なぜ Amazon Cognito ではなく Keycloak の選定に⾄ったか、その経緯について紹介しました。⼤規模で
クラウドネイティブなアプリケーションを想定する場合、Keycloak はファーストチョイスになり得ます。
次回は CDK で Keycloak クラスタを実装する前段として、構築時の留意事項、およびコンテナイメージの
ビルド/デプロイについて紹介します。