Cognitoの移行トリガーを用いて認証基盤を移行した話
はじめに
AWS Cognito の認証基盤から別の AWS アカウントの Cognito へパスワードリセットなしにユーザー移行を行ったため、事例の共有になります。
移行の背景
当時弊社の AWS 環境は本番アカウントと開発アカウントと別れていましたが、クローズドにて顧客検証を行っていたため主に開発アカウントを利用していました。
利用規模や開発体制の拡大と以下要因が重なったことで当時利用していた AWS アカウントを廃止して新規 AWS アカウントを利用することととなり、AWS Cognito を利用していたためユーザー情報の移行をすることになりました。
- サービス名の変更
- terrafrom の導入
- AWS IAM アイデンティティセンターの導入
システム環境
弊社のサービス環境はサーバーレスで実現しており、フロントは S3 に Nuxt の SPA を格納、バックエンドを AWS Gateway + Lambda で動作しており DB を MongoDB Atlas を利用しています。
新環境の AWS Cognito ユーザープールのユーザー移行について
Cognito にユーザーを移行する方法として2パターン用意されています。
1.CSV ファイルを作成してユーザー情報を一括インポートにて移行させる方法
特徴:パスワードの移行はできないなため、移行後ユーザーにはパスワードリセットを行ってもらう必要があります。
2.新環境のユーザープールで初回認証時する際に Lambda トリガーを起動させて、ユーザー移行と同時にログイン処理を行う方法
特徴:AWS Cognito の仕様に則った Lambda を作成する必要があるが、ユーザーのパスワードは引き継ぎできるためユーザーは意識せずに移行が可能です。
公式ドキュメント:https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/cognito-user-pools-import-users.html
弊社では技術負債解消対応のためにユーザーへ負担をかけたくなかったことと、1.の方法を選んだ場合顧客への案内および問い合せ対応が発生してくるため、
両方の負担軽減のため今回はシステムで解決する判断を行いました。
以降は、2. の方法の説明になります。
ユーザー移行 Lambda トリガーについて
Lambda トリガーは存在しないusernameからリクエストがあった場合起動します。
リクエストのパターンとしては、ユーザーが ID とパスワードを入力してログインを行った場合と、ユーザーがパスワードリセットを行った場合の 2 パターンの操作を行った場合トリガーに設定した Lambda が起動します。
処理フローは以下の流れになります。
ユーザーが ID とパスワードを入力してログインを行った場合
ユーザーがパスワードリセットを行った場合
Lambda トリガー起動時のパラメータでタイプが分かれるため Lambda の中で条件分岐を行い、適切に処理して AWS Cognito の仕様に則った返却を行うことでユーザーの移行が完了する仕組みとなっています。
仮に Lambda トリガーがエラーになった場合(旧 Cognito への認証が失敗した場合など)には、新環境の AWS Cognito にはユーザーの登録は行われません。またユーザーには Lambda が失敗した旨のエラーメッセージは返却されず通常の認証が失敗した際のエラーメッセージが返却されます。
今回は、AWS から AWS への認証基盤移行になりますが、旧環境への認証は独自実装する形になるため他の認証基盤からの移行も可能となる仕組みとなっています。
具体的な Lambda の作成については公式を参照ください。
Lambda トリガーの設定方法
以下手順でユーザーを移行したい新環境の Cognito に Lambda トリガーを設定します。
1.移行するユーザープールを選択
2.ユーザープールのプロパティから Lambda トリガーを追加を選択
3.トリガータイプを「サインアップ」、サインアップの割り当てを「ユーザーを移行トリガー」を選択。
4.Lambda 関数に起動させる Lambda を紐づけて「Lambda トリガーを追加」
移行時の構成
最終的に弊社では以下のように構成を作り、順次移行を進めて行きました。
今回の移行で工夫した点
- AWS Cognito に登録しているユーザー情報とデータベースに登録しているユーザー情報をマッピングするために cognito_sub を利用しているのですが、移行に伴い変わってしまうため API アクセス時にデータベースの情報を書き換える処理を移行期間中のみ追加して対応しました。
- 旧環境にある AWS Cognito にアクセスするため、クロスアカウントアクセス用の認証情報を Lambda 内のコードで取得するように実装しているのですが、これをグローバル関数として用意しておきウォームスタートの場合に再利用するように実装してパフォーマンスを上げるように工夫しました。
ハマったポイント
- 移行の準備中に AWS Cognito のマネジメントコンソールの UI 画面が新しくなるタイミングで、旧マネジメントコンソール画面だと存在した設定が新マネジメントコンソール画面だと確認できないものがあり Terraform に乗せ換える際に設定の反映漏れが発生し挙動が新環境と旧環境で違うことが発生がありました。
- フロントで指定する AWS Cognito の認証フローで推奨とされる
USER_SRP_AUTH
だと Lambda トリガーのパラメータが入ってこないため、USER_PASSWORD_AUTH
にする必要がある旨見逃しており検証中ハマりました。。。。
まとめ
ドキュメントが少なかったので Lambda トリガーの仕様を理解するのに少し時間かかったため、実際に動かして検証してみることで理解できることが多かった印象です。
機能自体についてはLambdaを実装するため移行元を問わない点やカスタム属性の書き込みを同時に行えるため柔軟に対応できることや、ユーザーに意識させないで認証基盤の移行ができることはとてもよかったです。
Discussion