Contents
Amazon Cognito ユーザープールとは
本セクションでは、Cognito が提供する認証・認可の全体像と、本ハンズオンで実装する主要フローを解説します。
Cognito のユーザープールは「ユーザー属性の永続管理」と「OpenID Connect/OAuth 2.0 に基づくトークン発行」の両方を一元化できるマネージドサービスです。AWS が自動でスケーリング・高可用性を担保するため、独自実装に比べて運用コストが大幅に削減できます。また、高度なセキュリティ機能(MFA、リスクベース認証)や Lambda トリガーによる拡張性 が標準で利用できる点も重要です。
以下の手順を順に実施すれば、コンソール操作からコード化まで一貫した認証基盤が構築できます。
| フェーズ | 主な作業 |
|---|---|
| ① コンソール | ユーザープール・アプリクライアントの手動作成(概要把握) |
| ② CLI | aws cognito-idp で同等設定をスクリプト化 |
| ③ IaC | CloudFormation または Terraform による完全自動化 |
| ④ テスト | Amplify/SDK を用いたサインアップ・サインインの検証 |
1. AWS Management Console でユーザープールを作成・設定する手順
この章では、コンソール UI を使った初期構築手順と、後からコード化しやすい設定項目をまとめます。
1‑1. ユーザープールの基本情報入力
コンソールの 「User Pools」 → 「Create user pool」 で以下を設定します。
- プール名:プロジェクト名と環境が分かる
myapp-prod-poolのように命名 - タグ:公式ドキュメント(Tagging resources)で推奨されているキー例を使用。例:
Project=MyApp,Env=Prod,Owner=team@example.com
ポイント
タグは Cost Allocation とリソース検索に必須です。全ての Cognito 関連リソース(UserPool、UserPoolClient、Lambda)へ同一タグを付与してください。
1‑2. 属性スキーマとカスタム属性
| 項目 | 設定例 |
|---|---|
| 標準属性 | email(必須・自動検証)、phone_number(任意) |
| カスタム属性 | custom:department (String)、custom:isAdmin (Boolean) などビジネス要件に合わせて追加 |
注意
カスタム属性はプレフィックスcustom:が必須です。属性名は 1 〜 64 文字、英数字とアンダースコアのみ使用可能です。
1‑3. サインアップ/サインイン体験のカスタマイズ
メール・SMS 検証
User Pool → Message customizations → Verification messages でテンプレートを編集し、メール と SMS の検証を有効化します。
ホスト型 UI(Hosted UI)
App client settings → Hosted UI をオンにすると、Cognito が提供するサインアップ/サインイン画面が自動生成されます。ロゴ URL やカラーテーマは同画面の UI customization で設定可能です。
1‑4. セキュリティポリシー
| ポリシー | 推奨設定 |
|---|---|
| パスワード要件 | 最小長 12文字、大文字・小文字・数字・記号すべて必須 |
| MFA | TOTP(Google Authenticator 等) を推奨し、SMS はオプションにする |
| リスクベース認証 | 「Advanced security」→「Adaptive authentication」で、異常ログインや IP 変化時に MFA Challenge を要求 |
メトリクスの正確な名称
Cognito が CloudWatch に出力するリスク関連メトリクスはRiskDecision(例:BLOCK,MFA_CHALLENGE,NO_RISK) です。旧称のAuthRiskScoreは存在しないため、公式ドキュメント(Monitoring Cognito with CloudWatch)を参照してください。
1‑5. アプリクライアントと OAuth2 フロー設定
基本情報
- Client name:
myapp-web-client(わかりやすく命名) - Generate secret:SPA やモバイルは オフ 推奨(シークレットが漏洩しやすいため)
| OAuth2 フロー | 説明 | SPA での利用推奨 |
|---|---|---|
| Authorization Code Grant (PKCE 対応) | code を取得後サーバー側でトークンと交換。PKCE によりクライアントシークレット不要で安全性が向上。 |
必須(最新ベストプラクティス) |
| Implicit Grant | アクセストークンを直接返す旧方式。XSS 攻撃リスクが高いため非推奨。 | × |
| Client Credentials Grant | サーバー間認証に使用。ユーザーコンテキストは無い。 | - |
PKCE の設定
App client settings → Allowed OAuth FlowsでAuthorization code grantとProof Key for Code Exchange (PKCE)を有効化します。フロントエンド側ではcode_challenge_method=S256を使用してください。
リダイレクト URI の登録
|
1 2 3 |
https://myapp.example.com/callback https://myapp.example.com/logout-callback |
正確に入力し、ワイルドカードは不可です。誤った URI は認証エラーの原因になります。
1‑6. ドメイン設定と UI カスタマイズ
| 種類 | 手順 |
|---|---|
| 標準ドメイン | Domain name タブで myapp.auth.ap-northeast-1.amazoncognito.com を入力 |
| カスタムドメイン(任意) | ACM にリージョン ap-northeast-1 用の証明書を発行 → 同タブで独自ドメイン auth.myapp.example.com を紐付け |
CSS カスタマイズは Hosted UI → CSS customization へコードを書き込むだけで反映できます。
2. AWS CLI と IaC(CloudFormation / Terraform)での自動化
この章では、コンソール操作をすべてコードとして管理できるようにする方法を解説します。
2‑1. CLI でのユーザープール作成例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# ユーザープール作成(属性・パスワードポリシー・MFA を含む) aws cognito-idp create-user-pool \ --pool-name myapp-prod-pool \ --username-attributes email phone_number \ --auto-verified-attributes email \ --policies '{ "PasswordPolicy": { "MinimumLength": 12, "RequireUppercase": true, "RequireLowercase": true, "RequireNumbers": true, "RequireSymbols": true } }' \ --mfa-configuration ON \ --software-token-mfa-configuration Enabled=true # アプリクライアント作成(PKCE 対応) aws cognito-idp create-user-pool-client \ --user-pool-id <POOL_ID> \ --client-name myapp-web-client \ --generate-secret false \ --allowed-oauth-flows code \ --allowed-oauth-scopes email openid profile \ --callback-urls "https://myapp.example.com/callback" \ --allowed-oauth-scopes "email" "openid" "profile" |
ポイント
--allowed-oauth-flowsにcodeを指定し、PKCE が自動的に有効化されます(CLI では明示的なフラグは不要です)。
2‑2. CloudFormation テンプレート
以下は Cognito ユーザープール + Lambda トリガー の最小構成例です。2026 年時点の最新プロパティを使用しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
AWSTemplateFormatVersion: '2010-09-09' Description: Cognito User Pool with Adaptive Authentication and Lambda triggers Resources: UserPool: Type: AWS::Cognito::UserPool Properties: UserPoolName: !Sub "${AWS::StackName}-pool" UsernameAttributes: - email - phone_number AutoVerifiedAttributes: - email Policies: PasswordPolicy: MinimumLength: 12 RequireUppercase: true RequireLowercase: true RequireNumbers: true RequireSymbols: true MfaConfiguration: ON SmsAuthenticationMessage: "Your verification code is {####}" EmailVerificationSubject: "Verify your email for MyApp" LambdaConfig: PreSignUp: !GetAtt PreSignUpFunction.Arn PostConfirmation: !GetAtt PostConfirmFunction.Arn UserPoolAddOns: AdvancedSecurityMode: ENFORCED # リスクベース認証を有効化 UserPoolClient: Type: AWS::Cognito::UserPoolClient Properties: ClientName: myapp-web-client UserPoolId: !Ref UserPool GenerateSecret: false AllowedOAuthFlows: - code # PKCE 対応の Authorization Code Grant AllowedOAuthScopes: - email - openid - profile CallbackURLs: - https://myapp.example.com/callback ExplicitAuthFlows: - ALLOW_USER_PASSWORD_AUTH - ALLOW_REFRESH_TOKEN_AUTH # ---------- Lambda Functions ---------- PreSignUpFunction: Type: AWS::Lambda::Function Properties: Runtime: nodejs20.x Handler: index.handler Role: !GetAtt LambdaExecutionRole.Arn Code: ZipFile: | exports.handler = async (event) => { const email = event.request.userAttributes.email || ""; if (!email.endsWith("@example.com")) { throw new Error("Only @example.com addresses are allowed."); } return event; }; PostConfirmFunction: Type: AWS::Lambda::Function Properties: Runtime: nodejs20.x Handler: index.handler Role: !GetAtt LambdaExecutionRole.Arn Code: ZipFile: | exports.handler = async (event) => { console.log(`User ${event.userName} confirmed.`); return event; }; LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole |
テンプレートのポイント
UserPoolAddOns.AdvancedSecurityModeを ENFORCED にすると、リスクベース認証が常に適用されます。AllowedOAuthFlowsにcodeのみを指定し、PKCE が有効になることを明示しています。- Lambda 関数はインラインで定義しているので、最小限のリポジトリでも動作します。
2‑3. Terraform モジュール例
公式モジュール terraform-aws-modules/cognito-user-pool/aws をベースに、必要な項目だけを上書きします。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
module "cognito_user_pool" { source = "terraform-aws-modules/cognito-user-pool/aws" version = "~> 4.0" name = "myapp-prod-pool" username_attributes = ["email", "phone_number"] auto_verified_attributes = ["email"] password_policy = { minimum_length = 12 require_uppercase = true require_lowercase = true require_numbers = true require_symbols = true } mfa_configuration = "ON" sms_authentication_message = "Your verification code is {####}" email_verification_subject = "Verify your MyApp account" schema = [ { name = "custom:department" attribute_data_type = "String" mutable = true required = false }, { name = "custom:isAdmin" attribute_data_type = "Boolean" mutable = true required = false } ] lambda_config = { pre_sign_up = aws_lambda_function.pre_signup.arn post_confirmation = aws_lambda_function.post_confirm.arn } tags = { Project = "MyApp" Env = "prod" Owner = "team@example.com" } } |
ベストプラクティス
-terraform init→terraform plan→terraform applyの順で実行し、状態は必ず S3 バックエンドに保存してください。
- モジュールのバージョンは定期的に更新し、AWS が提供する新機能(例: PKCE 強制)への追従を忘れないようにします。
3. Lambda トリガーと実装テスト
この章では、Cognito の拡張ポイントである Lambda トリガーの設定方法と、Amplify/SDK を用いたエンドツーエンドテスト手順を紹介します。
3‑1. IAM ロール作成(最小権限)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
aws iam create-role \ --role-name CognitoLambdaExecRole \ --assume-role-policy-document file://trust-policy.json # trust-policy.json の内容例 cat > trust-policy.json <<'EOF' { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF aws iam attach-role-policy \ --role-name CognitoLambdaExecRole \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole |
3‑2. Lambda 関数作成(Node.js)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# Pre Sign‑up(メールドメイン制限) cat > pre-signup.js <<'EOF' exports.handler = async (event) => { const email = event.request.userAttributes.email || ""; if (!email.endsWith("@example.com")) { throw new Error("Only @example.com addresses are allowed."); } return event; }; EOF zip pre-signup.zip pre-signup.js aws lambda create-function \ --function-name PreSignUpFunction \ --runtime nodejs20.x \ --handler pre-signup.handler \ --role arn:aws:iam::$(aws sts get-caller-identity --query Account --output text):role/CognitoLambdaExecRole \ --zip-file fileb://pre-signup.zip |
同様に Post Confirmation 用の関数も作成し、index.handler に console.log 等を記述します。
3‑3. Cognito へトリガー紐付け
|
1 2 3 4 |
aws cognito-idp update-user-pool \ --user-pool-id <POOL_ID> \ --lambda-config PreSignUp=arn:aws:lambda:<region>:<account-id>:function:PreSignUpFunction,PostConfirmation=arn:aws:lambda:<region>:<account-id>:function:PostConfirmFunction |
コンソールでも User Pool → Triggers タブから同様に設定できます。
3‑4. Amplify(JavaScript)での認証フロー検証
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import { Auth } from 'aws-amplify'; Auth.configure({ region: 'ap-northeast-1', userPoolId: '<POOL_ID>', userPoolWebClientId: '<CLIENT_ID>', // PKCE 対応なのでシークレットは不要 }); // ★ サインアップ await Auth.signUp({ username: 'alice@example.com', password: 'Str0ngP@ssw0rd!', attributes: { email: 'alice@example.com', phone_number: '+819012345678' } }); // ★ メールで受け取ったコードを入力して確認 await Auth.confirmSignUp('alice@example.com', '<CODE_FROM_EMAIL>'); // ★ サインイン(PKCE が内部的に自動適用される) const user = await Auth.signIn('alice@example.com', 'Str0ngP@ssw0rd!'); console.log('Access token:', user.getAccessToken().getJwtToken()); |
iOS (Swift) と Android (Kotlin) でも同様の手順でテストできます。公式サンプルは以下をご参照ください:
- iOS → https://docs.amplify.aws/lib/auth/getting-started/q/platform/ios
- Android → https://docs.amplify.aws/lib/auth/getting-started/q/platform/android
3‑5. 確認ポイント
| 項目 | 判定基準 |
|---|---|
| メール検証コードが届くか | OK:メール受信後 Auth.confirmSignUp が成功 |
| Pre Sign‑up の制限が機能するか | NG: 別ドメインでサインアップするとエラーメッセージが返る |
| Post Confirmation で CloudWatch Logs に出力されているか | OK:User alice@example.com confirmed. がログに表示 |
4. 運用・監視ベストプラクティス
本章では、構築した Cognito 環境を長期的に安全・安定運用するための具体的な指針と自動化ポイントをまとめます。
4‑1. タグ戦略と命名規則
| リソース | 推奨タグ例 |
|---|---|
| UserPool / UserPoolClient / Lambda | Project=MyApp, Env=Prod, Owner=team@example.com |
| CloudWatch アラーム | 同上に加えて AlertLevel=Critical など |
命名規則:<app>-<env>-cognito-<resource>(例: myapp-prod-cognito-pool)で、リソース一覧が一目で把握できるようにします。
4‑2. パスワードポリシーと MFA の定期見直し
| 項目 | 推奨頻度 | アクション例 |
|---|---|---|
| パスワード長・文字種 | 半年ごと | MinimumLength を 12 → 14 に段階的に引き上げ |
| MFA 種類 | 四半期ごと | SMS の利用率を測定し、80 % 以上が TOTP に移行したら SMS を無効化 |
| リスクベース認証の閾値 | 毎月 | CloudWatch RiskDecision の分布を確認し、ブロック率が高すぎないか検討 |
4‑3. ログ・メトリクス監視
- CloudWatch Logs
- Cognito コンソール → “General settings” → “Logging” で All events を有効化。
- 標準メトリクス(自動送信)
| メトリクス | 説明 |
|---|---|
| SignInSuccess | 正常サインイン数 |
| SignInFailure | 失敗したサインイン数 |
| SignUpSuccess | 正常サインアップ数 |
| SignUpFailure | サインアップエラー(例: カスタム属性バリデーション) |
| RiskDecision | NO_RISK, MFA_CHALLENGE, BLOCK のいずれかを示す |
- アラーム例
|
1 2 3 4 5 6 7 8 9 |
AlarmName: Cognito-SignInFailure-High MetricName: SignInFailure Namespace: AWS/Cognito Threshold: 20 # 5 分間に 20 件以上の失敗で発火 EvaluationPeriods: 1 ComparisonOperator: GreaterThanOrEqualToThreshold AlarmActions: - arn:aws:sns:ap-northeast-1:<account-id>:CognitoAlerts |
- Security Hub 連携
- CloudWatch アラームを SNS 経由で Security Hub に転送し、インシデント自動化(AWS Step Functions + Lambda)に活用できます。
4‑4. CI/CD パイプラインへの組み込み
| ステップ | 実装例 |
|---|---|
| テンプレート検証 | cfn-lint / terraform validate を GitHub Actions のジョブで実行 |
| デプロイ | aws cloudformation deploy または terraform apply -auto-approve をステージング → 本番の 2 段階デプロイで実施 |
| テスト自動化 | Amplify CLI の amplify auth status とカスタム E2E スクリプト(Cypress)でサインアップ/サインインを検証 |
次にやるべきこと
- コンソールで最小構成のユーザープールを作成し、タグ・ドメイン設定まで完了させます。
- 公式リポジトリ(https://github.com/aws-samples/amazon-cognito-user-pool)からサンプル CloudFormation テンプレートを取得し、PKCE が有効な Authorization Code Grant を必ず確認してください。
- 作成したスタックを GitHub Actions で自動デプロイ できるようにパイプラインを構築し、テストがすべて成功することを CI に組み込みます。
以上で、最新ベストプラクティス(PKCE、リスクベース認証の正確なメトリクス名、公式ドキュメント参照)に沿った Amazon Cognito ユーザープール の設計・実装・運用が完了します。質問や不明点があれば、AWS 公式サポートもしくは IAM/セキュリティ担当者へお問い合わせください。