上級 45分 Lesson 13

Cognito & STS — 認証認可・フェデレーション・トークン管理

Cognito User/Identity Pools、Lambda トリガー、STS AssumeRole、Confused Deputy対策を徹底解説

AWS Cognito STS SCS-C03 認証 Security

はじめに

Cognito と STS は AWS における認証・認可・トークン管理の中心的サービス。SCS-C03 では両者の連携パターン、制約、セキュリティ対策が頻出です。

本講では AWS の責任分界点を理解しながら、実装レベルの詳細設定を掘り下げます。


第1部:Amazon Cognito

1.1 Cognito の2大コンポーネント

側面User PoolsIdentity Pools
機能認証(Authentication)認可(Authorization)
役割ユーザーID・パスワード管理、トークン発行AWS リソースへのアクセス権限付与
出力ID Token / Access Token / Refresh Token一時的な AWS 認証情報
連携先アプリケーション、API GatewayAWS サービス(S3, DynamoDB等)
スコープリージョナルグローバル(リージョン指定なし)

重要: User Pools だけでは AWS リソースにアクセスできない。Identity Pools と組み合わせて初めて完全な認証認可が成立します。

Cognito 認証フロー図

Loading diagram...


1.2 User Pools — 詳細設定

1.2.1 パスワードポリシー&アカウント復旧

User Pools 作成時に以下を設定します:

  • パスワード最小文字数: 8~256文字(デフォルト8)
  • 大文字必須、小文字必須、数字必須、特殊文字必須
  • カスタムパスワードルール: Regex 対応

アカウント復旧方法

  • メール検証リンク(デフォルト24時間有効)
  • SMS コード(デフォルト24時間有効)
  • セルフサービスパスワードリセット可否

試験のポイント:

  • パスワードリセットリンクの有効期限は設定不可(固定24時間)
  • リセット時に既存トークンは無効化されます

1.2.2 MFA(多要素認証)

User Pools は3つの MFA 方式をサポート:

  1. SMS(ショートメッセージ)

    • Cognito が SQS 経由で SNS へ送信
    • 設定: SNS IAM ロール必須
  2. TOTP(Time-based One-Time Password)

    • Google Authenticator など対応
    • AWS が秘密鍵を保管
  3. メール(Email)

    • SES 経由でワンタイムコード送信
    • 6桁、デフォルト24時間有効

MFAの強制方針:

  • Optional: ユーザー選択可能
  • Required: すべてのユーザーに必須
  • Custom: リスク評価に基づき動的に要求(Advanced Security)
# AWS CLI でユーザーに MFA を強制
aws cognito-idp admin-set-user-mfa-preference \
  --user-pool-id ap-northeast-1_xxxx \
  --username john@example.com \
  --sms-mfa-settings Enabled=true,PreferredMfa=true

1.2.3 Lambda トリガー — 8つの重要なポイント

User Pools は認証フロー内の8つのポイントで Lambda を実行できます:

トリガー実行タイミング用途
Pre Sign-upサインアップ前メール確認スキップ、自動確認
Pre Authenticationログイン直前カスタム検証、ブロック条件
Post Authenticationログイン完了後ログ記録、ポイント加算
Custom Messageメール/SMS送信前メッセージテンプレート変更
Pre Token Generationトークン発行直前カスタムクレーム追加、スコープ制御
User MigrationUser Migration フロー時既存 DB からのマイグレーション
Post Confirmationメール確認後確認完了時の処理
Custom Authflow Challengeカスタム認証フロー多段階認証の実装

Pre Token Generation の実装例

def lambda_handler(event, context):
    """
    User Pools のトークン生成直前に実行。
    カスタムスコープやグループ情報を ID Token に埋め込む。
    """
    event['response']['claimsOverrideDetails'] = {
        'claimsToAddOrOverride': {
            'email_verified': 'true',
            'custom:tenant_id': 'tenant-123',
            'custom:department': 'engineering'
        },
        'claimsToSuppress': ['phone_number'],
        'priorityOverride': 'GIVEN_CLAIMS',
    }
    return event

Lambda トリガーの制約(重要):

  • 実行タイムアウト: 5秒(延長不可)
  • 時間がかかる処理(外部 API 呼び出しなど)はできません
  • エラーが発生すると認証フロー全体が失敗
  • VPC 内の Lambda は起動が遅くなるため 5秒制限に注意

