AWS Configを利用してAWSリソースの設定情報を(ほぼ)網羅的に取得する

記事タイトルとURLをコピーする

こんにちは、久保です。

AWSを利用している場合、CloudFormationやTerraform, AWS CDKといったIaCツールを利用して構成管理されているケースも多いと思いますが、場合によってはAWSの実設定を参照し、設計などの想定した状態と乖離していないか?を確認したいこともあるかと思います。

この記事では、AWS Configを利用してAWSリソースの設定情報を網羅的に取得するシェルスクリプトをご紹介します。

概要

AWS ConfigはAWSリソースの設定情報を収集・保存・監査するサービスです。 AWS ConfigのAPIであるget-discovered-resource-countsを利用すると、AWS Configに記録されているリソースの種類と数を取得できます。

例:

$ aws configservice get-discovered-resource-counts
{
    "totalDiscoveredResources": 226,
    "resourceCounts": [
        {
            "resourceType": "AWS::Config::ResourceCompliance",
            "count": 71
        },
        {
            "resourceType": "AWS::IAM::Role",
            "count": 39
        },

また、batch-get-resource-configを利用することで、特定のリソースの詳細な設定情報を取得できます。

例えばS3であれば以下のような情報が取得できます。

{
    "baseConfigurationItems": [
        {
            "version": "1.3",
            "accountId": "123456789012", 
            "configurationItemCaptureTime": "2025-04-09T17:36:08.157000+09:00",
            "configurationItemStatus": "ResourceDiscovered",
            "configurationStateId": "1744187768157",
            "arn": "arn:aws:s3:::example-cloudtrail-logs-bucket",
            "resourceType": "AWS::S3::Bucket",
            "resourceId": "example-cloudtrail-logs-bucket",
            "resourceName": "example-cloudtrail-logs-bucket", 
            "awsRegion": "ap-northeast-1",
            "availabilityZone": "Regional",
            "resourceCreationTime": "2025-04-09T17:19:31+09:00",
            "configuration": "{\"name\":\"example-cloudtrail-logs-bucket\",\"owner\":{\"displayName\":null,\"id\":\"example-owner-id\"},\"creationDate\":\"2025-04-09T08:19:31.000Z\",\"region\":\"ap-northeast-1\"}",
            "supplementaryConfiguration": {
                "AccessControlList": "\"{\\\"grantSet\\\":null,\\\"grantList\\\":[{\\\"grantee\\\":{\\\"id\\\":\\\"example-owner-id\\\",\\\"displayName\\\":null},\\\"permission\\\":\\\"FullControl\\\"}],\\\"owner\\\":{\\\"displayName\\\":null,\\\"id\\\":\\\"example-owner-id\\\"},\\\"isRequesterCharged\\\":false}\"",
                "BucketAccelerateConfiguration": "{\"status\":null,\"isRequesterCharged\":false}",
                "BucketLifecycleConfiguration": "{\"rules\":[{\"id\":\"Example-LifeCycleRule\",\"status\":\"Enabled\",\"filter\":{},\"expirationInDays\":365,\"expiredObjectDeleteMarker\":false,\"noncurrentVersionExpiration\":{\"days\":365,\"newerNoncurrentVersions\":1}}],\"transitionDefaultMinimumObjectSize\":\"ALL_STORAGE_CLASSES_128K\"}",
                "BucketLoggingConfiguration": "{\"destinationBucketName\":null,\"logFilePrefix\":null,\"targetObjectKeyFormat\":null}",
                "BucketNotificationConfiguration": "{\"configurations\":{},\"eventBridgeConfiguration\":null}",
                "BucketPolicy": "{\"policyText\":\"{\\\"Version\\\":\\\"2012-10-17\\\",\\\"Statement\\\":[{\\\"Sid\\\":\\\"AWSCloudTrailAclCheck\\\",\\\"Effect\\\":\\\"Allow\\\",\\\"Principal\\\":{\\\"Service\\\":\\\"cloudtrail.amazonaws.com\\\"},\\\"Action\\\":\\\"s3:GetBucketAcl\\\",\\\"Resource\\\":\\\"arn:aws:s3:::example-cloudtrail-logs-bucket\\\",\\\"Condition\\\":{\\\"StringEquals\\\":{\\\"AWS:SourceArn\\\":\\\"arn:aws:cloudtrail:ap-northeast-1:123456789012:trail/Example-Trail\\\"}}},{\\\"Sid\\\":\\\"AWSCloudTrailWrite\\\",\\\"Effect\\\":\\\"Allow\\\",\\\"Principal\\\":{\\\"Service\\\":\\\"cloudtrail.amazonaws.com\\\"},\\\"Action\\\":\\\"s3:PutObject\\\",\\\"Resource\\\":\\\"arn:aws:s3:::example-cloudtrail-logs-bucket/AWSLogs/123456789012/*\\\",\\\"Condition\\\":{\\\"StringEquals\\\":{\\\"AWS:SourceArn\\\":\\\"arn:aws:cloudtrail:ap-northeast-1:123456789012:trail/Example-Trail\\\",\\\"s3:x-amz-acl\\\":\\\"bucket-owner-full-control\\\"}}}]}\"}",
                "BucketVersioningConfiguration": "{\"status\":\"Off\",\"isMfaDeleteEnabled\":null}",
                "IsRequesterPaysEnabled": "false",
                "PublicAccessBlockConfiguration": "{\"blockPublicAcls\":true,\"ignorePublicAcls\":true,\"blockPublicPolicy\":true,\"restrictPublicBuckets\":true}",
                "ServerSideEncryptionConfiguration": "{\"rules\":[{\"applyServerSideEncryptionByDefault\":{\"sseAlgorithm\":\"AES256\",\"kmsMasterKeyID\":null},\"bucketKeyEnabled\":false}]}"
            }
        },

取得できる情報のうち、"configuration"と"supplementaryConfiguration"が設定情報となりますので、それらのみを抽出し、利用しやすいようにjsonを整形します。

これらAPIを利用して、AWS Configに対応しているAWSサービスの設定情報をすべて取得し、以下の構成で出力するシェルスクリプトを掲載しています。

  • すべてのAWS Config対応サービスの設定を統合したjsonファイル
  • 各サービスごとの設定が記載されたjsonファイル群("configuration"と"supplementaryConfiguration"のみ)
  • 各サービスごとのAWS Configの生のレスポンス情報が記載されたjsonファイル群

AWS Configがサポートしているリソース

AWS Configがサポートしているリソースの一覧は公式ドキュメントで確認できます。

https://docs.aws.amazon.com/config/latest/developerguide/resource-config-reference.html

スクリプト

# AWS Configで取得可能なリソースの全設定情報をjson形式で取得するスクリプト
# TargetGroupはAWS Configで取得できないため個別にaws cliで取得
# 
# 実行例:
#   ./get-all-aws-resources.sh --region ap-northeast-1 --output-dir output
#
# オプション:
#   --region, -r: AWSリージョン名(デフォルト: ap-northeast-1)
#   --output-dir, -o: 出力ディレクトリ(デフォルト: output)
#
# 依存ツール: 
#   aws-cli, jq
#
# 出力先:
#   <output-dir>/config-per-services/ に各サービスごとにJSONファイルを作成
#   リソースが存在しないサービスのファイルは作成されない
#   all-aws-resources-<account id>-<region>.json というファイルにすべてのjsonファイルを連携した内容が出力される
# 
DEFAULT_AWS_REGION="ap-northeast-1"
DEFAULT_OUTPUT_DIR="output"
AWS_REGION="$DEFAULT_AWS_REGION"
OUTPUT_BASE_DIR="$DEFAULT_OUTPUT_DIR"
 
while [[ $# -gt 0 ]]; do
  case $1 in
    --region|-r)
      AWS_REGION="$2"
      shift 2
      ;;
    --output-dir|-o)
      OUTPUT_BASE_DIR="$2"
      shift 2
      ;;
    *)
      echo "不明なオプション: $1"
      echo "使用方法: $0 [--region|-r REGION] [--output-dir|-o DIR]"
      exit 1
      ;;
  esac
done
 
export AWS_REGION
export OUTPUTS_DIR="${OUTPUT_BASE_DIR}/config-per-services"
export RAW_OUTPUTS_DIR="${OUTPUTS_DIR}/raw"
 
mkdir -p "$OUTPUTS_DIR"
mkdir -p "$RAW_OUTPUTS_DIR"
 
echo "=== AWS リソース存在チェック開始 ==="
 
# 実際にリソースが存在するサービスタイプのみを取得
EXISTING_RESOURCE_TYPES=$(aws configservice get-discovered-resource-counts \
  | jq -r '.resourceCounts[] | select(.count > 0) | .resourceType')
 
EXISTING_COUNT=$(echo "$EXISTING_RESOURCE_TYPES" | grep -c .)
echo "リソースが存在するサービスタイプ数: $EXISTING_COUNT"
echo "対象サービス:"
echo "$EXISTING_RESOURCE_TYPES" | sed 's/^/  /'
echo ""
 
echo "=== リソース情報収集開始 ==="
 
echo "$EXISTING_RESOURCE_TYPES" | while IFS= read -r RESOURCE_TYPE; do
    OUTPUT_FILE_NAME="$(echo "$RESOURCE_TYPE" | sed 's/::/-/g').json"
    OUTPUT_FILE_RAW_NAME="raw_${OUTPUT_FILE_NAME}"
    OUTPUT_FILE="${OUTPUTS_DIR}/${OUTPUT_FILE_NAME}"
    OUTPUT_FILE_RAW="${RAW_OUTPUTS_DIR}/${OUTPUT_FILE_RAW_NAME}"
 
    echo "start: $RESOURCE_TYPE$OUTPUT_FILE"
 
    RESOURCE_IDS_TEXT=$(aws configservice list-discovered-resources --resource-type "${RESOURCE_TYPE}" | jq -r ".resourceIdentifiers[].resourceId // empty")
    
    RESOURCE_COUNT=0
    if [ -n "${RESOURCE_IDS_TEXT}" ]; then
      # wc -l は入力が空でも1を返すことがあるため、パイプで渡す前にチェック
      RESOURCE_COUNT=$(echo "${RESOURCE_IDS_TEXT}" | grep -c .) # 空行を除いてカウント
      if [ "${RESOURCE_COUNT}" -gt 0 ]; then
        # 100件ずつ取得
        i=0
        batch=()
        while IFS= read -r rid; do
          [ -z "$rid" ] && continue
          batch+=("{\"resourceType\":\"${RESOURCE_TYPE}\",\"resourceId\":\"$rid\"}")
          i=$((i+1))
          if [ $((i%100)) -eq 0 ]; then
            keys="[$(IFS=,; echo "${batch[*]}")]"
            aws configservice batch-get-resource-config --resource-keys "$keys" >> "$OUTPUT_FILE_RAW"
            batch=()
          fi
        done <<< "${RESOURCE_IDS_TEXT}"
        
        if [ ${#batch[@]} -gt 0 ]; then
          keys="[$(IFS=,; echo "${batch[*]}")]"
          aws configservice batch-get-resource-config --resource-keys "$keys" >> "$OUTPUT_FILE_RAW"
        fi
        
        JQ_FILTER=".baseConfigurationItems[] | {configuration: (.configuration | fromjson), supplementaryConfiguration: (.supplementaryConfiguration | with_entries(.value |= (try fromjson catch .)))}"
        jq "$JQ_FILTER" "$OUTPUT_FILE_RAW" | jq -s '.' > "$OUTPUT_FILE"
      fi
    fi
 
    echo "end:   $RESOURCE_TYPE, file: $OUTPUT_FILE, count: ${RESOURCE_COUNT}"
    echo "----------------------------------------"
  done
 
echo "=== AWS Config収集完了 ==="
 
# TargetGroupはAWS Configlist-discovered-resourcesで取得できないため個別に情報を取得
echo "=== TargetGroup情報収集開始 ==="
TARGET_GROUPS=$(aws elbv2 describe-target-groups 2>/dev/null)
if [ $? -eq 0 ] && [ "$(echo "$TARGET_GROUPS" | jq '.TargetGroups | length')" -gt 0 ]; then
  TARGET_GROUPS_JSON=$(echo "$TARGET_GROUPS" | jq '.TargetGroups')
 
  TARGET_GROUPS_OUT=()
  for tg_arn in $(echo "$TARGET_GROUPS" | jq -r '.TargetGroups[].TargetGroupArn'); do
    health=$(aws elbv2 describe-target-health --target-group-arn "$tg_arn")
    tags=$(aws elbv2 describe-tags --resource-arns "$tg_arn")
    attributes=$(aws elbv2 describe-target-group-attributes --target-group-arn "$tg_arn" 2>/dev/null || echo '{"Attributes":[]}')
    tg_info=$(jq -n --arg arn "$tg_arn" \
      --argjson health "$health" \
      --argjson tags "$tags" \
      --argjson attributes "$attributes" \
      '{target_group_arn: $arn, health: $health, tags: $tags, attributes: $attributes}')
    TARGET_GROUPS_OUT+=("$tg_info")
  done
 
  # TargetGroup本体情報も含めて出力
  jq -n --argjson groups "$TARGET_GROUPS_JSON" --argjson details "[${TARGET_GROUPS_OUT[*]}]" '{TargetGroups: $groups, Details: $details}' > "${OUTPUTS_DIR}/AWS-ElasticLoadBalancingV2-TargetGroup.json"
  echo "TargetGroup情報を収集しました"
else
  echo "TargetGroupが存在しないか、ELBv2サービスが利用できません。スキップします。"
fi
echo "=== TargetGroup情報収集完了 ==="
 
echo "=== 統合JSONファイル作成開始 ==="
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
ALL_JSON_FILE="${OUTPUT_BASE_DIR}/all-aws-resources-${ACCOUNT_ID}-${AWS_REGION}.json"
echo "{" > "$ALL_JSON_FILE"
first=1
for f in ${OUTPUTS_DIR}/AWS-*.json; do
  [ -e "$f" ] || continue
  key=$(basename "$f" .json)
  if [ $first -eq 0 ]; then
    echo "," >> "$ALL_JSON_FILE"
  fi
  echo -n "\"$key\": " >> "$ALL_JSON_FILE"
  cat "$f" >> "$ALL_JSON_FILE"
  first=0
done
echo "}" >> "$ALL_JSON_FILE"
 
echo ""
echo "=== 収集完了 ==="
echo "統合JSONファイル: $ALL_JSON_FILE"
echo "出力ディレクトリ: $OUTPUT_BASE_DIR"

利用方法

前提条件

必要なツール

  • AWS CLI: バージョン2.x推奨
  • jq: JSON処理用

AWS設定

  • AWS認証情報の設定(AWS CLI設定済み)
  • AWS Configサービスが有効になっていること
  • 必要なIAM権限:
  {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Action": [
          "config:GetDiscoveredResourceCounts",
          "config:ListDiscoveredResources", 
          "config:BatchGetResourceConfig",
          "sts:GetCallerIdentity",
          "elbv2:DescribeTargetGroups",
          "elbv2:DescribeTargetHealth",
          "elbv2:DescribeTags",
          "elbv2:DescribeTargetGroupAttributes"
        ],
        "Resource": "*"
      }
    ]
  }

使用方法

実行例

上記コードをget-all-aws-resources.shという名前で保存し、実行権限を付与してください。

実行例:

./get-all-aws-resources.sh --region ap-northeast-1 --output-dir output
./get-all-aws-resources.sh --region us-west-2 --output-dir custom-dir

指定可能なパラメータ

  • --region, -r (オプション): 対象とするAWSリージョン
    • デフォルト: ap-northeast-1
    • 例: us-east-1, eu-west-1, ap-southeast-1
  • --output-dir, -o (オプション): 出力先ディレクトリ
    • デフォルト: output
    • 例: --output-dir my-output

出力ファイル

ディレクトリ構造

output/
├── config-per-services/
│   ├── AWS-EC2-Instance.json              # EC2インスタンス情報
│   ├── AWS-S3-Bucket.json                 # S3バケット情報
│   └── raw/                               # 生の取得データ(デバッグ用)
│       ├── raw_AWS-EC2-Instance.json
│       └── raw_AWS-S3-Bucket.json
└── all-aws-resources-123456789012-ap-northeast-1.json  # 全リソース統合ファイル (AccountID-Region)

ファイル形式

統合ファイル

全サービスの情報を1つのJSONファイルにまとめたものです:

{
  "AWS-EC2-Instance": [...],
  "AWS-S3-Bucket": [...],
  "AWS-ElasticLoadBalancingV2-TargetGroup": {...}
}
個別サービスファイル

各AWSサービスのリソース情報が配列形式で格納されます:

[
  {
    "configuration": {
      "instanceId": "i-1234567890abcdef0",
      "instanceType": "t3.micro",
      "state": {
        "name": "running"
      }
      // ...その他の設定情報
    },
    "supplementaryConfiguration": {
      // 補足設定情報
    }
  }
]

実行例とログ出力

$ ./get-all-aws-resources.sh

=== AWS リソース存在チェック開始 ===
リソースが存在するサービスタイプ数: 5
対象サービス:
  AWS::EC2::Instance
  AWS::S3::Bucket
  AWS::EC2::SecurityGroup
  AWS::EC2::VPC
  AWS::IAM::Role

=== リソース情報収集開始 ===
start: AWS::EC2::Instance → outputs/AWS-EC2-Instance.json
end:   AWS::EC2::Instance, file: outputs/AWS-EC2-Instance.json, count: 2
----------------------------------------
start: AWS::S3::Bucket → outputs/AWS-S3-Bucket.json
end:   AWS::S3::Bucket, file: outputs/AWS-S3-Bucket.json, count: 3
----------------------------------------

=== AWS Config収集完了 ===

=== TargetGroup情報収集開始 ===
TargetGroupが存在しないか、ELBv2サービスが利用できません。スキップします。
=== TargetGroup情報収集完了 ===

=== 統合JSONファイル作成開始 ===

=== 収集完了 ===
統合JSONファイル: outputs/all-aws-resources-123456789012.json
出力ディレクトリ: outputs

出力の利用例

前述のスクリプトを実行すると、以下のような構成でjsonが出力されます。

output/
├── config-per-services/
│   ├── AWS-EC2-Instance.json              # EC2インスタンス情報
│   ├── AWS-S3-Bucket.json                 # S3バケット情報
│   └── raw/                               # 生の取得データ(デバッグ用)
│       ├── raw_AWS-EC2-Instance.json
│       └── raw_AWS-S3-Bucket.json
└── all-aws-resources-123456789012-ap-northeast-1.json  # 全リソース統合ファイル (AccountID-Region)

これらを参照することで、AWSリソースの設定情報を元にレビューやチェックを行う、といったことがやりやすくなります。

AWS利用の規模によっては統合ファイルがとても大きくなることが想定されますので、その場合はサービスごとにjsonファイルをご利用いただくことも可能です。

小規模な環境であれば全体を生成AIに渡してレビューしてもらうことも可能かと思います。
※生成AIのインプットにする場合はご利用の生成AIサービスで入力データが学習されない契約になっているかなど情報の扱いについては十分にご注意ください。

注意事項

  • AWSの構成情報が出力されますのでお取り扱いには十分ご注意ください
  • AWS Configサービスが有効になっている必要があります
  • AWS Configで記録対象となっていないリソースは取得されません
  • リージョン別の取得となるためリージョンごとに実行が必要です

おわりに

AWS CLIでも個別のAWS設定の取得は可能ですが、対象サービスは自身で洗い出し、describeコマンドもそれぞれ調査する必要があります。
AWS Configを利用することで利用しているほとんどのサービスをもれなく抽出することが可能となります。

機会があればご利用いただけますと幸いです。

久保 賢二(執筆記事の一覧)

猫とAWSが好きです。