🚀 Cognito User Migration Lambda 関数の実装ガイド
Amazon Cognito を使っていると、「既存のユーザーを新しいユーザープールにどうやって移行するのか?」という課題に直面することがあります。この記事では、初回ログイン時に旧ユーザープールから新ユーザープールへシームレスに移行する Lambda 関数の構築方法について、詳細に解説します。
🧠 背景と目的
- Cognitoのユーザープールを再構成する必要がある
- 既存ユーザーのパスワードを保持したまま移行したい
- 移行のUXを損なわず、自動化したい
これを実現するのが、Cognito User Migration Trigger に対応する Lambda 関数です。
🛠 機能概要
この Lambda 関数では、次のような処理を行います。
- ✅ 旧ユーザープールで認証を実行
- 🔄 ユーザー属性(メールやカスタム属性など)を新ユーザープールに移行
- 🔒 ユーザーを「確認済み(CONFIRMED)」として登録し、確認メールは送信しない
🌍 環境変数の設定
変数名 | 説明 |
---|---|
OLD_USER_POOL_ID |
移行元の旧ユーザープールID |
OLD_CLIENT_ID |
移行元ユーザープールのクライアントID |
🔐 必要なIAMポリシー
Lambda にアタッチする IAM ポリシー例は以下の通りです:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:{REGION}:{ACCOUNT_ID}:*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:{REGION}:{ACCOUNT_ID}:log-group:/aws/lambda/CognitoUserMigration:*"
]
},
{
"Effect": "Allow",
"Action": [
"cognito-idp:AdminInitiateAuth",
"cognito-idp:AdminGetUser"
],
"Resource": "arn:aws:cognito-idp:{REGION}:{ACCOUNT_ID}:userpool/{OLD_USER_POOL_ID}"
}
]
}
※ {REGION}
, {ACCOUNT_ID}
, {OLD_USER_POOL_ID}
は自身の環境に応じて置き換えてください。
⚙ トリガー設定
Cognito ユーザープールのトリガーで以下を設定:
-
UserMigration_Authentication
:ユーザー認証時に発火 -
UserMigration_ForgotPassword
:パスワードリセット時(※未サポート)
🔁 認証フローの流れ
- クライアントが
USER_PASSWORD_AUTH
でログインを試行 - 新ユーザープールにユーザーが存在しない
-
UserMigration_Authentication
トリガーで Lambda が起動 - Lambda で旧ユーザープールに対し認証実行
- 認証成功なら、新ユーザープールに属性を登録し
CONFIRMED
状態に - 認証失敗なら、そのまま失敗を返す
🧪 実装例(Python)
import boto3
import os
client = boto3.client("cognito-idp")
def lambda_handler(event, context):
username = event["userName"]
password = event["request"]["password"]
try:
auth_result = client.admin_initiate_auth(
UserPoolId=os.environ["OLD_USER_POOL_ID"],
ClientId=os.environ["OLD_CLIENT_ID"],
AuthFlow="ADMIN_NO_SRP_AUTH",
AuthParameters={
"USERNAME": username,
"PASSWORD": password
}
)
# 認証成功 → 属性取得
user = client.admin_get_user(
UserPoolId=os.environ["OLD_USER_POOL_ID"],
Username=username
)
attributes = {attr["Name"]: attr["Value"] for attr in user["UserAttributes"]}
# 属性の移行(必要なものだけ抽出も可)
event["response"]["userAttributes"] = {
"email": attributes.get("email", ""),
"email_verified": "true",
# "custom:your_attr": attributes.get("custom:your_attr", "")
}
event["response"]["finalUserStatus"] = "CONFIRMED"
event["response"]["messageAction"] = "SUPPRESS"
event["response"]["forceAliasCreation"] = False
except client.exceptions.NotAuthorizedException:
raise Exception("認証失敗:パスワードが正しくありません")
except client.exceptions.UserNotFoundException:
raise Exception("認証失敗:旧ユーザープールにユーザーが存在しません")
return event
🧬 移行される属性
-
基本属性:
email
,email_verified
-
カスタム属性:
custom:
プレフィックスを持つすべての属性
✅ 使用方法まとめ
- Lambda に上記コードをデプロイ
- 環境変数を設定
- トリガーに
UserMigration_Authentication
を設定 - 新ユーザープールでユーザーがログインを試みると、旧ユーザープールから自動で移行される
🧪 AWS CLIでのテスト
AWS_PROFILE=your-profile aws cognito-idp initiate-auth \
--auth-flow USER_PASSWORD_AUTH \
--client-id {NEW_CLIENT_ID} \
--auth-parameters USERNAME=user@example.com,PASSWORD=your-password
🧯 よくあるエラーと対処
エラー | 原因 |
---|---|
NotAuthorizedException |
認証情報が誤っている |
UserNotFoundException |
ユーザーが旧ユーザープールに存在しない |
Lambdaエラー |
IAMポリシー不足、環境変数設定ミスなど |
🔍 注意点・ベストプラクティス
-
パスワードリセットはサポートしていません(2025年6月現在)
-
messageAction: "SUPPRESS"
を指定しないと確認メールが送信されます -
event["response"]["finalUserStatus"] = "CONFIRMED"
を忘れないこと -
移行処理は初回ログイン時のみ実行されます
-
ログイン画面は
USER_PASSWORD_AUTH
を使う必要があります❗重要:ログイン時に「ユーザーネーム+パスワード」をクライアント(フロントエンド)から Cognito に**直接渡す形式(
USER_PASSWORD_AUTH
)**でなければ、User Migration Lambda は発火しません。たとえば以下のような形式が該当します:
aws cognito-idp initiate-auth \ --auth-flow USER_PASSWORD_AUTH \ --client-id YOUR_CLIENT_ID \ --auth-parameters USERNAME=your_user,PASSWORD=your_pass
一方、
SRP
(Secure Remote Password)フローや、ホスト型UI(Hosted UI)経由の認証では、UserMigration_Authentication
はトリガーされません。
📌 まとめ
この Lambda 関数を活用することで、Cognito ユーザーを安全かつシームレスに移行できます。Cognitoの標準機能とAWS SDKの併用により、シンプルかつ堅牢な移行プロセスを実現可能です。