1.2.4 Advanced Security Features

User Pools に組み込まれた侵害対策機能

  1. 適応型認証(Adaptive Authentication)

    • IP アドレス、デバイス、位置情報を監視
    • 異常なログイン試行を検出
    • リスク評価に基づき MFA 要求
  2. 侵害された認証情報検出(Compromised Credentials Detection)

    • AWS の脅威インテリジェンスとの連携
    • パスワード漏洩データベースとマッチング
    • 該当ユーザーにパスワード変更を強制

有効化方法:

aws cognito-idp update-user-pool \
  --user-pool-id ap-northeast-1_xxxx \
  --account-recovery-setting PriorityList=[{Name=verified_email,Priority=1},{Name=verified_phone_number,Priority=2}] \
  --user-attribute-update-settings AttributesRequireVerificationBeforeUpdate=[email,phone_number]

1.2.5 ホストUI vs カスタムUI

要素ホストUIカスタムUI
構築時間分単位数日~数週間
Cognito が提供ログイン・サインアップ・MFA フォームSDK のみ
ホスティングCognito マネージド(cognito-idp.xx.amazoncognito.com)自分で構築・ホスト
ドメイン設定カスタムドメイン対応(SSL/TLS 自動管理)自由
セキュリティAWS マネージド自分で実装
CSRF 対策自動手動実装必須

カスタムドメインの制約:

  • 同じドメイン名は AWS 全体で一意(削除後も7日間は再使用不可)
  • CloudFront を経由するため、SSL サーティフィケートは AWS が自動管理
  • ACM 証明書の手動管理は不要

1.2.6 App Client 設定

User Pools ごとに複数の App Client を作成できます:

クライアント名: 自由

アプリケーションタイプ:

  • Web(SPA/SSR)
  • Native(iOS/Android)
  • Desktop

認証フロー:

  • ALLOW_USER_PASSWORD_AUTH: ユーザー名・パスワードで直接トークン取得可能(モバイルアプリに適している)
  • ALLOW_USER_SRP_AUTH: パスワードを平文で送信しない(推奨)
  • ALLOW_REFRESH_TOKEN_AUTH: Refresh Token でアクセストークン更新可能
  • ALLOW_CUSTOM_AUTH: カスタム認証フロー利用

クライアントシークレット:

  • Web アプリなら「シークレット生成」
  • SPA(JavaScript)なら「シークレット生成しない」(フロント側に秘密情報を持たせない)

トークン有効期限:

  • Refresh Token: 1日~10年
  • Access Token: 5分~24時間
  • ID Token: 5分~24時間

試験のポイント:

  • SPA でシークレット有りを使うと、フロントエンドに秘密情報が露出する
  • PKCE(Proof Key for Code Exchange)は OAuth 2.0 Authorization Code Flow で必須

1.3 Identity Pools — 詳細設定

User Pools でトークンを取得した後、そのトークンを使用して Identity Pools から AWS の一時認証情報 を取得します。

1.3.1 認証済み vs 未認証ロール

認証済みロール(Authenticated Role)

  • User Pools / IdP のトークンで Identity を取得
  • 該当ロールの権限で AWS リソースアクセス可能

未認証ロール(Unauthenticated Role)

  • トークンなしで Identity を取得
  • 限定的な読み取り権限(例: S3 バケットの public フォルダ)

実装例:

import boto3
import json

cognito_idp = boto3.client('cognito-idp', region_name='ap-northeast-1')
cognito_identity = boto3.client('cognito-identity', region_name='ap-northeast-1')
sts = boto3.client('sts', region_name='ap-northeast-1')

# ステップ1: User Pools からトークン取得
response = cognito_idp.admin_initiate_auth(
    UserPoolId='ap-northeast-1_xxxx',
    ClientId='clientid123',
    AuthFlow='ADMIN_USER_PASSWORD_AUTH',
    AuthParameters={
        'USERNAME': 'john@example.com',
        'PASSWORD': 'Password123!'
    }
)

id_token = response['AuthenticationResult']['IdToken']

# ステップ2: Identity Pools から Identity ID 取得
identity_response = cognito_identity.get_id(
    IdentityPoolId='ap-northeast-1:12345678-1234-1234-1234-123456789012',
    Logins={
        'cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_xxxx:' + id_token
    }
)

identity_id = identity_response['IdentityId']

