AWSリソースのエビデンス取得用スクリプトを作成してみた: AWS WAF編

1 min read

はじめに

AWSリソースのエビデンス取得用スクリプトを作成してみたの第四弾となります。 AWS WAFでは複数リージョンで有効化するケースが存在すると思います。 その際に、各リージョンでのエビデンスを取得するのは大変なので、以下のようなスクリプトを作成しました。

※本スクリプトはCloudShell上でのみ動作確認をしています。

スクリプト内容

#!/bin/bash

# 全リージョンのリストを取得
regions=$(aws ec2 describe-regions --query 'Regions[].RegionName' --output text)

for region in $regions; do
    echo -e "\nリージョン: $region"
    
    # 各リージョンのフォルダを作成
    mkdir -p "$region"
    
    # 各リージョンのWeb ACLのリストを取得
    web_acl_arns=$(aws wafv2 list-web-acls --scope REGIONAL --region $region --query 'WebACLs[].ARN' --output text)

    if [ -z "$web_acl_arns" ]; then
        echo "  WAF Web ACLが存在しません"
    else
        echo "  Web ACLs:"
        for web_acl_arn in $web_acl_arns; do
            # Web ACLの詳細情報を取得
            web_acl=$(aws wafv2 get-web-acl --name $(echo $web_acl_arn | awk -F'/' '{print $(NF-1)}') --scope REGIONAL --id $(echo $web_acl_arn | awk -F'/' '{print $NF}') --region $region)

            echo "    - $web_acl_arn"
            echo "      名前: $(echo $web_acl | jq -r '.WebACL.Name')"
            echo "      ID: $(echo $web_acl | jq -r '.WebACL.Id')"
            echo "      説明: $(echo $web_acl | jq -r '.WebACL.Description')"
            
            # ルールのリストを表示
            rules=$(echo $web_acl | jq -r '.WebACL.Rules[] | .Name')
            if [ -z "$rules" ]; then
                echo "      ルールが存在しません"
            else
                echo "      ルール一覧:"
                for rule in $rules; do
                    echo "        - $rule"
                done
            fi

            # デフォルトアクションを表示
            default_action=$(echo $web_acl | jq -r '.WebACL.DefaultAction')
            echo "      デフォルトアクション: $(echo $default_action | jq -r 'keys[]')"

            # CAPTCHA設定を表示
            captcha_config=$(echo $web_acl | jq -r '.WebACL.CaptchaConfig')
            if [ "$captcha_config" != "null" ]; then
                captcha_immunity_time=$(echo $captcha_config | jq -r '.ImmunityTimeProperty.ImmunityTime')
                if [ "$captcha_immunity_time" == "null" ]; then
                    captcha_immunity_time=300
                fi
            else
                captcha_immunity_time=300
            fi
            echo "      CAPTCHA設定のイミュニティ時間: $captcha_immunity_time"

            # チャレンジ設定を表示
            challenge_config=$(echo $web_acl | jq -r '.WebACL.ChallengeConfig')
            if [ "$challenge_config" != "null" ]; then
                challenge_immunity_time=$(echo $challenge_config | jq -r '.ImmunityTimeProperty.ImmunityTime')
                if [ "$challenge_immunity_time" == "null" ]; then
                    challenge_immunity_time=300
                fi
            else
                challenge_immunity_time=300
            fi
            echo "      チャレンジ設定のイミュニティ時間: $challenge_immunity_time"
            
            # トークンドメインリストを表示
            token_domain_list=$(echo $web_acl | jq -r '.WebACL.TokenDomains[]?')
            if [ -z "$token_domain_list" ]; then
                echo "      トークンドメインリストが存在しません"
            else
                echo "      トークンドメインリスト:"
                for domain in $token_domain_list; do
                    echo "      - $domain"
                done
            fi

            # Web ACLに関連付けられたリソースの一覧を表示
            resource_types=("APPLICATION_LOAD_BALANCER" "API_GATEWAY" "APPSYNC" "COGNITO_USER_POOL" "APP_RUNNER_SERVICE" "VERIFIED_ACCESS_INSTANCE")

            echo "      関連付けられたリソース:"
            resource_found=false
            all_resources=()
            for resource_type in "${resource_types[@]}"; do
                associated_resources=$(aws wafv2 list-resources-for-web-acl --web-acl-arn $web_acl_arn --resource-type $resource_type --region $region --query 'ResourceArns[]' --output json)
                if [ "$(echo $associated_resources | jq '. | length')" -gt 0 ]; then
                    resource_found=true
                    all_resources+=" $resource_type\n$(echo $associated_resources | jq -c '.[]')\n\n"
                    echo "        $resource_type:"
                    for resource in $(echo $associated_resources | jq -r '.[]'); do
                        echo "          - $resource:"
                    done
                fi
            done

            if [ "$resource_found" = false ]; then
                echo "      関連付けられたリソースが存在しません"
            fi
            
            # ログ記録設定を取得
            logging_configuration=$(aws wafv2 get-logging-configuration --resource-arn $web_acl_arn --region $region)
            
            if [ -z "$logging_configuration" ]; then
                echo "      ログ記録設定が存在しません"
            else
                echo "      ログ記録設定の有効化状況: $(echo $logging_configuration | jq -r '.LoggingConfiguration.ResourceArn')"
                echo "        ログの送信先: $(echo $logging_configuration | jq -r '.LoggingConfiguration.LogDestinationConfigs[]?')"
                echo "        除外フィールド: $(echo $logging_configuration | jq -r '.LoggingConfiguration.RedactedFields[]?')"
            fi

            # Sampled Requestsの有効化設定を取得
            sampled_requests_enabled=$(echo $web_acl | jq -r '.WebACL.VisibilityConfig.SampledRequestsEnabled')
            echo "      Sampled Requestsの有効化設定: $sampled_requests_enabled"
            
            # CloudWatch Metricsのルール名とメトリクス名の対応を表示
            echo "      CloudWatch Metricsのルール名とメトリクス名の対応:"
            echo $web_acl | jq -r '.WebACL.Rules[] | "        - ルール名: \(.Name), メトリクス名: \(.VisibilityConfig.MetricName)"'
            
            echo -e "\n"

            # ファイル出力
            echo "$web_acl" > "$region/get-web-acl_$(echo $web_acl_arn | awk -F'/' '{print $(NF-1)}').json"
            echo -e "$all_resources" >  "$region/list-resources-for-web-acl_$(echo $web_acl_arn | awk -F'/' '{print $(NF-1)}').json"
            echo "$logging_configuration" > "$region/get-logging-configuration_$(echo $web_acl_arn | awk -F'/' '{print $(NF-1)}').json"
        done
    fi

    # 各リージョンのIPセットのリストを取得
    ip_sets=$(aws wafv2 list-ip-sets --scope REGIONAL --region $region --query 'IPSets[].ARN' --output text)
    if [ -z "$ip_sets" ];then
        echo "  IPセットが存在しません"
    else
        echo "  IPセット:"
        for ip_set in $ip_sets; do
            echo "    - $ip_set"
            ip_set_details=$(aws wafv2 get-ip-set --name $(echo $ip_set | awk -F'/' '{print $(NF-1)}') --scope REGIONAL --id $(echo $ip_set | awk -F'/' '{print $NF}') --region $region)
            echo "      名前: $(echo $ip_set_details | jq -r '.IPSet.Name')"
            echo "      説明: $(echo $ip_set_details | jq -r '.IPSet.Description')"
            echo "      IPのバージョン: $(echo $ip_set_details | jq -r '.IPSet.IPAddressVersion')"
            echo "      IPのリスト: $(echo $ip_set_details | jq -r '.IPSet.Addresses | join(", ")')"

            echo -e "\n"

            # ファイル出力
            echo "$ip_set_details" > "$region/get-ip-set_$(echo $ip_set | awk -F'/' '{print $(NF-1)}').json"
        done
    fi

    # 各リージョンの正規表現パターンセットのリストを取得
    regex_pattern_sets=$(aws wafv2 list-regex-pattern-sets --scope REGIONAL --region $region --query 'RegexPatternSets[].ARN' --output text)
    if [ -z "$regex_pattern_sets" ];then
        echo "  正規表現パターンセットが存在しません"
    else
        echo "  正規表現パターンセット:"
        for regex_pattern_set in $regex_pattern_sets; do
            echo "    - $regex_pattern_set"
            regex_pattern_set_details=$(aws wafv2 get-regex-pattern-set --name $(echo $regex_pattern_set | awk -F'/' '{print $(NF-1)}') --scope REGIONAL --id $(echo $regex_pattern_set | awk -F'/' '{print $NF}') --region $region)
            echo "      名前: $(echo $regex_pattern_set_details | jq -r '.RegexPatternSet.Name')"
            echo "      説明: $(echo $regex_pattern_set_details | jq -r '.RegexPatternSet.Description')"
            echo "      正規表現パターンのリスト:"
            echo $regex_pattern_set_details | jq -r '.RegexPatternSet.RegularExpressionList[] | "        - \(.RegexString)"'

            echo -e "\n"
            
            # ファイル出力
            echo "$regex_pattern_set_details" > "$region/get-regex-pattern-set_$(echo $regex_pattern_set | awk -F'/' '{print $(NF-1)}').json"
        done
    fi

    # 各リージョンのルールグループのリストを取得
    rule_groups=$(aws wafv2 list-rule-groups --scope REGIONAL --region $region --query 'RuleGroups[].ARN' --output text)
    if [ -z "$rule_groups" ];then
        echo "  ルールグループが存在しません"
    else
        echo "  ルールグループ:"
        for rule_group in $rule_groups; do
            echo "    - $rule_group"
            rule_group_details=$(aws wafv2 get-rule-group --name $(echo $rule_group | awk -F'/' '{print $(NF-1)}') --scope REGIONAL --id $(echo $rule_group | awk -F'/' '{print $NF}') --region $region)
            echo "      名前: $(echo $rule_group_details | jq -r '.RuleGroup.Name')"
            echo "      説明: $(echo $rule_group_details | jq -r '.RuleGroup.Description')"
            echo "      キャパシティ: $(echo $rule_group_details | jq -r '.RuleGroup.Capacity')"
            echo "      ルールのリスト:"
            echo $rule_group_details | jq -r '.RuleGroup.Rules[] | "        - \(.Name)"'

            echo -e "\n"

            # ファイル出力
            echo "$rule_group_details" > "$region/get-rule-group_$(echo $rule_group | awk -F'/' '{print $(NF-1)}').json"
        done
    fi
