この記事は以下の記事の実装編となっております。
実装したいこと ログインしたタイミングでユーザを移行する
Cognitoへユーザ移行するlambdaの作成手順とコードの実装例を説明します。
なお、AWS公式ではjwtからメールアドレスなどの情報が取れるとのことでしたが今回は移行元Cognitoからadmin_get_userで取得しています。
jwtからメールアドレスなどの情報を取得したい場合は下記をご参照ください。注意点とともにサンプルコードを紹介しております。
図1 今回実現したいこと
STEP1 移行元のCognitoの設定をしよう(クライアントの発行)
アプリクライアントの発行を行います。既に発行済みの場合はそれを使うことができます。
その際、今回のサンプルコードはクライアントシークレットを生成はしない、認証用の管理 API のユーザー名パスワード認証を有効にするとユーザー名パスワードベースの認証を有効にするはチェックを入れていないとエラーになるのでご注意ください。
Cognitoアプリクライアント発行
アプリクライアント発行は
AWSマネジメントコンソールのCognito→ユーザプール→移行元のユーザプール→アプリクライアント
の順でアクセスします。
アプリクライアントの設定内容
設定はクライアントシークレットを生成はしない、認証用の管理 API のユーザー名パスワード認証を有効にするとユーザー名パスワードベースの認証を有効にするでお願いします。クライアントのシークレットは今回のサンプルコードを書き換えれば動作すると思いますが、そのまま使う場合はチェックを外してください。
こちらで発行いただくとアプリクライアントIDが生成されます。
発行されるアプリクライアントIDはサンプルソースに記入する必要があるのでメモしておいてください。
STEP2 移行元のAWS環境でIAMRoleを作成して信頼関係を結ぼう
移行先のlambdaから移行元のCognitoにアクセスする必要があるので移行元のAWSアカウントでIAMロールを作成して移行先のAWSアカウントに信頼関係の設定をします。
IAMRoleの作成
IAMRoleの作成はIAM→ロールから実施します。
信頼関係の設定
信頼関係を結ぶために信頼されたエンティティタイプでAWSアカウントを選択します。AWSのアカウントの項目では別のAWSアカウントを選択して移行先のAWSアカウントIDを記入してください。入力が完了したら次へを押下します。
信頼関係を設定することで別のAWSアカウントからこのロールを利用できるようになります
次に許可ポリシーの設定をします。今回はAWSマネージドポリシーのAmazonCognitoPowerUserを選択します。あとは任意の名前を付けて作成してください。
AmazonCognitoPowerUserはCognitoユーザプールに対する読書き権限が含まれています。セキュリティ要件などで権限を絞りたい場合は自分でポリシーを定義することもできます。
ここで発行されるロールのARNは後程サンプルコードに記載する必要があるのでメモしておいてください。
STEP3 ユーザ移行lambdaを作成しよう
PythonランタイムでLambda関数の作成
マネジメントコンソールでLambda→関数で関数の作成を押下してLambda関数を作成します。
関数名は好きなものを付けてください。ランタイムはPython3.9を選択します。設定出来たら関数を作成します。
Python3系であれば動くと思います。筆者は3.9で動作確認済みです。
サンプルソースコードにCognitoユーザプールID、アプリクライアント、ロールを記入
ここまで出来たらサンプルソースにCognitoのユーザプール、アプリクライアント、ロールを貼り付けます。これらはSTEP1,STEP2で作成したものです。
role_arnに作成したIAMロールのARN、FROM_USER_POOL_IDにCognitoユーザープール、FROM_APP_CLIENT_IDにアプリクライアントを設定してください。7~12行目です。
import boto3
from boto3.session import Session
import json
def lambda_handler(event, context):
region = "ap-northeast-1"
# TODO 作成したリソースの情報で更新してください。
# 移行元 スイッチロールするIAMロールの情報
role_arn = "arn:aws:iam::123456789012:role/XXXXXXXXX"
# 移行元Cognito情報
FROM_USER_POOL_ID = "ap-northeast-1_XXXXXXX"
FROM_APP_CLIENT_ID = "xxxxxxxxxxxxxxxxxxxxxxx"
# ユーザが入力したID/PW取得
username = event['userName']
password = event['request']['password']
# 移行元環境にSWITCHする
sts_cli = boto3.client('sts')
response = sts_cli.assume_role(
RoleArn=role_arn,
RoleSessionName="session"
)
session = Session(
aws_access_key_id=response['Credentials']['AccessKeyId'],
aws_secret_access_key=response['Credentials']['SecretAccessKey'],
aws_session_token=response['Credentials']['SessionToken'],
region_name=region
)
# 移行元のCognitoにアクセスし、ログインする
# 移行元のCognitoにログインできなければここでエラーとなる。(ID/PW間違いなど)
from_client = session.client('cognito-idp')
response = from_client.admin_initiate_auth(
UserPoolId=FROM_USER_POOL_ID,
ClientId=FROM_APP_CLIENT_ID,
AuthFlow="ADMIN_NO_SRP_AUTH",
AuthParameters={
'USERNAME': username,
'PASSWORD': password
}
)
# 旧Cognitoからadmin_get_userで必要なユーザ情報を取り出す
# ここではメールアドレスと電話番号を取り出しています。
response = from_client.admin_get_user(UserPoolId=FROM_USER_POOL_ID, Username=username)
for userattribute in response['UserAttributes']:
if userattribute['Name'] == 'phone_number':
phone_number = userattribute['Value']
if userattribute['Name'] == 'email':
email = userattribute['Value']
# 移行先Cognitoにユーザを作成する。eventに入れてreturnでeventを返却すればユーザが作成される。
# なお、作成したユーザーは即時有効化し、メールアドレスと電話番号も検証済みとする
event['response']['userAttributes'] = {
'username': username,
'email': email,
'email_verified': True,
'phone_number': phone_number,
'phone_number_verified': True
}
event['response']['finalUserStatus'] = 'CONFIRMED'
# ユーザー登録時のメール送信は抑制
event['response']['messageAction'] = 'SUPPRESS'
# 移行元のユーザを削除する場合はコメントアウトを外す
# from_client.admin_delete_user(
# UserPoolId=FROM_USER_POOL_ID,
# Username=username
# )
return event
Cognitoの登録APIを呼び出していないのを不思議に思った方もいるでしょう。
event[‘response’]に設定内容を入れておくだけで移行ができます。Cognitoの登録APIを呼び出さなくても登録は呼び出し元のCognitoがやってくれているようです。
ソースコードを貼り付けてLambda関数をデプロイ
サンプルソースコードの修正が完了したらソースをlambdaに貼り付けます。
元のソースをすべて消してサンプルソースを貼り付けて「Deploy」を押下してlambdaをデプロイしてください。数秒でデプロイされます。
ソースを修正した際はDeployボタンを押すのを忘れないようにしてください。
STEP4 ユーザ移行lambdaの実行ロールにスイッチロールを許可しよう
サンプルソースの中の18行目に移行元環境にSWITCHするという箇所があります。これを実現するにはlambdaの実行ロールにスイッチロールする権限を与える必要があります。
Lambda設定から実行ロールを選択
Lambdaの実行ロールにスイッチロールする権限を割り振っていきます。前の手順でデプロイしたlambdaの画面→設定→アクセス権限の順に開いていきます。
開いたらロール名をクリックしてIAMRoleの設定画面にジャンプします。
ロール名を押下するとIAMのコンソールに移動します。
ポリシー作成
画面が遷移したら許可を追加→ポリシーをアタッチの順に選択していきます。
次にポリシーを作成を押下します。
ポリシーの作成でJSONを押下し、以下のJSONを貼り付けてください。スイッチロールを許可するポリシーになっています。
貼り付けたらあとはデフォルトで適当な名前を付けてポリシーを作成します。
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "*"
}
}
ポリシーの貼り付け画面
作成したポリシーのアタッチ
ポリシーの作成後、ポリシーを xxxxxxx にアタッチの画面に戻り、作成したポリシーをlambda実行ロールに割り当ててください。作成したポリシーを選択してポリシーをアタッチを押下します。
STEP5 移行先Cognitoでトリガを設定しよう
トリガを設定することでCognitoでログインがあったときLambda関数を実行するようにできます。
トリガーの選択
Cognito→ユーザプール→トリガーの順でアクセスします。
ユーザー移行トリガーの選択
多数あるトリガの中から今回はユーザーの移行を選択します。Lambda関数からSTEP3で作成したユーザ移行lambdaを選択してください。
設定は以上です。
動作確認
では実際に動きを見てみましょう。
事前準備:移行元Cognitoにユーザ登録
事前準備として移行元Cognitoにユーザを登録しておきます。コンソールからできますが、アカウントのステータスをCONFIRMEDにしておいてください。作成直後はFORCE_CHANGE_PASSWORDになるかと思うので下記コマンドでCONFIRMEDにしておきます。
aws cognito-idp admin-set-user-password --user-pool-id ap-northeast-1_XXXXXX --username ユーザ名 --password パスワード --permanent
FORCE_CHANGE_PASSWORDままでも正常に動作する可能性がありますが、CONFIRMDになっているケースで利用することが多いと思うのでCONFIRMDで動作確認します。
マネジメントコンソールからはCONFIRMDにできないのでAWSCLIで操作します。
CLIコマンドを実行するとCONFIRMDになります。
Cognitoにサインアップしてみる
移行先Cognitoには移行対象のユーザが存在しないことを確認しておきます。
では事前準備で作成したユーザでサインアップしてみます。
スクリーンショットの例ではmigration_test_userを使っています。
サインアップもコンソールからはできないのでCLIで実行します。
aws cognito-idp admin-initiate-auth --user-pool-id ap-northeast-1_XXXXXXX --client-id クライアントID --auth-flow ADMIN_USER_PASSWORD_AUTH --auth-parameters USERNAME=ユーザ名,PASSWORD=パスワード
対象ユーザが移行される
成功するとCLIでトークンが返却されてきます。そして移行先のCognitoに対象ユーザが登録されます。
サンプルコードでは移行元にユーザが残ります。
移行元のユーザを削除したい場合はサンプルコードのコメントアウトを外していただければ削除されます。
PR
当ブログはWordPressテーマSWELLを使用しています。非常に使いやすく、簡単にプロのようなデザインを使えるのでお勧めです!!
SWELL – シンプル美と機能性両立を両立させた、圧巻のWordPressテーマ
システムエンジニア
AWSを中心としたクラウド案件に携わっています。
IoTシステムのバックエンド開発、Datadogを用いた監視開発など経験があります。
IT資格マニアでいろいろ取得しています。
AWS認定:SAP, DOP, SAA, DVA, SOA, CLF
Azure認定:AZ-104, AZ-300
ITIL Foundation
Oracle Master Bronze (DBA)
Oracle Master Silver (SQL)
Oracle Java Silver SE
■略歴
理系の大学院を卒業
IT企業に就職
AWSのシステム導入のプロジェクトを担当