AWS Amplify Hosting に AWS WAF Web ACL をアタッチするときの注意事項

本記事は 夏休みクラウド自由研究2025 8/1付の記事です

こんにちは、広野です。

ちょうど書いていた記事が夏休みシーズンだったので、会社の自由研究扱いにしてしまいました。w

さて。

2025 年 3 月に AWS Amplify Hosting でホストされたサイトに AWS WAF の Web ACL をアタッチすることができるようになりました。

少々使ってみたい要件があったので、やってみて気付いた点を書き残しておこうと思います。

やりたいこと

あえて簡単にひとことで言うと、以下をやりたかったです。

  • 指定した IPv4 アドレス (またはサブネット) からのみサイトへのアクセスを許可したい。

結論から言うと、特定の条件が引っかかって実現できなかったのですが。

従来のソリューションとの比較

冒頭の新機能がリリースされるまでは、以下のソリューションがありました。

  • AWS Amplify に Amazon CloudFront をかぶせて、AWS WAF をアタッチします。
    Amplify Hosting で Wrapping された Amazon CloudFront には AWS WAF をアタッチできなかったので、二重に Amazon CloudFront が存在します。

  • もう 1 つは、AWS Amplify を使用せず、Amazon CloudFront を組み込んだアプリ基盤を構築し、AWS WAF をアタッチします。
    私の過去のブログで紹介した方法です。

 

新しいソリューションでは、以下の図のように AWS Amplify Hosting で Wrapping された Amazon CloudFront に直接 AWS WAF をアタッチできるようになったわけです。おそらく、多くの要件はこの構成を活用して実現できると思います。

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

実は、ソース IP アドレス制限をかけるときには注意事項があります。

まず、IP アドレスには IPv4 と IPv6 があります。ソース IP アドレス制限をかけるときには IPv4 で設定するのが一般的かつ現実的です。IPv6 でも設定はできるのですが、IPv6 はソース IP アドレスが頻繁に変わることがあり、レンジ設定も難しく、実質制御できないと思った方がよいです。

そのため、AWS Amplify Hosting のサイトに IPv4 のみでアクセスできるようにしたいのですが、条件によってはそれができません。

仕様上、AWS Amplify は IPv4 と IPv6 を同時に利用可能とする デュアルスタック をサポートしており、いろいろと確認したところカスタムドメインを使用していると IPv4 通信のみを利用可能とする構成がサポートされていませんでした。

 

「いや、うちの会社のインターネットは IPv4 しか使ってないから問題ないよ」

このケースであれば問題ありません。素直に最初から最後まで IPv4 通信をしてきてくれますので。

ですが、世の中には IPoE なる IPv6 ネイティブの通信が既に普及してきており、IPoE ユーザーは IPv4 網を経由せずダイレクトに IPv6 の AWS Amplify Hosting サイトに到達してしまいます。このとき、ソース IP アドレスは IPv6 アドレスになり、Web ACL で 100% 拒否されてしまうのです。つまり、IPoE ユーザーは全くサイトにアクセスできないということです。

この通信のイメージは以下です。

 

もしも AWS Amplify Hosting が IPv6 を無効にできるなら、以下の図のように Web ACL が成り立ちます。
本当はこうしたいのです。※できません。

結論

結局、IPv4 ベースのソース IP アドレス制限は AWS Amplify + AWS WAF では完全にはできません。アクセス元が必ず IPv4 で通信してきてくれるなら、という条件付きで実現可能です。

純粋 Amazon CloudFront であれば IPv6 を無効にできるので、完全に実現できるのは従来のソリューションのままです。

Amazon Route 53 で別のレコードをかぶせればいけるか?とも思ったのですが、難しいと思いました。いずれにしてももう少し手を加えればできる方法はあるのかもしれません。

AWS Amplify に限らず、他の AWS サービスでもデュアルスタックのみしかサポートしていないリソースに AWS WAF をアタッチする場合は同じことが発生します。