done

使用方法

以下のコマンドを実行し、スクリプトを実行してください。

sh get-awswaf.sh

スクリプト実行ログをファイルとして保存する場合はリダイレクトを使用してください。

sh get-awswaf.sh > get-awswaf.logging

出力結果

標準出力は以下のように表示されます。一目で設定値がわかるようになっています。


リージョン: ap-northeast-1
  Web ACLs:
    - arn:aws:wafv2:ap-northeast-1:XXXXXXXXXXXX:regional/webacl/XXXXXXXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXX
      名前: XXXXXXXXXXXXXXXXXXXXXXXXX
      ID: XXXXXXXXXXXXXXXXXXXXXXXXX
      説明: 
      ルール一覧:
        - XXXXXXXXXXXXXXXXXXXXXXXXX
      デフォルトアクション: Allow
      CAPTCHA設定のイミュニティ時間: 300
      チャレンジ設定のイミュニティ時間: 300
      トークンドメインリストが存在しません
      関連付けられたリソースが存在しません
      ログ記録設定の有効化状況: arn:aws:wafv2:ap-northeast-1:XXXXXXXXXXXX:regional/webacl/XXXXXXXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXX
        ログの送信先: arn:aws:s3:::XXXXXXXXXXXXXXXXXXXXXXXXX
        除外フィールド: 
      Sampled Requestsの有効化設定: true
      CloudWatch Metricsのルール名とメトリクス名の対応:
        - ルール名: XXXXXXXXXXXXXXXXXXXXXXXXX, メトリクス名: XXXXXXXXXXXXXXXXXXXXXXXXX


