Cognito IDプールの認証プロバイダーに別リージョン・別アカウントのCognitoユーザープールを設定してみた

Cognito IDプールとCognitoユーザープールの連携、別リージョンや別アカウントでもできるのかな? と、疑問に思ったので試してみました。結論から言えば、別リージョンや別アカウントでも問題なくできそうです。
2021.06.22

Cognito IDプールはCognitoユーザープールを認証プロバイダーとして連携することで、 Cognitoユーザープールでログインしたユーザーに応じてAWSの一時クレデンシャルキーを発行することができるサービスです。

詳しくは以前書いたブログを御覧ください。

このCognito IDプールとCognitoユーザープールの連携、別リージョンや別アカウントでもできるのかな? と、疑問に思ったので試してみました。

結論から言えば、別リージョンや別アカウントでも問題なくできそうです。

Cognitoユーザープールを構築する

Cognitoユーザープールの構築については、以前書いたブログをご参照ください。 このとき構築したオレゴン(us-west-2)リージョンのCognitoユーザープールを流用します。

上記ブログを参考に、Cognitoユーザーのサインアップまでは済ませておいてください。

サインアップができていると、AWS CLIの aws cognito-idp admin-initaite-auth コマンドで、IDトークンが取得できます。

$ USER_POOL_ID=us-west-2_xxxxxxxxx
$ CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxx
$ USER_EMAIL="email@example.com"
$ PASSWORD="Password01@"
$ aws cognito-idp admin-initiate-auth \
  --user-pool-id ${USER_POOL_ID} \
  --client-id ${CLIENT_ID} \
  --auth-flow ADMIN_NO_SRP_AUTH \
  --auth-parameters "USERNAME=${USER_EMAIL},PASSWORD=${PASSWORD}"

上記コマンドを実行すると、こんな形のJSONでアクセストークン・リフレッシュトークン・IDトークンが返ってきます。

{
    "ChallengeParameters": {},
    "AuthenticationResult": {
        "AccessToken": "eyJraW...",
        "ExpiresIn": 3600,
        "TokenType": "Bearer",
        "RefreshToken": "eyJjdH...",
        "IdToken": "eyJraW..."
    }
}

別リージョンにCognito IDプールを構築する

東京(ap-northeast-1)リージョンに変更して、新しいCognito IDプールを作成します。

IDプール名に適当な名前を入力して、認証プロバイダからはCognitoを選んで、 オレゴンリージョンで作ったCognitoユーザープールの ユーザープールIDアプリクライアントID を入力してプールの作成をします。

認証されたユーザーの利用するIAM Roleと、認証されていないユーザーの利用するIAM Roleが新規作成されるので、これを許可します。

作成した Cognito IDプールのID は、あとで使うのでメモしておいてください。 「IDプールの編集」ボタンをクリックすると確認できます。

別リージョンのCognito IDプールとCognitoユーザープールの連携ができたので、 Cognito IDプールで一時クレデンシャルキーが発行できるか試してみます。

Cognito IDプールから一意な Identity ID を取得して、そのIdentity IDをもとにAWSの一時的なクレデンシャルキーを取得します。

これらは、AWS CLIの aws cognito-identity get-id, aws cognito-identity get-credentials-for-identity コマンドで実施できます。

$ REGION=us-west-2
$ USER_POOL_ID=us-west-2_xxxxxxxxx
$ CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxx
$ USER_EMAIL=email@example.com
$ PASSWORD="Password01@"
$ IDENTITY_POOL_ID=ap-northeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$ COGNITO_USER_POOL=cognito-idp.${REGION}.amazonaws.com/${USER_POOL_ID}
$ ID_TOKEN=$(aws cognito-idp admin-initiate-auth \
  --user-pool-id ${USER_POOL_ID} \
  --client-id ${CLIENT_ID} \
  --auth-flow ADMIN_NO_SRP_AUTH \
  --auth-parameters "USERNAME=${USER_EMAIL},PASSWORD=${PASSWORD}" \
  --query "AuthenticationResult.IdToken" \
  --output text) && echo ${ID_TOKEN}
$ IDENTITY_ID=$(aws cognito-identity get-id \
  --identity-pool-id ${IDENTITY_POOL_ID} \
  --logins "${COGNITO_USER_POOL}=${ID_TOKEN}" \
  --query "IdentityId" \
  --region ap-northeast-1 \
  --output text) && echo ${IDENTITY_ID}
$ OUTPUT=$(aws cognito-identity get-credentials-for-identity \
  --identity-id ${IDENTITY_ID} \
  --logins "${COGNITO_USER_POOL}=${ID_TOKEN}" \
  --region ap-northeast-1) && echo ${OUTPUT}

このコマンドを実行してAWSの一時的なクレデンシャルキーを取得すると、こんな形で結果が返ってきます。

結果はJSON形式ですので、 jq コマンドを使ってターミナルで使える形に変えてやります。

