【アップデート】AWS WAFv2でAWSマネージドルールグループ内のルールのアクションが個別に変更できるようになりました

AWS WAFv2のマネージドルールの各ルールでBlock/Count以外のアクションが使用可能になりました!
2022.11.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

みなさん、こんにちは。

AWS事業本部コンサルティング部の芦沢(@ashi_ssan)です。

アップデートにより、AWS WAFv2でAWSマネージドルールグループ内のルールのアクションが個別に変更できるようになりました。

アップデートの発表がAWSのアップデートブログになっていなかったため、AWS公式ドキュメントのDocument historyから変更内容を紹介します。

※例によって日本語版のドキュメントは更新されていないので英語版のドキュメントから引用します。

・Change

Action overrides in rule groups

・Description

You can now override the actions of the rules in a rule group to any rule action setting. As with the prior Count action override, you can apply your overrides to all rules in a rule group and to individual rules.

引用:https://docs.aws.amazon.com/waf/latest/developerguide/doc-history.html

アップデート内容

これまでAWSマネージドルールグループ内のルールは、デフォルト設定であるBlock(検知したリクエストを遮断する)もしくはCount(検知しても遮断せずログにのみ記録する)のどちらかしか設定できませんでした。

今回のアップデートによって存在するすべてのルールアクション(Allow / Block / Count / CAPTCHA / Challenge)から選択して設定することができるようになりました1

マネジメントコンソール上からみてわかる変更点と、APIのJSONから見るとはじめてわかる変更点の2つがありますので、それぞれ紹介していきます。

マネジメントコンソールから見るアップデート

こちらがアップデート後のマネジメントコンソールです。

四角で囲っている箇所がアップデートされているところです。

以前は以下のようにトグル形式で切り替える形となっていました。


画像のようにChoose rule action overrideのトグルをクリックしてルール毎に個別にアクションを設定できます。空欄の状態であればデフォルトのアクションはBlockの設定になるはずです。

Override all rule actions欄にアクションを入力すると、すべてのルールに入力したアクションが補完されます。

Remove all overridesをクリックすると、現在入力しているルールがすべて削除されます。便利ですね。

API JSONから見るアップデート

CloudFormationを使っている方ならお馴染みの記法ですが、アップデートによりExcludedRulesだったステートメントをRuleActionOverridesに置き換えられるようになりました。

AWS公式ドキュメントから引用するとこのようになります。