# ステップ3: 一時認証情報を取得
credentials_response = cognito_identity.get_credentials_for_identity(
    IdentityId=identity_id,
    Logins={
        'cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_xxxx:' + id_token
    }
)

# これで AWS リソースにアクセス可能
temporary_credentials = credentials_response['Credentials']

1.3.2 ロールマッピング — トークンベース vs ルールベース

Identity Pools は複数の IAM ロールを管理でき、どのロールを割り当てるかを制御できます:

マッピング方式制御方法ユースケース
トークンベースID Token のカスタムクレームで選択テナントごとのロール分離、部門別権限
ルールベースCognito が提供する属性で選択IAM ロール数が多い場合、動的マッピング

トークンベースマッピングの例:

{
  "IdentityPoolId": "ap-northeast-1:xxxx",
  "RoleMappingType": "Token",
  "RulesConfiguration": null,
  "RoleMapping": {
    "ap-northeast-1_xxxx:client1": {
      "RoleArn": "arn:aws:iam::123456789012:role/user-role",
      "AmbiguousRoleResolution": "AuthenticatedRole"
    }
  }
}

ルールベースマッピングの例:

{
  "IdentityPoolId": "ap-northeast-1:xxxx",
  "RoleMappingType": "Rules",
  "RulesConfiguration": {
    "Rules": [
      {
        "Priority": 1,
        "Rule": {
          "Claim": "custom:department",
          "MatchType": "Equals",
          "Value": "engineering",
          "RoleArn": "arn:aws:iam::123456789012:role/engineering-role"
        }
      },
      {
        "Priority": 2,
        "Rule": {
          "Claim": "custom:department",
          "MatchType": "Equals",
          "Value": "marketing",
          "RoleArn": "arn:aws:iam::123456789012:role/marketing-role"
        }
      }
    ]
  }
}

1.3.3 外部IdP連携(フェデレーション)

Identity Pools は以下の外部 IdP と統合可能:

  1. Cognito User Pools(同じ AWS アカウント)
  2. Facebook / Google / Apple / Amazon
  3. SAML プロバイダー(Okta, Salesforce, Active Directory 等)
  4. OpenID Connect(OIDC)プロバイダー

Google フェデレーションの設定例:

# Identity Pools に Google プロバイダーを追加
aws cognito-identity update-identity-pool \
  --identity-pool-id "ap-northeast-1:xxxx" \
  --identity-pool-name "MyPool" \
  --supported-login-providers "accounts.google.com=123456789.apps.googleusercontent.com"

1.4 できないこと・制約

User Pools の制約

制約詳細
クォータ上限ユーザー数: 無制限、User Pools 数: リージョンあたり10個(拡張申請可)
パスワードリセットリンク有効期限固定24時間(変更不可)
Lambda トリガーのタイムアウト5秒(延長不可)
カスタムドメイン一意性AWS 全体で一意、削除後7日間は再使用不可
SMS 送信制限SNS で設定した制限に従う(デフォルト: 1秒あたり1件)
ホストUI のカスタマイズテンプレート機能で限定的に可能だが、完全なカスタマイズはできない
トークン署名アルゴリズムRS256 固定(HMAC-SHA256 等への変更不可)

Identity Pools の制約

制約詳細
IAM ロール切り替え遅延ロール変更後、既存の一時認証情報は変更前のロールで有効
ロールマッピング最大数トークンベース: クレーム値によって上限あり
リージョン指定なしIdentity Pool はグローバルだが、関連する IAM ロールはリージョンごと

1.5 ベストプラクティス

1. Advanced Security を常に有効化

aws cognito-idp update-user-pool \
  --user-pool-id ap-northeast-1_xxxx \
  --user-attribute-update-settings AttributesRequireVerificationBeforeUpdate=[email,phone_number] \
  --account-recovery-setting PriorityList=[{Name=verified_email,Priority=1}]

理由: 侵害された認証情報の検出、適応型認証により、ブルートフォース攻撃やリスト型攻撃を防止できます。

2. Lambda トリガーでカスタムバリデーション

def pre_authentication_handler(event, context):
    """
    ログイン直前に実行。
    カスタムビジネスロジック(例: IP ホワイトリスト、デバイス登録確認)を追加。
    """
    user_attributes = event['request'].get('userAttributes', {})
    email = user_attributes.get('email')
    
    # カスタムバリデーション(5秒以内に完了必須)
    if not is_ip_whitelisted(event['request']['userContextData']['sourceIp']):
        raise Exception(f"Login from {event['request']['userContextData']['sourceIp']} not allowed")
    
    return event

