【小ネタ】AWS WAF v2 の WebACL (CloudFront用)を東京リージョンから CloudFormation で作成しようとしたら怒られた
コンバンハ、千葉(幸)です。
言われればそうだよなぁと思わなくもない落とし穴にハマったので、次はハマらないように書いておきます。
目次
やりたかったこと
以下のリソースを一つの CloudFormation スタックで東京リージョンで一気に作成したかったです。
- CloudFront ディストリビューション
AWS::CloudFront::Distribution
- オリジンアクセスアイデンティティ
AWS::CloudFront::CloudFrontOriginAccessIdentity
- S3 バケット(オリジンに指定)
AWS::S3::Bucket
- S3 バケットポリシー
AWS::S3::BucketPolicy
- AWS WAF v2 WebACL
AWS::WAFv2::WebACL
CloudFront はグローバルなサービスでありながら、東京リージョンから CloudFormation を実行して問題なく作成できるので、 WAF も一気に作れるだろうという考えでいました。
やれなかったこと
WebACL の作成時にエラーが吐かれました。
はじめに WebACL 以外のリソースを定義した CloudFormation テンプレートを流してみて問題なくスタックが作成できたので、以下を追加したテンプレートでスタックの更新を試みました。
(お試しで枠だけ作ろうとしたのでルールは一切設定していないです。)
# ------------------------------------------------------------# # AWS WAFv2 # ------------------------------------------------------------# webAclforcloudfront: Type: AWS::WAFv2::WebACL Properties: DefaultAction: Allow: {} Description: WebACL for CloudFront Name: test-cf-webacl # Rules: # - Rule Scope: CLOUDFRONT VisibilityConfig: SampledRequestsEnabled: true CloudWatchMetricsEnabled: true MetricName: test-cf-webacl
ちなみに WebACL は以下の2種類がありますが、その定義は上記ハイライト部で実施しています。
- リージョナル:ALB もしくは API Gateway に適用
- グローバル:CloudFrontに適用
スタックの更新を実行したところ、作成に失敗しました。悲しい。
Error reason: The scope is not valid., field: SCOPE_VALUE, parameter: CLOUDFRONT
ひとまず上記のエラーで調べてみたところ、以下のフォーラムがヒットしました。
https://forums.aws.amazon.com/thread.jspa?messageID=927178
同様のエラーが発生している事象で、そこでは「us-east-1 (バージニア北部) で CloudFormation を実行していないからだよ」という回答がなされていました。
そんなことドキュメントに書いてあったっけ!? 暗黙の了解のように扱われても困るよ、明記してくれないと! と思ったのですが、きちんと書いてありました。すみません。
CLOUDFRONT の場合、米国東部 (バージニア北部) リージョン (us-east-1) で WAFv2 リソースを作成する必要があります。
AWS::WAFv2::WebACL - AWS CloudFormation
手前の確認不足で、すみません。
やることにしたこと
WebACL の部分だけ切り出して独立したテンプレートとすることにしました。
ひとまず切り出して以下のような形式とすることで us-east-1 で問題なくデプロイできることを確認しました。
AWSTemplateFormatVersion: '2010-09-09' Description: "Create webAcl" Resources: # ------------------------------------------------------------# # AWS WAFv2 # ------------------------------------------------------------# webAclforcloudfront: Type: AWS::WAFv2::WebACL Properties: DefaultAction: Allow: {} Description: WebACL for CloudFront Name: test-cf-webacl # Rules: # - Rule Scope: CLOUDFRONT VisibilityConfig: SampledRequestsEnabled: true CloudWatchMetricsEnabled: true MetricName: test-cf-webacl
CloudFront の作成を us-east-1 に寄せることも考えたのですが、他のリソースとの兼ね合いを考慮してそれは断念しました。
そうすると残る課題は、作成した WebACL をどう割り当てるかです。
CloudFront ディストリビューションに WebACL を割り当てる設定を CloudFormation で行う場合、AWS::CloudFront::Distribution
内の DistributionConfig
の中で定義する必要があります。
Aliases: - String CacheBehaviors: - CacheBehavior Comment: String CustomErrorResponses: - CustomErrorResponse DefaultCacheBehavior: DefaultCacheBehavior DefaultRootObject: String Enabled: Boolean HttpVersion: String IPV6Enabled: Boolean Logging: Logging OriginGroups: OriginGroups Origins: - Origin PriceClass: String Restrictions: Restrictions ViewerCertificate: ViewerCertificate WebACLId: String
AWS::CloudFront::Distribution DistributionConfig - AWS CloudFormation
WebACLId
に設定する値として、 WAF v2 の WebACL を適用する場合には ARN を渡す必要があります。
このディストリビューションに関連付ける AWS WAF ウェブ ACL がある場合は、それを指定する一意の識別子。最新バージョンの AWS WAF を使用して作成されたウェブ ACL を指定するには、ACL ARN を使用します
同一のテンプレート内で記述されていれば単純に !GetAtt
で引っ張ってこれるのですが、分かれてしまったためそうもいきません。
CloudFormation の Outputs を利用してテンプレートを跨いで参照する方式が使えないかと考えたのですが、リージョンを跨いでの参照はできないようです。
最終的に、CloudFront への WebACL の適用はそこだけ手動で行うか、 WebACL の ARN を手動でスタックのパラメータとして渡すような形で更新をかける方針にしました。
ちょっと納まりが悪いですが致し方ないですね。
おわりに
そう言えばグローバルなリソースだとちょくちょくこういう注意事項があったなーと思い出すハマりポイントでした。
CloudFront は東京リージョンからでも作成できるので、 WebACL も併せて作成できると大変助かります!(アップデートお待ちしています!)
以上、ドキュメント読み取り能力の低さを露呈した千葉(幸)がお送りしました。
おまけに
一通り書き上げた後に気付いたのですが、こちらのブログでも同じような事象に対する記述をされていました。
- 従来の WAF であれば us-east-1 縛りはない
- 2020年3月時点ではドキュメントに記載が無かった(と思われる)
東京リージョンで実行する CloudFormation スタックにパラメータを渡すという部分は同じですが、 AWS CLI を用いて工夫されているようですね。
勉強になります。