本記事は 夏休みクラウド自由研究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 アタッチ機能でしたが、機能しないケースもあるという紹介でした。
本記事が皆様のお役に立てれば幸いです。







