「CloudFront経由でS3にアクセスする + WAFv2でアクセス制限をかける」リソース一式を構築するAWS CDKのサンプルです.
- WAFv2リソースは
us-east-1
リージョンのスタックとして - S3バケットとCloudFrontは
それ以外の
リージョンのスタックとして(検証ではap-northeast-1を使用)
deployする方法と,実装でハマったポイントをまとめました.
CDKは,2021.04.13時点での最新バージョンである,1.98.0を使用しました.
動機
-
S3でホスティングしている既存ウェブサイト(ap-northeast-1)に独自ドメインを割り当てたかったが,バケット名がドメイン名と異なっており,CloudFrontの導入が必要となった.
-
CloudFront経由でのアクセスに,IPベースでのアクセス制限をかける必要があり,WAFでのアクセス制御も必要となった.
-
既存リソースはCDKで管理されており,新たに追加するリソースもCDKの管理下にしたかった.
Overview
01-waf stack
WAFv2 WebACLを管理するスタックです.
CloudFormation - WAFv2 - Scopeに書かれているように,WAFv2のACLをCloudFrontに関連付けたい場合,US East (N. Virginia) Region (us-east-1)へWAFv2リソースを作成する必要があります.そこで,app.tsで明示的にリージョンを指定しています.
const wafStack = new WafStack(app, '01-waf', {
// (省略)
env: {
account: stackEnv.account,
region: "us-east-1", // ここ
},
// (省略)
});
実装当初,この制限に気づかず,deployエラーでハマりました.(WAFv1の場合,リージョン制限は無いようです.)
後述のスタックで作成するCloudFrontとの関連付けには,作成したWebACLのARNが必要となります.
ここでは,SSM Parameter StoreにWebACL ARNを格納しました(これを参照する方法は後述).
02-web-dist stack
- コンテンツを格納するS3バケット
- S3バケットを向き先としたCloudFront distribution
を管理するスタックです.技術検証のため,01-waf スタックと別リージョンにしています.
S3バケット,CloudFront web distributionを定義し,先に作成したWAFv2 ACLと関連付けていくのですが,
ここでの問題は,US East (N. Virginia) RegionのParameter Storeに格納されているWebACL ARNを参照しなければならない点です.
cross-regionの参照は通常の方法では不可能なため,こちらを参考にカスタムリソースを使った参照クラスを実装して解決しました.
ハマったポイント
-
WAFv2 リソースのリージョン制限
WAFv2のWebACLをCloudFrontに関連付ける場合,ACLをus-east-1に作成する必要がありました.
-
CDKでの他リージョンのSSM Parameter Store参照
const param = ssm.StringParameter.valueForStringParameter(this, `param-name`);
の方法で参照できるのは,そのスタックの同一リージョンのParameter Storeのみです.
cross-region参照するため,カスタムリソースを使った方法の情報にたどり着くまで苦労しました... -
CDKでのCloudFrontへのWAF WebACLの関連付け
@aws-cdl/aws-wafv2
モジュールにCfnWebACLAssociationというクラスがあり,最初,これを使えばよいかと思ったのですが,こちらで関連付けできるのは,API Gateway REST API等,CloudFront distribution以外
の場合でした.
CloudFrontと関連付ける場合は,CloudFrontWebDistribution側で,WebACLを指定する必要があります.
webACLのプロパティ名はwebACLIdとなっていますが,WAFv2を使う場合WebACLのARNを指定
する点にも注意してください.this.distribution = new cloudfront.CloudFrontWebDistribution( this, "website-distribution", { webACLId: webAclArn, // 以下省略 } );
ACLの中身
本サンプルでは,IPアドレスベースの制限としています.アクセスを許可するIPアドレスは,
cdk.context.jsonに記述して,CDK context valueとしてインポートしています.
サンプル公開用では,ダミーのIPアドレスを記述しているので,検証したいIPアドレスに書き換えてください.
{
"allowed_ips": [
"10.0.0.0/16"
]
}
Reference
本スタック実装にあたり参考にさせていただいたサイトを,トピック別に掲載しました.