$ AWS_ACCESS_KEY_ID=$(echo ${OUTPUT} | jq .Credentials.AccessKeyId)
$ AWS_SECRET_ACCESS_KEY=$(echo ${OUTPUT} | jq .Credentials.SecretKey)
$ AWS_SESSION_TOKEN=$(echo ${OUTPUT} | jq .Credentials.SessionToken)
$ echo "export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID"
$ echo "export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY"
$ echo "export AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN"

このコマンドを実行して結果部分をコピー&ペーストすれば、Cognito IDプールが発行した一時クレデンシャルキーを利用できます。

実際にまた別のシェルでこの一時クレデンシャルキーを使用して、 aws sts get-caller-identity コマンドを実行してみます。 そうすると、この一時クレデンシャルキーがCognito IDプールで設定したIAM RoleからAssumeRoleされた権限であることがわかり、 Cognitoユーザープールが別リージョンでも問題なく機能していることがわかります。

$ aws sts get-caller-identity
{
    "UserId": "XXXXXXXXXXXXXXXXXXXXX:CognitoIdentityCredentials",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/Cognito_user_identity_another_regionAuth_Role/CognitoIdentityCredentials"
}

別アカウントにCognito IDプールを構築する

今度は別のAWSアカウントに変更して、新しいCognito IDプールを作成します。

IDプール名に適当な名前を入力して、認証プロバイダからはCognitoを選んで、 別のAWSアカウントで作っておいたCognitoユーザープールの ユーザープールIDアプリクライアントID を入力してプールの作成をします。

認証されたユーザーの利用するIAM Roleと、認証されていないユーザーの利用するIAM Roleが新規作成されるので、これを許可します。

作成した Cognito IDプールのID は、あとで使うのでメモしておいてください。

別AWSアカウントのCognito IDプールとCognitoユーザープールの連携ができたので、 Cognito IDプールで一時クレデンシャルキーが発行できるか試してみます。

Cognito IDプールから一意な Identity ID を取得して、そのIdentity IDをもとにAWSの一時的なクレデンシャルキーを取得します。 まずはCognitoユーザープールを作ったAWSアカウントのクレデンシャルキーを使って、IDトークンを発行します。

$ USER_POOL_ID=us-west-2_xxxxxxxxx
$ CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxx
$ USER_EMAIL=email@example.com
$ PASSWORD="Password01@"
$ ID_TOKEN=$(aws cognito-idp admin-initiate-auth \
  --user-pool-id ${USER_POOL_ID} \
  --client-id ${CLIENT_ID} \
  --auth-flow ADMIN_NO_SRP_AUTH \
  --auth-parameters "USERNAME=${USER_EMAIL},PASSWORD=${PASSWORD}" \
  --query "AuthenticationResult.IdToken" \
  --output text) && echo ${ID_TOKEN}

その後、 **発行したIDトークン&& とCognito IDプールを作ったAWSアカウントのクレデンシャルキーを使って、AWSの一時的なクレデンシャルキーを発行してみます。

$ ID_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxx
$ REGION=us-west-2
$ USER_POOL_ID=us-west-2_xxxxxxxxx
$ IDENTITY_POOL_ID=us-west-2:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$ COGNITO_USER_POOL=cognito-idp.${REGION}.amazonaws.com/${USER_POOL_ID}
$ IDENTITY_ID=$(aws cognito-identity get-id \
  --identity-pool-id ${IDENTITY_POOL_ID} \
  --logins "${COGNITO_USER_POOL}=${ID_TOKEN}" \
  --query "IdentityId" \
  --output text) && echo ${IDENTITY_ID}
$ OUTPUT=$(aws cognito-identity get-credentials-for-identity \
  --identity-id ${IDENTITY_ID} \
  --logins "${COGNITO_USER_POOL}=${ID_TOKEN}") && echo ${OUTPUT}
$ AWS_ACCESS_KEY_ID=$(echo ${OUTPUT} | jq .Credentials.AccessKeyId)
$ AWS_SECRET_ACCESS_KEY=$(echo ${OUTPUT} | jq .Credentials.SecretKey)
$ AWS_SESSION_TOKEN=$(echo ${OUTPUT} | jq .Credentials.SessionToken)
$ echo "export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID"
$ echo "export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY"
$ echo "export AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN"

また別のシェルでこの一時クレデンシャルキーを使用して、 aws sts get-caller-identity コマンドを実行してみます。 そうすると、この一時クレデンシャルキーがCognito IDプールで設定したIAM RoleからAssumeRoleされた権限であることがわかり、 Cognitoユーザープールが別のAWSアカウントでも問題なく機能していることがわかります。

$ aws sts get-caller-identity
{
    "UserId": "XXXXXXXXXXXXXXXXXXXXX:CognitoIdentityCredentials",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/Cognito_user_identity_another_accountAuth_Role/CognitoIdentityCredentials"
}

終わりに

Cognito IDプールとCognitoユーザープールの連携が、別リージョン、別AWSアカウントでも可能か試してみました。

ドキュメントを読んでもできるのかできないのか分からなかったので、実際に試してみてできることがわかってスッキリしました。