こんにちは、ひるたんぬです。
最近電車に乗る機会が増えており、電車内でスマホを凝視するとすぐに酔ってしまう私は、電車の中吊り広告を眺めることが多いです。
そんな中で、ふと「〇〇が!?」というような表現が目に留まりました。そういえば「!」「?」の順番って大体「!?(感嘆符→疑問符)」のような…
と同時に、英語の書物では「?!(疑問符→感嘆符)」と、逆であることが多いような気もしてきました。
絵文字では「⁉️(感嘆符→疑問符)」のみしか存在しないようですが、Unicode上では「⁉(U+2049)」「⁈(U+2048)」のどちらも存在します。
調べる中で「インテロハング | ‽(U+203D)」という順番も気にしなくて良い記号があることも知りました。
順番のルールは調べてみましたが、明確なルールは存在せず、「デザイン・バランス上の都合で日本は!?が多い」という意見が多かったように見受けられました。
この点について、理由をご存じの方はぜひご教示いただきたいです。
さて、今回は前回の記事にも関連するところがありますが、Microsoft Entra IDなどの外部IdPをAmazon Cognitoに連携した際に、そのユーザーを自動的にグループに所属させる方法をご紹介します。前回の記事も興味がありましたらご覧ください。
なお、外部IdP経由でアクセスしたユーザーについて、Cognito上では自動的に一意のグループに所属されます。
Amazon Cognito は、ユーザープールに追加する OIDC、SAMl、ソーシャル ID プロバイダー (IdP) ごとにユーザーグループを作成します。グループ名の形式は [user pool ID]_[IdP name] です (例: us-east-1_EXAMPLE_MYSSO、us-east-1_EXAMPLE_Google)。自動生成された一意の各 IdP ユーザープロファイルは、このグループに自動的に追加されます。
引用:AWS 「ユーザープールにグループを追加する」
今回の記事では、それ以外の(自分で作成した)グループに自動的に所属させたい場合の内容となっております。
事前準備
既にユーザをCognito以外の別IDプロバイダーで管理していることを想定しています。
今回はEntra IDと連携しています。OIDC・SAMLどちらでも動作確認はしておりますので、要件に合わせて設定してください。
設定が完了したら、以下のようになっていることを確認します。
手順
今回の肝となる機能はCognitoのLambdaトリガーです。個人的には「Cognito用のEventBridge」という感覚です。
Cognitoのサインアップ時やトークン作成時などの各種処理イベントに対してトリガーを設定でき、それに対応するLambda関数を実行できる機能です。
Amazon Cognito ユーザープールでユーザーを作成または更新する前に、フェデレーティッドユーザー属性を変換します
引用:AWS 「Lambda トリガーを使用したユーザープールワークフローのカスタマイズ」
Lambda関数の準備
今回は、「外部IdPユーザに対して、すべてのグループに所属させる」というLambda関数を準備しました。
特定のグループにのみ所属させたい場合などは、適宜コードを修正してください。
import os
import logging
import boto3
from botocore.exceptions import ClientError
logging.basicConfig(level=os.getenv("LOG_LEVEL", "INFO"))
logger = logging.getLogger(__name__)
cognito = boto3.client("cognito-idp")
PROVIDER_NAME = os.getenv("PROVIDER_NAME").lower()
def list_all_groups(user_pool_id: str) -> list[str]:
groups: list[str] = []
paginator = cognito.get_paginator("list_groups")
for page in paginator.paginate(UserPoolId=user_pool_id):
groups.extend(
g["GroupName"]
for g in page.get("Groups", [])
if "GroupName" in g
)
logger.info("list_all_groups: total=%d", len(groups))
return groups
def lambda_handler(event, context):
user_pool_id = event["userPoolId"]
trigger_source = event.get("triggerSource")
event_username = event.get("userName", "")
logger.info(
"handler start request_id=%s trigger=%s userPoolId=%s userName=%s",
getattr(context, "aws_request_id", None),
trigger_source,
user_pool_id,
event_username,
)
# InboundFederation のみ対象(別トリガーの場合は適宜変更・削除してください)
if trigger_source != "InboundFederation_ExternalProvider":
return event
# Cognito 実 username に正規化
prefix = f"{PROVIDER_NAME}_"
username = (
event_username
if event_username.lower().startswith(prefix)
else prefix + event_username
)
group_names = list_all_groups(user_pool_id)
success = failed = 0
# 全グループへの追加処理を実行
for group in group_names:
try:
cognito.admin_add_user_to_group(
UserPoolId=user_pool_id,
Username=username,
GroupName=group,
)
success += 1
except ClientError as e:
failed += 1
logger.error(
"add group failed username=%s group=%s error=%s",
username,
group,
e,
exc_info=True,
)
logger.info(
"handler done username=%s success=%d failed=%d total=%d",
username,
success,
failed,
len(group_names),
)
return event
また、このコードでは環境変数「PROVIDER_NAME」を使用しています。
Lambda内の環境変数に追加してください。値にはCognitoに外部IdPを連携させたときの「プロバイダー名」を設定します。
Lambdaトリガーの設定
先ほど作成したLambda関数に対して、CognitoのLambdaトリガーを設定します。
Cognitoのユーザープール内にある「認証 – 拡張機能」をクリックします。
するとLambdaトリガーの画面が出てくるので「Lambda トリガーを追加」をクリックします。
トリガータイプを「フェデレーション – インバウンドフェデレーション トリガー」になるように選択し、先ほど作成したLambda関数を選択します。
設定が完了したら、「Lambda トリガーを追加」をクリックします。

