Amazon Cognito ユーザープールに AWS WAF Web ACL をアタッチするときの注意事項

こんにちは、広野です。

2025 年 6 月に Amazon Cognito マネージドログインに AWS WAF の Web ACL をアタッチすることができるようになりました。

 

 

何ら真新しいことではないのですが、気を付けた方がよい点があるので書いておきます。

 

公式ドキュメント

以下に公式ドキュメントがあります。

 

 

アタッチした AWS WAF Web ACL によるチェック対象は以下になります。

  • Managed login and the classic hosted UI
  • Public API operations

つまり、UI と API なんですが。さらっと書かれすぎているので、以降、別ブログ記事の図を引用して説明します。

 

どこがチェック対象なのか

図に示すと、以下の赤丸の 2 箇所がチェック対象になります。

 

 

もう少し概念レベルで Amazon Cognito ユーザープールを機能分割すると、以下のように表現できます。

Amazon Cognito のマネージドログイン UI と、API がチェック対象になるのですが、それぞれのソースが異なります。

 

ソース IP アドレス制限をかけるときの注意

このため、Amazon Cognito マネージドログインを使用する環境でソース IP アドレス制限をかけるときには注意事項があります。

ソースは複数箇所あると考えた方がよいです。上記のケースでは、ユーザーデバイスと Amazon EC2 インスタンスの IP アドレスを両方許可するようにしてあげないと、認証フローが通りません。

 

おまけ AWS CloudFormation テンプレート

AWS Cognito に AWS WAF をアタッチする AWS CloudFormation テンプレートを参考までに貼り付けます。

今回検証したのは特定のソース IP アドレス (サブネット) を許可する設定です。

アプリケーションクライアントの設定は省略しています。Amazon Cognito ユーザープールと、AWS WAF およびそのログ保存に絞っています。登場する IP アドレスは架空のものです。

AWSTemplateFormatVersion: 2010-09-09
Description: The CloudFormation template that creates a Cognito user pool with Managed Login.

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
  SystemName:
    Type: String
    Description: System name. use lower case only. (e.g. example)
    Default: example
    MaxLength: 10
    MinLength: 1

  SubName:
    Type: String
    Description: System sub name. use lower case only. (e.g. prod or dev)
    Default: dev
    MaxLength: 10
    MinLength: 1

  SesId:
    Type: String
    Description: Amazon SES ID for sending emails. (email addreess or domain)
    Default: xxxx.xxx
    MaxLength: 100
    MinLength: 5

  SesConfigurationSet:
    Type: String
    Description: Amazon SES configuration set for sending emails.
    Default: xxxxxxxxxxxxxxxx
    MaxLength: 100
    MinLength: 5

  CognitoReplyTo:
    Type: String
    Description: Cognito Reply-to email address. (e.g. xxx@xxx.xxx)
    Default: xxxxx@xxx.xxx
    MaxLength: 100
    MinLength: 5

  CognitoEmailFrom:
    Type: String
    Description: Cognito e-mail from address. (e.g. xxx@xxx.xxx)
    Default: xxxxx@xxx.xxx
    MaxLength: 100
    MinLength: 5

  LogRetentionDays:
    Type: Number
    Description: The retention period (days) for AWS WAF logs. Enter an integer between 35 to 540.
    Default: 365
    MaxValue: 540
    MinValue: 35

  SourceIpv4RangeList:
    Type: CommaDelimitedList
    Description: The comma delimited list of allowed source IPv4 address range (CIDR) except /0 to access this web site. (e.g. xxx.xxx.xxx.xxx/xx,yyy.yyy.yyy.yyy/yy)
    Default: "8.8.8.8/32,8.8.4.4/32"

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "General Configuration"
        Parameters:
          - SystemName
          - SubName
      - Label:
          default: "Email Configuration"
        Parameters:
          - SesId
          - SesConfigurationSet
          - CognitoReplyTo
          - CognitoEmailFrom
      - Label:
          default: "Security Configuration"
        Parameters:
          - LogRetentionDays
          - SourceIpv4RangeList

Resources:
# ------------------------------------------------------------#
# Cognito
# ------------------------------------------------------------#
  UserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      UserPoolName: !Sub ${SystemName}-${SubName}
      MfaConfiguration: "OFF"
      Policies:
        PasswordPolicy:
          MinimumLength: 8
          RequireUppercase: true
          RequireLowercase: true
          RequireNumbers: true
          RequireSymbols: false
          TemporaryPasswordValidityDays: 180
      AccountRecoverySetting:
        RecoveryMechanisms:
          - Name: verified_email
            Priority: 1
      AdminCreateUserConfig:
        AllowAdminCreateUserOnly: true
      AutoVerifiedAttributes:
        - email
      DeviceConfiguration:
        ChallengeRequiredOnNewDevice: false
        DeviceOnlyRememberedOnUserPrompt: false
      EmailConfiguration:
        ConfigurationSet: !Ref SesConfigurationSet
        EmailSendingAccount: DEVELOPER
        From: !Sub "${SystemName}-${SubName} admin <${CognitoEmailFrom}>"
        ReplyToEmailAddress: !Ref CognitoReplyTo
        SourceArn: !Sub arn:aws:ses:${AWS::Region}:${AWS::AccountId}:identity/${SesId}
      EmailVerificationMessage: !Sub "${SystemName}-${SubName} Verification code: {####}"
      EmailVerificationSubject: !Sub "${SystemName}-${SubName} Verification code"
      UsernameConfiguration:
        CaseSensitive: false
      UserPoolAddOns:
        AdvancedSecurityMode: "OFF"
      UserPoolTags:
        Cost: !Sub ${SystemName}-${SubName}
      UserPoolTier: ESSENTIALS

  UserPoolDomain:
    Type: AWS::Cognito::UserPoolDomain
    Properties:
      Domain: !Sub ${SystemName}-${SubName}
      ManagedLoginVersion: 2
      UserPoolId: !Ref UserPool