補足すると、IPv4 over IPv6 を経由したソース IPv4 アドレスは一般的には別契約の他者と共有されているので、それだけを完全に信用したソース IP アドレス制限は危険です。ただし、プロバイダーのオプションで専用ソース IPv4 アドレスを提供してくれる IPoE 接続サービスもあるので、その場合は問題ないと思います。ネイティブな IPv4 でも、クラウドのセキュリティプロキシサービスを経由しているとソース IP アドレスを別契約の他者と共有するケースがあるので、その場合も信用はできません。もはやソース IP アドレス安全神話は崩れてきているなぁと思っています。

おまけ AWS CloudFormation テンプレート

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

今回検証した構成なので実用的ではありませんが、AWS CloudFormation だとこう書けばデプロイできるというのがわかるぐらいのものと思っていただければ。

AWS Amplify のリージョンに関わらず、バージニア北部リージョンでデプロイする必要があります。AWS Amplify Hosting アプリケーションの ARN がインプットとして必要です。テンプレート内に記入している IP アドレスは例のために書いたもので、実際には有り得ない値です。

AWSTemplateFormatVersion: 2010-09-09
Description: The CloudFormation template that creates a WAF web acl for Amplify hosting. This template must be deployed in us-east-1 region only.

# ------------------------------------------------------------#
# 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

  AmplifyArn:
    Type: String
    Description: The target Amplify ARN.
    Default: arn:aws:amplify:xxxxxxxxxxxx:999999999999:apps/xxxxxxxxxxxx
    AllowedPattern: ^arn:aws:amplify:.+:\d{12}:apps\/.+$

  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: "192.168.0.0/24,8.8.8.8/32"

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

Resources:
# ------------------------------------------------------------#
# WAF Web Acl for Amplify
# ------------------------------------------------------------#
  WebAclAmplify:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: !Sub ${SystemName}-${SubName}-amplify
      Description: !Sub WAFv2 WebAcl for Amplify ${SystemName}-${SubName}
      Scope: CLOUDFRONT
      DefaultAction:
        Block: {}
      Rules:
        - Name: !Sub CustomRule-IpWhiteList-${SystemName}-${SubName}
          Action:
            Allow: {}
          Priority: 0
          Statement:
            IPSetReferenceStatement:
              Arn: !GetAtt Ipv4WhiteList.Arn
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: !Sub CustomRule-IpWhiteList-${SystemName}-${SubName}
            SampledRequestsEnabled: true
      VisibilityConfig:
        CloudWatchMetricsEnabled: true
        MetricName: !Sub WebAcl-${SystemName}-${SubName}
        SampledRequestsEnabled: true
      Tags:
        - Key: Cost
          Value: !Sub ${SystemName}-${SubName}
    DependsOn:
      - Ipv4WhiteList

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

  WebAclAssociationAmplify:
    Type: AWS::WAFv2::WebACLAssociation
    Properties:
      ResourceArn: !Ref AmplifyArn
      WebACLArn: !GetAtt WebAclAmplify.Arn
    DependsOn:
      - WebAclAmplify

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

# ------------------------------------------------------------#
# S3
# ------------------------------------------------------------#
  S3BucketWafLogs:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub aws-waf-logs-${SystemName}-${SubName}
      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}

まとめ

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

期待していた AWS Amplify Hosting への AWS WAF アタッチ機能でしたが、機能しないケースもあるという紹介でした。

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

著者について
広野 祐司

AWS サーバーレスアーキテクチャを駆使して社内クラウド人材育成アプリとコンテンツづくりに勤しんでいます。React で SPA を書き始めたら快適すぎて、他の言語には戻れなくなりました。サーバーレス & React 仲間を増やしたいです。AWS は好きですが、それよりもバックエンド構築を簡単にしてくれたことに対する感謝の気持ちの方が強いです。
取得資格:AWS 認定は15資格、IT サービスマネージャ、ITIL v3 Expert 等
2020 - 2024 Japan AWS Top Engineer 受賞
2022 - 2024 AWS Ambassador 受賞
2023 当社初代フルスタックエンジニア認定
好きなAWSサービス:AWS Amplify / AWS AppSync / Amazon Cognito / AWS Step Functions / AWS CloudFormation

広野 祐司をフォローする

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

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

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