mazyu36の日記

某SIer所属のクラウドエンジニアのブログ

AWS CDKでAWS WAFのスコープダウンステートメントを実装する

はじめに

CDKでWAFのスコープダウンステートメントを実装することがよくあるが、書き方を忘れがちなのでメモとしてまとめておく。

2023/2現在だとaws_wafv2はL2 Constructがないため、L1 Constructを使用する。

aws-cdk-lib.aws_wafv2 module · AWS CDK

スコープダウンステートメントとは

一言で言えば「WAFの例外設定」である。

「特定のパスに該当するリクエストのみWAFの適用対象外とする」等がよく行われる。

docs.aws.amazon.com

実装方法

以下マネージドルールの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, /test2AWSManagedRulesCommonRuleSetの検査対象外とする実装例である。 以下ポイントを記載する。

スコープダウンステートメントの実装

         // スコープダウンステートメント
          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の検査対象になる。
  • statementsscopeDownStatementListで定義した、「パスが/test1に完全一致する場合のnotStatement(=パスが/test1ではない)」、「パスが/test2に完全一致する場合notStatement(=パスが/test2ではない)」。
  • 上記により「パスが/test1ではない」かつ「パスが/test2ではない」場合のみWAFの検査対象となる(パスが/test1および/test2は除外される)。

対象のパスが増える場合は、scopeDownStatementListのリストに追加を行えば良い。