はじめに
CDKでWAFのスコープダウンステートメントを実装することがよくあるが、書き方を忘れがちなのでメモとしてまとめておく。
2023/2現在だとaws_wafv2
はL2 Constructがないため、L1 Constructを使用する。
aws-cdk-lib.aws_wafv2 module · AWS CDK
スコープダウンステートメントとは
一言で言えば「WAFの例外設定」である。
「特定のパスに該当するリクエストのみWAFの適用対象外とする」等がよく行われる。
実装方法
以下マネージドルールのAWSManagedRulesCommonRuleSet
に対してスコープダウンステートメントを設定する例を示す。
// 検査対象外とするパスのリスト const scopeDownStatementList = [ // 検査対象外のパス1つめ { notStatement: { statement: { byteMatchStatement: { fieldToMatch: { uriPath: {} }, positionalConstraint: 'EXACTLY', textTransformations: [{ priority: 0, type: 'NONE', }], searchString: '/test1' } } } }, // 検査対象外のパス2つめ { notStatement: { statement: { byteMatchStatement: { fieldToMatch: { uriPath: {} }, positionalConstraint: 'EXACTLY', textTransformations: [{ priority: 0, type: 'NONE', } ], searchString: '/test2' } } } } ] // WebAclを作成 const webAcl = new wafv2.CfnWebACL(scope, 'WebAcl', { defaultAction: { allow: {} }, name: 'WebAclSample', scope: 'REGIONAL', visibilityConfig: { cloudWatchMetricsEnabled: true, metricName: 'WebAclSample', sampledRequestsEnabled: true, }, rules: [ { priority: 1, overrideAction: { none: {} }, visibilityConfig: { sampledRequestsEnabled: true, cloudWatchMetricsEnabled: true, metricName: 'AWS-AWSManagedRulesCommonRuleSet', }, name: 'AWSManagedRulesCommonRuleSet', statement: { managedRuleGroupStatement: { vendorName: 'AWS', name: 'AWSManagedRulesCommonRuleSet', // スコープダウンステートメント scopeDownStatement: { andStatement: { statements: [ // スプレッド構文で展開 ...scopeDownStatementList ] }, } } } } ] });
例は特定のパス/test1
, /test2
はAWSManagedRulesCommonRuleSet
の検査対象外とする実装例である。
以下ポイントを記載する。
スコープダウンステートメントの実装
// スコープダウンステートメント scopeDownStatement: { andStatement: { statements: [ // ここに追加 ] }, }
上記のscopeDownStatement.andStatement.statements
配下に条件(statement
)を記載しておけば、条件に合致したもののみをWAFの検査対象とすることができる。
ここに直接statement
を記載することもできるが、そうすると階層が深くなり可読性が落ちるため、別で宣言して代入することをよくやる。
スコープダウンステートメントの対象とするstatementをリストで宣言
const scopeDownStatementList = [ // 検査対象外のパス1つめ { notStatement: { statement: { byteMatchStatement: { fieldToMatch: { uriPath: {} }, positionalConstraint: 'EXACTLY', textTransformations: [{ priority: 0, type: 'NONE', }], searchString: '/test1' } } } }, // 検査対象外のパス2つめ { notStatement: { statement: { byteMatchStatement: { fieldToMatch: { uriPath: {} }, positionalConstraint: 'EXACTLY', textTransformations: [{ priority: 0, type: 'NONE', } ], searchString: '/test2' } } } } ]
例は/test1
および/test2
に対するリクエストをWAF検査対象外にしたい場合の条件(statement
)である。
「パスが/test1
に完全一致する場合のnotStatement(=パスが/test1
ではない)」、「パスが/test2
に完全一致する場合notStatement(=パスが/test2
ではない)」をリスト形式で記述している。
statementのリストをWebACLに代入
あとは作成したstatement
のリストをWebAclのscopeDownStatement
配下に代入すれば良い。この時リストをスプレッド構文で代入する形で記載するとスマートに記載できる
// スコープダウンステートメント scopeDownStatement: { andStatement: { statements: [ // スプレッド構文で展開 ...scopeDownStatementList ] }, }
これにより以下のようにパス指定でWAFの検査対象の除外が可能となる。
andStatement
配下のstatements
に全て一致する場合は、スコープダウンステートメントによりWAFの検査対象になる。statements
はscopeDownStatementList
で定義した、「パスが/test1
に完全一致する場合のnotStatement(=パスが/test1
ではない)」、「パスが/test2
に完全一致する場合notStatement(=パスが/test2
ではない)」。- 上記により「パスが
/test1
ではない」かつ「パスが/test2
ではない」場合のみWAFの検査対象となる(パスが/test1
および/test2
は除外される)。
対象のパスが増える場合は、scopeDownStatementList
のリストに追加を行えば良い。