~~~省略~~~


  IPセット:
    - arn:aws:wafv2:ap-northeast-1:XXXXXXXXXXXX:regional/ipset/XXXXXXXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXX
      名前: XXXXXXXXXXXXXXXXXXXXXXXXX
      説明: XXXXXXXXXX
      IPのバージョン: IPV4
      IPのリスト: XX.XX.XXX.XXX/XX, XXX.XXX.XX.XXX/XX


~~~省略~~~


  正規表現パターンセット:
    - arn:aws:wafv2:ap-northeast-1:XXXXXXXXXXXX:regional/regexpatternset/XXXXXXXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXX
      名前: XXXXXXXXXXXXXXXXXXXXXXXXX
      説明: 
      正規表現パターンのリスト:
        - .*\.(css|pdf|jpg|gif|txt|png|ico|js|jpeg|jpe)


~~~省略~~~


  ルールグループ:
    - arn:aws:wafv2:ap-northeast-1:XXXXXXXXXXXX:regional/rulegroup/XXXXXXXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXX
      名前: XXXXXXXXXXXXXXXXXXXXXXXXX
      説明: XXXXXXXXXXXXXXXXXXXXXXXXX
      キャパシティ: 100
      ルールのリスト:
        - XXXXXXXXXXXXXXXXXXXXXXXXX