以前は以下のようにExcludedRulesを使用してName欄で該当のルール名を指定することで、ルールのデフォルトのアクションであるBlockからCountへ切り替えることができました。

       "ManagedRuleGroupStatement": {
          "VendorName": "AWS",
          "Name": "AWSManagedRulesAdminProtectionRuleSet",
          "ExcludedRules": [
            {
              "Name": "AdminProtection_URIPATH"
            }
          ]

RuleActionOverridesでは、Nameの他にActionToUseという項目が増えアクション名を指定できるようになっています。例ではCountを指定していますがAllowやCAPTCHAなど他のアクションも指定できそうです。

       "ManagedRuleGroupStatement": {
          "VendorName": "AWS",
          "Name": "AWSManagedRulesAdminProtectionRuleSet",
          "RuleActionOverrides": [
            {
              "Name": "AdminProtection_URIPATH",
              "ActionToUse": {
                "Count": {}
              }
            }
          ]

今後はどちらを使えばいいのかについてですが、公式ドキュメントに以下とあるようにコンソール上のAPIの操作とCloudFormationでの操作に一貫性が生まれるRuleActionOverridesを利用した方がよさそうです。既存のExcludedRulesも一応そのまま使えるようです。

We recommend that you update all of your ExcludedRules settings in your JSON listings to RuleActionOverrides settings with the action set to Count. The API accepts either setting, but you'll get consistency in your JSON listings, between your console work and your API work, if you only use the new RuleActionOverrides setting. 引用:https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-rule-group-override-options.html

やってみた その1

試しに以前作成したCloudFormationテンプレートをもとにテンプレートを一部改変し、実行できるか検証してみます。

まずは基本的な記法は変更せず以下のテンプレートをそのまま実行してみました(ExcludedRulesを利用した記法)

テンプレートはこちらです(クリックで開きます)
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  Prefix:
    Type: String
    Default: test
    Description: "Fill in the name of the system name."
  Env:
    Type: String
    Default: develop
    Description: "Fill in the name of the environment."
  Scope:
    Type: String
    Default: REGIONAL
    AllowedValues:
      - REGIONAL
      - CLOUDFRONT
    Description: "Select in the scope of waf(REGIONAL or CLOUDFRONT)"
  # 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.
Resources:
# ------------------------------------------------------------#
# S3
# ------------------------------------------------------------#
  S3BucketForWaflog:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub aws-waf-logs-${Env}-${Prefix}-${AWS::AccountId}
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True
  S3BucketForAthenaQuery:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub athena-query-results-${Env}-${Prefix}-${AWS::AccountId}
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True
# ------------------------------------------------------------#
# WAF v2
# ------------------------------------------------------------#
  WebAcl:
    Type: AWS::WAFv2::WebACL
    Properties: 
      Name: !Sub ${Env}-${Prefix}-web-acl
      Scope: !Ref Scope
      DefaultAction:
        Allow: {}
      VisibilityConfig:
        CloudWatchMetricsEnabled: true
        SampledRequestsEnabled: true
        MetricName: !Sub ${Env}-${Prefix}-web-acl
      Rules:
        -
          Name: AWS-AWSManagedRulesCommonRuleSet
          Priority: 1
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
              ExcludedRules:
                - Name: NoUserAgent_HEADER
                - Name: UserAgent_BadBots_HEADER
                - Name: SizeRestrictions_QUERYSTRING
                - Name: SizeRestrictions_Cookie_HEADER
                - Name: SizeRestrictions_BODY
                - Name: SizeRestrictions_URIPATH
                - Name: EC2MetaDataSSRF_BODY
                - Name: EC2MetaDataSSRF_COOKIE
                - Name: EC2MetaDataSSRF_URIPATH
                - Name: EC2MetaDataSSRF_QUERYARGUMENTS
                - Name: GenericLFI_QUERYARGUMENTS
                - Name: GenericLFI_URIPATH
                - Name: GenericLFI_BODY
                - Name: RestrictedExtensions_URIPATH
                - Name: RestrictedExtensions_QUERYARGUMENTS
                - Name: GenericRFI_QUERYARGUMENTS
                - Name: GenericRFI_BODY
                - Name: GenericRFI_URIPATH
                - Name: CrossSiteScripting_COOKIE
                - Name: CrossSiteScripting_QUERYARGUMENTS
                - Name: CrossSiteScripting_BODY
                - Name: CrossSiteScripting_URIPATH
          OverrideAction:
            None: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            SampledRequestsEnabled: true
            MetricName: AWS-AWSManagedRulesCommonRuleSet
  WAFLogConfig:
    Type: AWS::WAFv2::LoggingConfiguration
    Properties:
      LogDestinationConfigs:
        - !GetAtt S3BucketForWaflog.Arn
      ResourceArn: !GetAtt WebAcl.Arn
  #WebACLAssociation:
  #  Type: AWS::WAFv2::WebACLAssociation
  #  Properties:
  #    ResourceArn: !Ref WebAclAssociationResourceArn
  #    WebACLArn: !GetAtt WebAcl.Arn

特に問題なく実行完了できました。

ルールを確認してみると、すべてのルールでUse action defined in the ruleと表記されていました。これはルールのデフォルトのアクションであるBlockとなっている場合の表記だと思われます。本来は全ルールに対してExcluded RuleでCountに指定しているのでこの状態はおかしいですね。

想定通りCountで指定できているのか表示どおりBlockとなっているかわからなかったため、試しにNoUserAgent_HEADERで検知させるように以下のようなリクエストを送信してみました。

curl -H 'User-Agent: ' http://[test_domain]

リクエストはブロックされませんでした。

> curl -H 'User-Agent: ' http://devio-stg-alb-1234567.ap-northeast-1.elb.amazonaws.com
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
	<head>
		<title>Test Page for the Apache HTTP Server</title>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<style type="text/css">
			/*<![CDATA[*/
			body {
(以下略)

Sampled Requestでも、Metric name: NoUserAgent_HEADERCOUNTと表示されていますね。

Editからルールの状態を確認してみます。

ExcludedRulesで指定したルールはすべてCountと設定されていました。

緑で囲った箇所で注記されているように「ExcludedRulesで指定されたルールは、RuleActionOverridesに自動置換されて設定される」とのことです。

Automatically converted the JSON for your Count rule action overrides from the old, “ExcludedRules” settings to the updated “RuleActionOverrides” settings. For details, download your web ACL as JSON and review the settings.

コンソール上と実際に設定に乖離があるのは、公式ドキュメントに記載されていたような「コンソール上のAPIの操作とCloudFormationでの操作に一貫性が」保たれていない状態になっていると想定します。検証結果からもRuleActionOverridesを利用するようにした方がよさそうであることがわかりました。

やってみた その2

続いて、先ほど利用したテンプレートのExcludedRulesをRuleActionOverridesに置き換えて実行してみます。

テンプレートはこちらです(クリックで開きます)
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  Prefix:
    Type: String
    Default: test
    Description: "Fill in the name of the system name."
  Env:
    Type: String
    Default: develop
    Description: "Fill in the name of the environment."
  Scope:
    Type: String
    Default: REGIONAL
    AllowedValues:
      - REGIONAL
      - CLOUDFRONT
    Description: "Select in the scope of waf(REGIONAL or CLOUDFRONT)"
  # 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.
Resources:
# ------------------------------------------------------------#
# S3
# ------------------------------------------------------------#
  S3BucketForWaflog:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub aws-waf-logs-${Env}-${Prefix}-${AWS::AccountId}
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True
  S3BucketForAthenaQuery:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub athena-query-results-${Env}-${Prefix}-${AWS::AccountId}
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True
# ------------------------------------------------------------#
# WAF v2
# ------------------------------------------------------------#
  WebAcl:
    Type: AWS::WAFv2::WebACL
    Properties: 
      Name: !Sub ${Env}-${Prefix}-web-acl
      Scope: !Ref Scope
      DefaultAction:
        Allow: {}
      VisibilityConfig:
        CloudWatchMetricsEnabled: true
        SampledRequestsEnabled: true
        MetricName: !Sub ${Env}-${Prefix}-web-acl
      Rules:
        -
          Name: AWS-AWSManagedRulesCommonRuleSet
          Priority: 1
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
              RuleActionOverrides:
              - Name: NoUserAgent_HEADER
                ActionToUse:
                  Count: {}
              - Name: UserAgent_BadBots_HEADER
                ActionToUse:
                  Count: {}
              - Name: SizeRestrictions_QUERYSTRING
                ActionToUse:
                  Count: {}
              - Name: SizeRestrictions_Cookie_HEADER
                ActionToUse:
                  Count: {}
              - Name: SizeRestrictions_BODY
                ActionToUse:
                  Count: {}
              - Name: SizeRestrictions_URIPATH
                ActionToUse:
                  Count: {}
              - Name: EC2MetaDataSSRF_BODY
                ActionToUse:
                  Count: {}
              - Name: EC2MetaDataSSRF_COOKIE
                ActionToUse:
                  Count: {}
              - Name: EC2MetaDataSSRF_URIPATH
                ActionToUse:
                  Count: {}
              - Name: EC2MetaDataSSRF_QUERYARGUMENTS
                ActionToUse:
                  Count: {}
              - Name: GenericLFI_QUERYARGUMENTS
                ActionToUse:
                  Count: {}
              - Name: GenericLFI_URIPATH
                ActionToUse:
                  Count: {}
              - Name: GenericLFI_BODY
                ActionToUse:
                  Count: {}
              - Name: RestrictedExtensions_URIPATH
                ActionToUse:
                  Count: {}
              - Name: RestrictedExtensions_QUERYARGUMENTS
                ActionToUse:
                  Count: {}
              - Name: GenericRFI_QUERYARGUMENTS
                ActionToUse:
                  Count: {}
              - Name: GenericRFI_BODY
                ActionToUse:
                  Count: {}
              - Name: GenericRFI_URIPATH
                ActionToUse:
                  Count: {}
              - Name: CrossSiteScripting_COOKIE
                ActionToUse:
                  Count: {}
              - Name: CrossSiteScripting_QUERYARGUMENTS
                ActionToUse:
                  Count: {}
              - Name: CrossSiteScripting_BODY
                ActionToUse:
                  Count: {}
              - Name: CrossSiteScripting_URIPATH
                ActionToUse:
                  Count: {}
          OverrideAction:
            None: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            SampledRequestsEnabled: true
            MetricName: AWS-AWSManagedRulesCommonRuleSet
  WAFLogConfig:
    Type: AWS::WAFv2::LoggingConfiguration
    Properties:
      LogDestinationConfigs:
        - !GetAtt S3BucketForWaflog.Arn
      ResourceArn: !GetAtt WebAcl.Arn
  #WebACLAssociation:
  #  Type: AWS::WAFv2::WebACLAssociation
  #  Properties:
  #    ResourceArn: !Ref WebAclAssociationResourceArn
  #    WebACLArn: !GetAtt WebAcl.Arn

結果はうまくいかず。。。

以下のハイライト箇所がうまく書けていないところまではわかったのですが、今回は断念。また再チャレンジしてみます。

      Rules:
        -
          Name: AWS-AWSManagedRulesCommonRuleSet
          Priority: 1
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
              RuleActionOverrides:
              - Name: NoUserAgent_HEADER
                ActionToUse:
                  Count: {}

WAFv2のAPIとしては対応しているのでできるはずです。

まとめ

  • AWSマネージドルールの各ルールのアクションを上書きして、すべてのルールアクション(Allow / Block / Count / CAPTCHA / Challenge)から選択して設定することができるようになった
  • APIとしては、これまであったExcludedRulesの置き換えとしてRuleActionOverridesが登場
    • CFn等でExcludedRulesは変わらず使用可能だが、コンソール上の操作ではRuleActionOverridesで設定される。
    • 一貫性の観点からExcludedRulesの利用は非推奨。
      • ExcludedRulesを利用するとコンソール上の表示ではデフォルト(Block)のように見えるが実際の設定はCountであるような状態になってしまう。

さいごに

アップデートによって、これまでBlockもしくはCountの指定しかできなかったAWSマネージドルールの各ルールのアクションがより柔軟に設定できるようになりました。

丸っとよしなにルール設定をしてくれるマネージドルールは便利ですが、細かい設定などの小回りが利かないところが欠点としてありました。 アップデートを機にAWSマネージドルールでCount、Block以外のCAPTCHAのようなアクションを利用することも可能になりました。

この記事が誰かに役に立てば幸いです。

以上、AWS事業本部コンサルティング部の芦沢(@ashi_ssan)でした。


  1. Challengeは新しくアップデートで追加されたルールアクションです、別途ブログにするつもりです。