def is_ip_whitelisted(ip):
    # ホワイトリスト確認ロジック
    return ip.startswith('10.0.')

3. トークンのスコープ設計

OAuth 2.0 スコープを使用して、API への細粒度なアクセス制御を実装します:

# App Client にカスタムスコープを追加
aws cognito-idp create-resource-server \
  --user-pool-id ap-northeast-1_xxxx \
  --identifier api \
  --name "API Resource Server" \
  --scopes Name=read,Description="Read access to API" Name=write,Description="Write access to API"

4. RefreshToken の安全な管理

  • HTTPOnly Cookie に Refresh Token を保存(JavaScript からアクセス不可)
  • CSRF 保護を実装
  • Refresh Token の定期更新(ローテーション)

第2部:AWS STS(Security Token Service)

2.1 STS の役割

STS は 一時的な AWS 認証情報 を発行するサービス。長期的な IAM ユーザーのアクセスキーの代わりに、期限付きの認証情報を提供することで、セキュリティを向上させます。

STS が発行する一時認証情報:

  • AccessKeyId
  • SecretAccessKey
  • SessionToken(重要)
  • Expiration(有効期限)

2.2 AssumeRole — クロスアカウント認証

2.2.1 基本的なフロー

Account A(信頼側)

  • STS AssumeRole リクエスト
  • Account B(委任側)の IAM ロール
  • 一時認証情報を取得
  • Account B のリソースにアクセス可能

実装例:

# Account A のユーザーが、Account B のロールを引き受ける
aws sts assume-role \
  --role-arn arn:aws:iam::999999999999:role/CrossAccountRole \
  --role-session-name session-name-123 \
  --duration-seconds 3600

レスポンス:

{
  "Credentials": {
    "AccessKeyId": "ASIAX1234567890ABCD",
    "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
    "SessionToken": "AQoDYXdzEJr...<省略>...EXAMPLETOKEN",
    "Expiration": "2026-04-27T15:30:00Z"
  },
  "AssumedRoleUser": {
    "AssumedRoleId": "AIDAI1234567890ABCD:session-name-123",
    "Arn": "arn:aws:iam::999999999999:assumed-role/CrossAccountRole/session-name-123"
  }
}

2.2.2 Confused Deputy 問題と External ID

Confused Deputy 問題とは:

シナリオ:

  1. Account A のサービス S が、Account B のロール R を AssumeRole
  2. 悪意のある Account C が、Account A の S に命令
  3. S が知らないうちに、Account B のロール R の権限で C の指示を実行

対策: External ID を使用

External ID による保護:

# Account B(委任側)でロール作成時に External ID を指定
aws iam create-role \
  --role-name CrossAccountRole \
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {
          "AWS": "arn:aws:iam::111111111111:root"
        },
        "Action": "sts:AssumeRole",
        "Condition": {
          "StringEquals": {
            "sts:ExternalId": "unique-external-id-12345"
          }
        }
      }
    ]
  }'

# Account A(信頼側)でロール引き受け時に External ID を指定
aws sts assume-role \
  --role-arn arn:aws:iam::999999999999:role/CrossAccountRole \
  --role-session-name session-name-123 \
  --external-id unique-external-id-12345 \
  --duration-seconds 3600

External ID がない場合、Account C も同じロールを AssumeRole できてしまいます。必ず使用してください。

2.2.3 Session Tags

AssumeRole 時に、セッションに対してタグ(キー・値ペア)を設定できます。これにより、ロール内でセッションごとの権限を制御できます:

aws sts assume-role \
  --role-arn arn:aws:iam::999999999999:role/CrossAccountRole \
  --role-session-name session-name-123 \
  --tags Key=Project,Value=ProjectA Key=Department,Value=Engineering \
  --duration-seconds 3600

