複数のスタックから参照されるAWS WAFのWebACLを書いた (CDK)
はじめに
API Gatewayに対してAWS WAFを使ってみよう、と思い立ち、こちらのページを参考にしてCDKで構築してみました。
このページで紹介いただいているスタックは、WebACLの作成とリソースの紐付けを1つのスタック内に持っているのですが、
- リソースごとにWebACLを作るより1つのWebACLを複数のリソースと紐づける方が料金的に有利
- 複数のリソースでWebACLを使い回すことを考えると、WebACLと同じスタック内で紐付けを行う形をとると使い勝手が悪い
という事情により、WebACLを定義するWAF部分を1つのスタック、紐付けはWebACLを利用するリソースを含むスタック、という構成で使えるように変更してみました。
WAF部分
WebACLに加えてWebACLのARNを格納するパラメータストアを含むスタックにしています。
S3用のバケットは以下コードでは含めてないですが、必要に応じてお好きにどうぞ…
実際のコードから抜粋しているので、このままだと動かないかもですが、見て欲しいところは「WebAclのARNを格納するパラメータストア」というコメントが入っている箇所になります。
なお、スタックの上位側(binディレクトリに置いてあるコード)の方からパラメータストア名を渡して使う形にしています。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
type WafStackProps = cdk.StackProps & {
webAclArnParameterName: string;
};
export class WafStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: WafStackProps) {
super(scope, id, props)
// WAF Web ACL
const webAcl = new cdk.aws_wafv2.CfnWebACL(this, "wafV2WebAcl", {
defaultAction: { allow: {} },
scope: "REGIONAL",
visibilityConfig: {
cloudWatchMetricsEnabled: true,
sampledRequestsEnabled: true,
metricName: "wafV2WebAcl",
},
rules: [
{
name: "AWSManagedRulesCommonRuleSet",
priority: 1,
statement: {
managedRuleGroupStatement: {
vendorName: "AWS",
name: "AWSManagedRulesCommonRuleSet",
},
},
overrideAction: {
none: {}
},
visibilityConfig: {
cloudWatchMetricsEnabled: true,
sampledRequestsEnabled: true,
metricName: "AWSManagedRulesCommonRuleSet",
},
},
// 必要なルールセットはここに追加
],
});
// WebAclのARNを格納するパラメータストア
new cdk.aws_ssm.StringParameter(this, 'wafV2WebAclArnParameter', {
parameterName: props.webAclArnParameterName,
stringValue: webAcl.attrArn,
});
}
}
せっかくのCDKなのに、WAFはL1 constructsしか使えないのがしんどいですね。
WAFを使う側
せっかくCDKでWAF側を書いたのですが、現在使う側はSAMで書かれているAPI Gatewayのみの状況のため、SAMテンプレートの抜粋を記述しておきます。
テンプレートパラメータWafWebAclArn
に上のスタックで作成したパラメータストアの名前を指定する形になります。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Parameters:
WafWebAclArn:
Type: 'AWS::SSM::Parameter::Value<String>'
Resources:
ApiFunction:
Type: AWS::Serverless::Function
Properties:
# いろいろ書く
Api:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
EndpointConfiguration:
Type: REGIONAL
# いろいろ書く
WebAclAssociation:
Type: AWS::WAFv2::WebACLAssociation
Properties:
ResourceArn: !Sub 'arn:aws:apigateway:${AWS::Region}::/restapis/${Api}/stages/${Api.Stage}'
WebACLArn: !Ref WafWebAclArn
※初出時、DependsOn
でApi
を指定していましたが、これだとAWS::ApiGateway::RestApi
に依存するという記載なのでダメでした。AWS::ApiGateway::Stage
に依存させる必要があるため、ResourceArn
としてApi.Stage
を使用しています。(2023/08/02修正・追記)
使っているのはパラメータストアなので、CDKでもStringParameter.valueForStringParameter
を使って実現可能です。こちらのページをご参照ください。
Discussion