# ------------------------------------------------------------#
# WAF Web Acl for Cognito
# ------------------------------------------------------------#
  WebAclCognito:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: !Sub ${SystemName}-${SubName}-cognito
      Description: WAFv2 WebACL for Cognito
      Scope: REGIONAL
      DefaultAction:
        Block: {}
      Rules:
        - Name: !Sub ${SystemName}-${SubName}-cognito-IpWhiteList
          Action:
            Allow: {}
          Priority: 0
          Statement:
            IPSetReferenceStatement:
              Arn: !GetAtt WAFv2Ipv4WhiteList.Arn
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: !Sub ${SystemName}-${SubName}-cognito-IpWhiteList
            SampledRequestsEnabled: true
      VisibilityConfig:
        CloudWatchMetricsEnabled: true
        MetricName: !Sub ${SystemName}-${SubName}-cognito
        SampledRequestsEnabled: true
      Tags:
        - Key: Cost
          Value: !Sub ${SystemName}-${SubName}
    DependsOn:
      - WAFv2Ipv4WhiteList

  WAFv2Ipv4WhiteList:
    Type: AWS::WAFv2::IPSet
    Properties:
      Name: !Sub ${SystemName}-${SubName}-Ipv4WhiteList
      Description: WAF v2 IPv4 white list for the IP-based restricted access
      IPAddressVersion: IPV4
      Addresses: !Ref SourceIpv4RangeList
      Scope: REGIONAL
      Tags:
        - Key: Cost
          Value: !Sub ${SystemName}-${SubName}

  WebACLAssociationCognito:
    Type: AWS::WAFv2::WebACLAssociation
    Properties:
      ResourceArn: !GetAtt UserPool.Arn
      WebACLArn: !GetAtt WebAclCognito.Arn
    DependsOn:
      - UserPool
      - WebAclCognito

  WebAclLoggingConfigurationCognito:
    Type: AWS::WAFv2::LoggingConfiguration
    Properties:
      ResourceArn: !GetAtt WebAclCognito.Arn
      LogDestinationConfigs:
        - !GetAtt S3BucketWafLogs.Arn
      LoggingFilter:
        DefaultBehavior: KEEP
        Filters:
          - Behavior: KEEP
            Conditions:
              - ActionCondition:
                  Action: BLOCK
            Requirement: MEETS_ANY
    DependsOn:
      - S3BucketWafLogs
      - WebAclCognito

# ------------------------------------------------------------#
# S3
# ------------------------------------------------------------#
  S3BucketWafLogs:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub aws-waf-logs-${SystemName}-${SubName}-cognito
      LifecycleConfiguration:
        Rules:
          - Id: AutoDelete
            Status: Enabled
            ExpirationInDays: !Ref LogRetentionDays
      OwnershipControls:
        Rules:
          - ObjectOwnership: BucketOwnerEnforced
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      Tags:
        - Key: Cost
          Value: !Sub ${SystemName}-${SubName}

# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#
Outputs:
# Cognito
  CognitoUserPoolId:
    Value: !Ref UserPool
    Export:
      Name: !Sub CognitoUserPoolId-${SystemName}-${SubName}
  CognitoUserPoolArn:
    Value: !GetAtt UserPool.Arn
    Export:
      Name: !Sub CognitoUserPoolArn-${SystemName}-${SubName}
  CognitoUserPoolProviderName:
    Value: !GetAtt UserPool.ProviderName
    Export:
      Name: !Sub CognitoUserPoolProviderName-${SystemName}-${SubName}
  CognitoUserPoolProviderUrl:
    Value: !GetAtt UserPool.ProviderURL
    Export:
      Name: !Sub CognitoUserPoolProviderUrl-${SystemName}-${SubName}

まとめ

いかがでしたでしょうか。

今回は小ネタでした。Amazon Cognito 周りの通信パスをご存知の方にとっては当たり前と思いましたが、意外と知られていないかもな?と思ったので書きました。

本記事が皆様のお役に立てれば幸いです。

著者について
広野 祐司

AWS サーバーレスアーキテクチャと React を使用して社内向け e-Learning アプリ開発とコンテンツ作成に勤しんでいます。React でアプリを書き始めたら、快適すぎて他の言語には戻れなくなりました。近年は社内外への AWS 技術支援にも従事しています。AWS サービスには AWS が考える IT 設計思想が詰め込まれているので、そこを理解できると他のことにも活かせるので、いつも AWS を通して勉強させて頂いてまます。
取得資格:AWS 認定は15資格、IT サービスマネージャ、ITIL v3 Expert 等
2020 - 2025 Japan AWS Top Engineer 受賞
2022 - 2025 AWS Ambassador 受賞
2023 当社初代フルスタックエンジニア認定
好きなAWSサービス:AWS AppSync Events / AWS Step Functions / AWS CloudFormation

広野 祐司をフォローする

クラウドに強いによるエンジニアブログです。

SCSKクラウドサービス(AWS)は、企業価値の向上につながるAWS 導入を全面支援するオールインワンサービスです。AWS最上位パートナーとして、多種多様な業界のシステム構築実績を持つSCSKが、お客様のDX推進を強力にサポートします。

AWSクラウド
シェアする
タイトルとURLをコピーしました