~~~省略~~~

以下のようにリージョン毎にディレクトリが生成されます。

[cloudshell-user@ip-XX-XXX-XXX-XXX ~]$ ls -l
total 136
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:55 ap-northeast-1
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:55 ap-northeast-2
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:55 ap-northeast-3
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:54 ap-south-1
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:55 ap-southeast-1
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:56 ap-southeast-2
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:55 ca-central-1
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:56 eu-central-1
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:54 eu-north-1
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:54 eu-west-1
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:54 eu-west-2
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:54 eu-west-3
-rw-r--r--. 1 cloudshell-user cloudshell-user 20617 Jun  7 01:56 get-awswaf.log
-rw-r--r--. 1 cloudshell-user cloudshell-user  9535 Jun  7 01:54 get-awswaf.sh
-rw-r--r--. 1 cloudshell-user cloudshell-user 29389 Jun  7 02:00 get-awswaf.zip
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:55 sa-east-1
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:56 us-east-1
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:56 us-east-2
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:56 us-west-1
drwxr-xr-x. 2 cloudshell-user cloudshell-user  4096 Jun  7 01:56 us-west-2
[cloudshell-user@ip-XX-XXX-XXX-XXX ~]$ 

以下のようにリージョンディレクトリ内にJSONが保存されます。

[cloudshell-user@ip-XX-XXX-XXX-XXX ~]$ ls -l ap-northeast-1/
total 160
-rw-r--r--. 1 cloudshell-user cloudshell-user  3567 Jun  7 01:55 get-ip-set_XXXXXXXXXXXXXXXXXXXXXXXXX.json
-rw-r--r--. 1 cloudshell-user cloudshell-user   424 Jun  7 01:55 get-logging-configuration_XXXXXXXXXXXXXXXXXXXXXXXXX.json
-rw-r--r--. 1 cloudshell-user cloudshell-user   666 Jun  7 01:55 get-regex-pattern-set_XXXXXXXXXXXXXXXXXXXXXXXXX.json
-rw-r--r--. 1 cloudshell-user cloudshell-user  2712 Jun  7 01:55 get-rule-group_XXXXXXXXXXXXXXXXXXXXXXXXX.json
-rw-r--r--. 1 cloudshell-user cloudshell-user  5493 Jun  7 01:55 get-web-acl_XXXXXXXXXXXXXXXXXXXXXXXXX.json
-rw-r--r--. 1 cloudshell-user cloudshell-user     1 Jun  7 01:55 list-resources-for-web-acl_XXXXXXXXXXXXXXXXXXXXXXXXX.json
[cloudshell-user@ip-XX-XXX-XXX-XXX ~]$