IAM ポリシーで Session Tags を参照:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/projects/${aws:PrincipalTag/Project}/*",
      "Condition": {
        "StringEquals": {
          "aws:PrincipalTag/Department": "Engineering"
        }
      }
    }
  ]
}

2.3 AssumeRoleWithSAML / AssumeRoleWithWebIdentity

2.3.1 AssumeRoleWithSAML

Okta、Salesforce、Active Directory などの SAML IdP との統合:

aws sts assume-role-with-saml \
  --role-arn arn:aws:iam::123456789012:role/SAMLRole \
  --principal-arn arn:aws:iam::123456789012:saml-provider/ExampleProvider \
  --saml-assertion file://saml-assertion.xml \
  --duration-seconds 3600

2.3.2 AssumeRoleWithWebIdentity

Google、Facebook などの OIDC プロバイダーとの統合:

aws sts assume-role-with-web-identity \
  --role-arn arn:aws:iam::123456789012:role/OIDCRole \
  --role-session-name session-name-123 \
  --web-identity-token token-from-google-oauth \
  --duration-seconds 3600

Cognito との連携:

# Cognito User Pools の ID Token を使用
aws sts assume-role-with-web-identity \
  --role-arn arn:aws:iam::123456789012:role/CognitoRole \
  --role-session-name session-name-123 \
  --web-identity-token ${ID_TOKEN} \
  --duration-seconds 3600

2.4 GetSessionToken(MFA付き)

IAM ユーザーが MFA 経由で一時認証情報を取得:

aws sts get-session-token \
  --serial-number arn:aws:iam::123456789012:mfa/user-mfa-device \
  --token-code 123456 \
  --duration-seconds 3600

ユースケース:

  • CLI での高権限操作を MFA で保護
  • CI/CD パイプラインへの認証情報提供

2.5 GetFederationToken

長期的な認証情報を持つユーザーが、期限付きの代理認証情報を発行:

aws sts get-federation-token \
  --name federated-user-session \
  --policy '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::my-bucket/*"
      }
    ]
  }' \
  --duration-seconds 3600

AssumeRole との違い:

  • AssumeRole: IAM ロールを引き受ける(ロールの権限 ∩ セッション権限)
  • GetFederationToken: カスタム権限を定義できる(より柔軟)

2.6 セッション期間の制約

API最小期間最大期間デフォルト注記
AssumeRole900秒(15分)43200秒(12時間)3600秒(1時間)ロール最大セッション期間で制限可能
AssumeRoleWithSAML900秒43200秒3600秒同上
AssumeRoleWithWebIdentity900秒43200秒3600秒同上
GetSessionToken900秒129600秒(36時間)3600秒ユーザーの最大セッション期間で制限可能
GetFederationToken900秒129600秒3600秒呼び出し元ユーザーの権限で制限

ロールチェーン時の制限(重要):

Account A の User → Account B のロール → Account C のロール

        A→B での期間: 1時間可能

                  B→C での期間: **A の残り時間以下**(最大1時間)

ロールチェーンは1時間以内に完了する必要があります。


2.7 できないこと・制約

制約詳細
トークン有効期間の上限AssumeRole は最大12時間、GetSessionToken は最大36時間
ロールチェーン1時間制限複数の AssumeRole を連続実行する場合、合計期間は1時間以内
リージョナルエンドポイント推奨グローバルエンドポイント(sts.amazonaws.com)よりもリージョナルエンドポイント(sts.ap-northeast-1.amazonaws.com)を推奨
MFA デバイス再登録IAM ユーザーのMFAデバイスを変更後、GetSessionToken に一時的に失敗する場合あり
External ID の後からの追加ポリシー更新後、既に発行された一時認証情報には影響なし

2.8 ベストプラクティス

1. 一時認証情報の徹底活用

import boto3
from botocore.credentials import RefreshableCredentials
from botocore.session import Session

# 長期的なアクセスキーではなく、一時認証情報を使用
sts = boto3.client('sts')
response = sts.assume_role(
    RoleArn='arn:aws:iam::999999999999:role/ApplicationRole',
    RoleSessionName='app-session',
    DurationSeconds=900
)

credentials = response['Credentials']
session = Session()
session.set_credentials(
    credentials['AccessKeyId'],
    credentials['SecretAccessKey'],
    credentials['SessionToken']
)

s3 = session.create_client('s3')

2. Confused Deputy 防止(必須)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "unique-id-for-this-lambda-function"
        },
        "ArnLike": {
          "aws:SourceArn": "arn:aws:lambda:ap-northeast-1:123456789012:function/my-function"
        }
      }
    }
  ]
}

3. STS エンドポイントはリージョナルを使用

# 推奨: リージョナルエンドポイント
aws sts assume-role \
  --endpoint-url https://sts.ap-northeast-1.amazonaws.com \
  --role-arn arn:aws:iam::999999999999:role/CrossAccountRole \
  --role-session-name session-name-123

理由: グローバルエンドポイント(sts.amazonaws.com)よりもレイテンシが低く、リージョン側のレートリミットに対応できます。

4. セッション期間を最小限に

# 15分(最小期間)で十分な場合は 900 秒を使用
aws sts assume-role \
  --role-arn arn:aws:iam::999999999999:role/CrossAccountRole \
  --role-session-name session-name-123 \
  --duration-seconds 900

第3部:Cognito + STS の連携パターン

3.1 Architecture: Cognito + API Gateway + Lambda

┌─────────────────────────────────────────────────────────────┐
│                      ユーザーの流れ                          │
└─────────────────────────────────────────────────────────────┘

① ユーザーがログイン

  User Pools(認証)

  ID Token / Access Token / Refresh Token を取得
  
② API への認可を取得

  Identity Pools

  一時的な AWS 認証情報(AccessKeyId, SecretAccessKey, SessionToken)
  
③ API Gateway の認可

  Lambda Authorizer が ID Token を検証

  API Gateway がリクエストを許可/拒否
  
④ Lambda 関数が実行

  一時認証情報で S3, DynamoDB などにアクセス


┌─────────┐          ┌────────────────┐
│ ユーザー │ -------> │ Cognito User   │
│          │          │ Pools (認証)   │
└─────────┘          └────────────────┘

                      ID Token 発行

                  ┌─────────────────────┐
                  │ Cognito Identity    │
                  │ Pools(認可)       │
                  └─────────────────────┘

                  一時認証情報を発行

        ┌─────────────────────────────┐
        │   API Gateway (認可)          │
        │   ↓ Lambda Authorizer で     │
        │   ↓ トークン検証             │
        └─────────────────────────────┘

                  ┌─────────────────┐
                  │ Lambda 関数     │
                  │ ↓ AWS リソース  │
                  │   (S3, DDB等)  │
                  └─────────────────┘

3.2 実装例:Lambda Authorizer

import json
import boto3
from jose import jwt

cognito_user_pool_id = 'ap-northeast-1_xxxx'
cognito_client_id = 'clientid123'
region = 'ap-northeast-1'

# Cognito の公開鍵を取得(JWT 署名検証用)
cognito = boto3.client('cognito-idp', region_name=region)

def lambda_handler(event, context):
    """
    API Gateway Lambda Authorizer
    ID Token を検証して、認可を判断する
    """
    token = event.get('authorizationToken', '')
    method_arn = event.get('methodArn', '')
    
    try:
        # JWT の署名検証
        claims = verify_token(token, cognito_user_pool_id, cognito_client_id, region)
        
        # トークンが有効な場合、ユーザーに API へのアクセスを許可
        return generate_policy('user', 'Allow', method_arn, claims)
    
    except Exception as e:
        print(f"Token verification failed: {str(e)}")
        return generate_policy('user', 'Deny', method_arn)


def verify_token(token, user_pool_id, client_id, region):
    """
    JWT トークンの署名を検証
    """
    # Cognito の JWKS エンドポイントから公開鍵を取得
    jwks_url = f"https://cognito-idp.{region}.amazonaws.com/{user_pool_id}/.well-known/jwks.json"
    
    # jose ライブラリを使用して検証
    # 実装はライブラリの公式ドキュメントに従う
    claims = jwt.get_unverified_claims(token)
    
    # 実際の署名検証はここで行う
    # 省略(本来は JWKS を使用して署名を検証)
    
    return claims


def generate_policy(principal_id, effect, resource, claims=None):
    """
    API Gateway の承認ポリシーを生成
    """
    auth_response = {
        'principalId': principal_id,
        'policyDocument': {
            'Version': '2012-10-17',
            'Statement': [
                {
                    'Action': 'execute-api:Invoke',
                    'Effect': effect,
                    'Resource': resource
                }
            ]
        }
    }
    
    # クレーム情報を Context に追加
    if claims:
        auth_response['context'] = {
            'email': claims.get('email', ''),
            'sub': claims.get('sub', '')
        }
    
    return auth_response

3.3 Cognito + ALB

┌──────────────┐
│ ユーザー     │
└──────────────┘

┌──────────────────────┐
│ ALB(Application    │
│ Load Balancer)     │
│ ↓ Cognito で認証    │
└──────────────────────┘

  Cognito User Pools

ID Token を ALB に返却

ALB が トークン検証後、
バックエンド EC2 / ECS へ
リクエストを転送

ALB リスナールールの設定例:

aws elbv2 create-rule \
  --listener-arn arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener/app/my-alb/1234567890abcdef/1 \
  --priority 1 \
  --conditions Field=path-pattern,Values='/api/*' \
  --actions \
    Type=authenticate-cognito,AuthenticateCognitoConfig='{
      UserPoolArn=arn:aws:cognito-idp:ap-northeast-1:123456789012:userpool/ap-northeast-1_xxxx,
      UserPoolClientId=clientid123,
      UserPoolDomain=my-domain
    }' \
    Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/my-targets/1234567890abcdef

3.4 STS + Organizations クロスアカウント

複数の AWS アカウントを一元管理する場合、STS を使用して Organizations 内のロールを AssumeRole します:

STSクロスアカウント構成

実装例:

# Management Account のユーザーが、Production Account のロールを AssumeRole
aws sts assume-role \
  --role-arn arn:aws:iam::111111111111:role/OrganizationAccountAccessRole \
  --role-session-name management-session \
  --external-id arn:aws:organizations::123456789012:organization/o-1234567890 \
  --duration-seconds 3600

3.5 フェデレーションパターン全体像

┌────────────────────────────────────────────────────────────┐
│            フェデレーション全体像                           │
└────────────────────────────────────────────────────────────┘

1. User Pools だけで認証(Web / Mobile アプリ)

   ID Token / Access Token を取得

   API Gateway + Lambda Authorizer で API 保護

   AWS リソースへはアクセスしない

2. User Pools + Identity Pools(AWS リソースアクセス必須)

   ID Token で Identity Pools から認可取得

   一時認証情報を使用して S3, DynamoDB へアクセス

3. 外部 IdP (Google / Okta / SAML)

   Cognito User Pools と外部 IdP をフェデレーション

   パターン2と同様

4. STS AssumeRole(B2B / クロスアカウント)

   別 AWS アカウントのロールを引き受ける

   External ID で Confused Deputy を防止

5. STS AssumeRoleWithWebIdentity(Cognito との直接連携)

   Cognito User Pools の ID Token を直接利用

   Identity Pools を経由せずに AWS リソースアクセス可能

試験で狙われるポイント

Cognito 編

  1. User Pools vs Identity Pools の役割

    • User Pools = 認証(ユーザー名・パスワード管理)
    • Identity Pools = 認可(AWS リソースへのアクセス権限)
  2. Lambda トリガーの 5秒制限

    • Pre Token Generation で外部 API 呼び出しは原則 NG
    • 5秒以内に完了する処理のみ
  3. Advanced Security Features

    • 侵害された認証情報検出
    • 適応型認証(リスク評価に基づく MFA)
  4. SPA でシークレット生成は NG

    • フロントエンドに秘密情報を露出させないため
  5. Identity Pool ロールマッピング

    • トークンベース vs ルールベース の選択基準

STS 編

  1. Confused Deputy 問題

    • External ID の使用は必須
    • AWS の責任分界点を理解
  2. ロールチェーン1時間制限

    • A → B → C のように複数ロールをチェーンする場合、合計期間は1時間以内
  3. AssumeRole と GetFederationToken の違い

    • AssumeRole: ロール権限の一部を取得
    • GetFederationToken: カスタム権限を定義
  4. Session Tags による細粒度な権限制御

    • セッション単位で権限を制御
  5. リージョナルエンドポイントの推奨

    • sts.ap-northeast-1.amazonaws.com の使用

まとめ

サービス用途出力有効期限
Cognito User Pools認証ID/Access/Refresh Token調整可能(デフォルト1時間)
Cognito Identity Pools認可AWS 一時認証情報最大12時間
STS AssumeRoleクロスアカウントAWS 一時認証情報最大12時間
STS GetSessionTokenMFA 認証AWS 一時認証情報最大36時間

Cognito と STS は、AWS のセキュアな認証認可の基盤です。フェデレーション、ロールマッピング、Confused Deputy 対策を完全に理解することが、SCS-C03 合格の鍵となります。