yasutomogのブログ

Software Engineerの雑記

AmplifyプロジェクトでCognito送信者のLambdaトリガーを設定してみた

概要

  • Amplifyプロジェクトで普通にAuthを追加してMFA対応していた
  • SMS認証コードとEMail認証コードはそれぞれCognito標準機能を使っていたが、TwilioやSendGridなどの別サービスで送るための対応が必要になった
  • Cognitoから認証コードを送るときに、カスタム送信できるような機構が用意されているので、それを利用

ドキュメントや参考になるブログ

docs.aws.amazon.com

docs.aws.amazon.com

docs.aws.amazon.com

qiita.com

対応方法

  • AmplifyのCloud Formationに組み込みたかったが、現状、この機能はCloud Formationに対応されていないらしく、別途設定が必要になる
  • KMS(AWSコンソール)から、「カスタマー管理型のキー」を作成する
    • 特に考えずそのまま作成する
  • Lambda Layerを作っておく
    • package.jsonに以下を追加しておく。実際の認証コード送信に必要であれば、「@sendgrid/mail」や「twilio」も追加しておく
  • Lambdaを用意する
    • 公式ドキュメントにあるものを流用すれば良い
    • handler関数では、Cognitoから発火されたイベント名をみて、処理をハンドリングしてあげる(TwilioやSendGridを使って認証コード送信を書く)
  • LambdaにKMSの権限をアタッチしてあげる
    • Lambdaの[設定]→[アクセス権限]→[実行ロール]からKMSの権限をアタッチする
  • Amazon Cognitoサービスプリンシパルに、Lambda関数を呼び出すための、cognito idp.amazonaws.com へのアクセス権を付与

    aws lambda add-permission \
    --function-name <作成したLambdaのARN> \
    --statement-id "CognitoLambdaInvokeAccess" \
    --action lambda:InvokeFunction \
    --principal cognito-idp.amazonaws.com
    
  • Cognitoユーザープールを更新して、Lambdaトリガーを追加する

    aws cognito-idp update-user-pool \
    --user-pool-id <CognitoユーザープールID>  \
    --lambda-config "CustomSMSSender={LambdaVersion=V1_0,LambdaArn=<作成したLambdaのARN>},CustomEmailSender={LambdaVersion=V1_0,LambdaArn=<作成したLambdaのARN>},KMSKeyID=<作成したKMSのARN>" \
    --profile <AWSのプロファイル>
    
  • 間違ってLambdaトリガーを追加したときに解除するコマンド

    aws cognito-idp update-user-pool \
    --userpool-id <userpool_id> \
    --lambda-config "{}"
    

ハマったところ

たまに認証コードが同じユーザーに2度送られる事象が発生

  • SMS認証コードをTwilioのVerify APIを使って送信していたが、時たま、2度送られていた
  • 設定したLambdaトリガーのログを見ていると、以下が出力されており、失敗したLambdaの約1分後に同じイベントが発火されていた。
  • Verify API処理が3秒超える場合がたまにあり、そのときに再度Lambdaが実行され2度送信されていることを確認

    Task timed out after 3.00 seconds
    

対応方法

  • Lambdaのタイムアウトをデフォルトの3秒から10秒に変更し、メモリも256mbに変更
  • 設定値は、利用するサービス仕様に合わせる

www.twilio.com

カスタムLambdaトリガーが実行されない事象発生

  • aws cognito-idp update-user-pool コマンドでLambdaカスタムトリガーを紐付けても、Lambdaが呼ばれない
  • AmplifyでAuth追加した時点では、Cognitoの「どの属性を確認しますか?」の項目では、「Eメールまたは電話番号」を選択していたが、コマンド実行すると、「検証なし」に変更されていた。

対応方法

  • aws cognito-idp update-user-pool コマンドのオプションに auto-verified-attributes を追加
  • 上記オプションには、 sms-configuration が必要になる
    • sms-configuration に指定には、「SMS 送信に使用する IAM ロールの ARN」と「SMS 送信に使用する IAM ロールの、信頼ポリシーに設定されている sts:ExternalId の値」が必要になる。
    • このIAMロールは、Amplifyで適切にAuth追加していると既に作成されているので、それを使う。
    • Cognito(AWSコンソール)の「MFAそして確認」メニューの一番下に「新規ロール名」があるので、IAM(AWSコンソール)から検索して、信頼関係のタブを開くと「sts:ExternalId」の値が確認可能
    aws cognito-idp update-user-pool \
    --user-pool-id <CognitoユーザープールID> \
    --lambda-config "CustomSMSSender={LambdaVersion=V1_0,LambdaArn=<作成したLambdaのARN>},CustomEmailSender={LambdaVersion=V1_0,LambdaArn=<作成したLambdaのARN>},KMSKeyID=<作成したKMSのARN>" \
    --profile <AWSのプロファイル> \
    --auto-verified-attributes {email,phone_number} \
    --sms-configuration SnsCallerArn=<SMS 送信に使用する IAM ロールの ARN>,ExternalId=<SMS 送信に使用する IAM ロールの、信頼ポリシーに設定されている sts:ExternalId の値>