動作確認
原因究明
このようになってしまう要因を探るために、Lambdaのログを確認してみます。
すると、一回目のアクセス時に動いているLambda内で、以下のようなエラーが出ていることが確認できました。
[ERROR] 2026-06-15T01:35:40.598Z 473f080d-e68d-47fb-9944-XXXXXXXXXXXXXX add group failed username=entraid-saml_sample.taro@exsample.onmicrosoft.com group=Group-B error=An error occurred (UserNotFoundException) when calling the AdminAddUserToGroup operation: User does not exist. Traceback (most recent call last): File "/var/task/cognito-idp-group-attach.py", line 64, in lambda_handler cognito.admin_add_user_to_group( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ UserPoolId=user_pool_id, ^^^^^^^^^^^^^^^^^^^^^^^^ Username=username, ^^^^^^^^^^^^^^^^^^ GroupName=group, ^^^^^^^^^^^^^^^^ ) ^ File "/var/lang/lib/python3.13/site-packages/botocore/client.py", line 602, in _api_call return self._make_api_call(operation_name, kwargs) ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^ File "/var/lang/lib/python3.13/site-packages/botocore/context.py", line 123, in wrapper return func(*args, **kwargs) File "/var/lang/lib/python3.13/site-packages/botocore/client.py", line 1078, in _make_api_call raise error_class(parsed_response, operation_name) botocore.errorfactory.UserNotFoundException: An error occurred (UserNotFoundException) when calling the AdminAddUserToGroup operation: User does not exist.
「User does not exist.」と言われていますね。
ここで、改めて今回設定したトリガーのドキュメントを確認してみます。
インバウンドフェデレーショントリガーは、外部 ID プロバイダーによる認証プロセス中にフェデレーションユーザー属性を変換します。
…(中略)…
このトリガーを使用して、新しいユーザーを作成する前、または既存のフェデレーティッドユーザープロファイルを更新する前に、属性を追加、上書き、または抑制します。
引用:AWS 「インバウンドフェデレーション Lambda トリガー」
答えが書かれていましたね。このトリガーはCognito上にユーザーを作成する前に動作をするものなので、初回アクセス時はユーザーが作成されていない、つまりCognito上にユーザーが存在しないということになります。
おわりに
今回はCognitoで外部IdPを連携させる際に、外部IdPユーザーをグループに自動的に所属させるための方法をご紹介しました。
初回アクセス時の課題は残っていますが、この記事がどなたかの参考になりましたら幸いです。









