それぞれ異なるリージョンの CDK スタックで作成された AWS WAF Web ACL と CloudFront Distribution の紐付けができるのか試してみた
こんにちは、製造ビジネステクノロジー部の若槻です。
グローバルリソースである Amazon CloudFront Distribution に対して紐付けられる AWS WAF Web ACL は、北部バージニア (us-east-1) リージョンに作成される必要があるという制限があります。
その場合に、それぞれ異なるリージョンの AWS CDK スタックで作成された AWS WAF Web ACL と CloudFront Distribution の紐付けができるのか?試す機会があったので共有します。
試してみた
クロススタック参照手法
今回、CDK においてクロススタック参照を行うのですが、その手法としてスタック同士が密結合とならない「パラメーターストア経由」の参照方法を利用します。
Web ACL の作成
まず、北部バージニア (us-east-1) リージョンに Web ACL を作成し、その Arn を ssm パラメータストアに保存します。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as wafv2 from 'aws-cdk-lib/aws-wafv2';
import * as ssm from 'aws-cdk-lib/aws-ssm';
export class MainStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: cdk.StackProps) {
super(scope, id, props);
// Web ACL の作成
const webAcl = new wafv2.CfnWebACL(this, 'WebAcl', {
defaultAction: { block: {} },
scope: 'CLOUDFRONT',
visibilityConfig: {
cloudWatchMetricsEnabled: true,
sampledRequestsEnabled: true,
metricName: 'WafWebAclForCloudfront',
},
rules: [],
});
// Web ACL の Arn を SSM パラメータストアに保存
new ssm.StringParameter(this, 'WebAclArn', {
parameterName: 'web-acl-arn',
stringValue: webAcl.attrArn,
});
}
}
上記をデプロイします。
パラメータストアに格納される Arn は次のようになります。
aws ssm get-parameter \
--name "/web-acl-arn" \
--region us-east-1 \
--query 'Parameter.Value' \
--output text
> arn:aws:wafv2:us-east-1:XXXXXXXXXXXX:global/webacl/WebAcl-KpSSk9rbWP3W/7bf29e1e-17bb-4c26-aeb6-3d6c23d5be34
CloudFront Distribution の作成、Web ACL との紐付け
次に、Web ACL とは別リージョンである東京 (ap-northeast-1) リージョンに CloudFront Distribution を作成し、Web ACL との紐付けを行います。
ここで、ap-northeast-1 リージョンの CDK スタックから us-east-1 リージョンの SSM パラメータストアに格納された Web ACL の Arn を取得するために、次のようなカスタムリソースを利用します。
import { custom_resources } from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CrossRegionGetParameter extends Construct {
public readonly parameterValue: string;
constructor(
scope: Construct,
id: string,
props: {
readonly parameterName: string;
readonly region: string;
}
) {
super(scope, id);
const getParameter = new custom_resources.AwsCustomResource(
this,
'GetParameterCustomResource',
{
onUpdate: {
service: 'SSM',
action: 'getParameter',
parameters: {
Name: props.parameterName,
},
physicalResourceId: custom_resources.PhysicalResourceId.of(
props.parameterName
),
region: props.region,
},
policy: custom_resources.AwsCustomResourcePolicy.fromSdkCalls({
resources: custom_resources.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
installLatestAwsSdk: false,
}
);
this.parameterValue = getParameter.getResponseField('Parameter.Value');
}
}
カスタムリソースで取得した Web ACL の Arn を CloudFront Distribution に紐付けます。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
import { CrossRegionGetParameter } from './cross-region-get-parameter-custom-resource';
export class Main2Stack extends cdk.Stack {
constructor(scope: Construct, id: string) {
super(scope, id);
// SSM パラメータストアから Web ACL の Arn を取得
const webAclArnParameter = new CrossRegionGetParameter(
this,
'WebAclArnParameter',
{
parameterName: 'web-acl-arn',
region: 'us-east-1',
}
);
// CloudFront Distribution の作成
new cloudfront.Distribution(this, 'Distribution', {
defaultBehavior: {
origin: new origins.HttpOrigin('classmethod.jp'),
},
// Web ACL を CloudFront Distribution に紐付け
webAclId: webAclArnParameter.parameterValue,
});
}
}
上記をデプロイします。
作成された CloudFront Distribution のセキュリティ設定にマネジメントコンソールからアクセスすると、Web ACL が紐付けられていることが確認できました。
トラブルシュート
Web ACL が us-east-1 リージョンに作成されていない場合
冒頭で述べた通り、CloudFront Distribution に紐付ける Web ACL は北部バージニア (us-east-1) リージョンに作成される必要があるため、us-east-1 リージョン以外で Web ACL を作成しようとすると次のようなエラーが発生します。
WebAcl Resource handler returned message: "Error reason: The scope is not valid., field: SCOPE_VALUE, parameter: CLOUDFRONT
おわりに
それぞれ異なるリージョンの CDK スタックで作成された AWS WAF Web ACL と CloudFront Distribution の紐付けができるのか試してみました。
作成に利用した CloudFormation スタックのリージョンは影響しないと想定はしていたのですが、実際に可能であると確認できて良かったです。
参考
以上