CloudFormation のパラメータに応じて AWS WAF のフィルタリング形式切り替えを実現させる

2022.07.28

こんにちは、森田です。

本記事では、AWS WAFv2 のフィルタリング形式(ブラックリスト・ホワイトリスト)切り替えを CloudFormation を使って実現する方法をご紹介します。

やりたいこと

  • 通常はブラックリスト形式でWAFを利用し、アプリケーションのメンテナンスに応じてホワイトリスト形式へ切り替える
  • CloudFormationのパラメータを変えることでブラックリスト・ホワイトリスト形式へ切り替えを行う

今回実現するブラックリスト形式(Default Action = ALLOW)の WAF でのIPアドレス制限については以下の記事が参考となります。

CloudFormationテンプレート

waf.yml

AWSTemplateFormatVersion: '2010-09-09'

Parameters:
  Prefix:
    Type: String
    Default: sample
    Description: "Fill in the name of the system name."
  Env:
    Type: String
    Default: dev
    Description: "Fill in the name of the environment."
  Scope:
    Type: String
    Default: REGIONAL
    AllowedValues: ["REGIONAL", "CLOUDFRONT"]
    Description: "Fill in the scope of waf"
  WebAclAssociationResourceArn:
    Type: String
    Default: "arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:loadbalancer/app/XXXXXXXXXXXX"
    Description: Enter RegionalResource(ALB,APIGateway,AppSync) ARN or CloudFront ARN to associate with WEBACL.
  MaintenanceMode:
    Type: String
    AllowedValues: ["on", "off"]
  BlackListIP:
    Description: IP list to deny access.
    Type: CommaDelimitedList
  WhiteListIP:
    Description: IP list to allow access.
    Type: CommaDelimitedList

Conditions:
  Maintenance: 
    !Equals ["on", !Ref MaintenanceMode]

Resources:
# ------------------------------------------------------------#
# WAF v2
# ------------------------------------------------------------#
  WebAcl:
    Type: AWS::WAFv2::WebACL
    Properties: 
      Name: !Sub ${Env}-${Prefix}-web-acl
      Scope: !Ref Scope
      DefaultAction:
        Allow: {}
      CustomResponseBodies:
        CustomResponseBody: 
          Content: "<h1>Blocked!!</h1>"
          ContentType: "TEXT_HTML"
      VisibilityConfig:
        CloudWatchMetricsEnabled: true
        SampledRequestsEnabled: true
        MetricName: !Sub ${Env}-${Prefix}-web-acl
      Rules:
        # ------------------------------------------------------------#
        # MaintenanceMode OFF Rule
        # ------------------------------------------------------------#
        - 
          Name: Blacklist-Rule
          Action:
              Block:
                CustomResponse:
                    ResponseCode: 403
                    CustomResponseBodyKey: CustomResponseBody
          Priority: 1
          Statement:
              IPSetReferenceStatement: 
                Arn: !GetAtt WAFv2BlackIPSet.Arn
          VisibilityConfig:
            CloudWatchMetricsEnabled: false
            MetricName: !Sub ${Env}-${Prefix}-All-Allow
            SampledRequestsEnabled: false
        # ------------------------------------------------------------#
        # MaintenanceMode ON Rule
        # ------------------------------------------------------------#
        - !If 
          - Maintenance
          - Name: Whitelist-Rule
            Action:
                Block:
                  CustomResponse:
                    ResponseCode: 403
                    CustomResponseBodyKey: CustomResponseBody
            Priority: 0
            Statement:
              NotStatement:
                Statement: 
                  IPSetReferenceStatement: 
                    Arn: !GetAtt WAFv2WhiteIPSet.Arn
            VisibilityConfig:
              CloudWatchMetricsEnabled: false
              MetricName: !Sub ${Env}-${Prefix}-Whitelist
              SampledRequestsEnabled: false
          - Ref: AWS::NoValue
          
  WebACLAssociation:
    Type: AWS::WAFv2::WebACLAssociation
    Properties:
      ResourceArn: !Ref WebAclAssociationResourceArn
      WebACLArn: !GetAtt WebAcl.Arn

  WAFv2WhiteIPSet:
    Type: "AWS::WAFv2::IPSet"
    Properties:
      Addresses: !Ref WhiteListIP
      IPAddressVersion: IPV4
      Name: !Sub ${Env}-${Prefix}-whitelist-ips
      Scope: !Ref Scope
  
  WAFv2BlackIPSet:
    Type: "AWS::WAFv2::IPSet"
    Properties:
      Addresses: !Ref BlackListIP
      IPAddressVersion: IPV4
      Name: !Sub ${Env}-${Prefix}-blacklist-ips
      Scope: !Ref Scope

このテンプレートのポイントとしては、76~94行目にて入力されたパラメータに応じてホワイトリスト形式のルールの作成を行います。

まず、入力されたMaintenanceModeのパラメータがonの場合は、ホワイトリストのルールがPriority: 0(最大の優先度)で作成されることになり、ホワイトリスト形式の振る舞いをするWAFとなります。

(ホワイトリストのルールが最優先して評価され、他のルールは評価されません。)

一方で、MaintenanceModeのパラメータがoffの場合は、58~72行目のルールが適用され、ブラックリスト形式の振る舞いをするWAFとなります。

(条件関数で AWS::NoValue が選択されることになり、ホワイトリストのルール作成されません。)

なお、MaintenanceModeのパラメータがoffの場合でルールの追加を行う場合が、ホワイトリストのルールでPriority: 0が使用されるため、それ以外のPriorityで指定する必要があります。

WAF の評価の動作を理解したい方はぜひ以下をご参照ください。

その他参考記事

芦沢さんの記事を多く参考にしております(ありがとうございます)