✅
セキュリティ運用の第一歩:AWS Config 全リージョン有効化&確認自動化ガイド
AWS Config 全リージョン有効化手順まとめ
目的
- 全リージョンで AWS Config を有効化
- config-bucket-<アカウントID> という S3 バケットにログを集約
- Recorder, Delivery Channel, Recording の有効化を一括自動化
- 設定確認用スクリプトで整合性をチェック
前提条件(確認)
Configのサービスリンクロール(AWSServiceRoleForConfig)が事前に作成されていること。なければ以下で1回だけ作成可能です。
aws iam create-service-linked-role --aws-service-name config.amazonaws.com
バケットポリシー未設定でも Config は動作可能(ただし、必要に応じて後から設定可能)
🔧 1. 全自動セットアップスクリプト(Config 有効化含む)
以下のスクリプトは、Config 記録のための IAM ロールと S3 バケットがすでに存在する前提で動作します。
bash -c '
ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
S3_BUCKET_NAME="config-bucket-$ACCOUNT_ID"
IAM_ROLE="arn:aws:iam::$ACCOUNT_ID:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig"
REGIONS=$(aws ec2 describe-regions --query "Regions[].RegionName" --output text)
# S3バケットをap-northeast-1に作成(存在確認付き)
if ! aws s3api head-bucket --bucket "$S3_BUCKET_NAME" 2>/dev/null; then
echo "[+] Creating S3 bucket: $S3_BUCKET_NAME"
aws s3api create-bucket \
--bucket "$S3_BUCKET_NAME" \
--region ap-northeast-1 \
--create-bucket-configuration LocationConstraint=ap-northeast-1
else
echo "[✓] S3 bucket $S3_BUCKET_NAME already exists"
fi
# S3バケットポリシーを設定
echo "[+] Setting S3 bucket policy for AWS Config"
cat > /tmp/config-bucket-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AWSConfigBucketPermissionsCheck",
"Effect": "Allow",
"Principal": { "Service": "config.amazonaws.com" },
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::$S3_BUCKET_NAME",
"Condition": { "StringEquals": { "AWS:SourceAccount": "$ACCOUNT_ID" } }
},
{
"Sid": "AWSConfigBucketExistenceCheck",
"Effect": "Allow",
"Principal": { "Service": "config.amazonaws.com" },
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::$S3_BUCKET_NAME",
"Condition": { "StringEquals": { "AWS:SourceAccount": "$ACCOUNT_ID" } }
},
{
"Sid": "AWSConfigBucketDelivery",
"Effect": "Allow",
"Principal": { "Service": "config.amazonaws.com" },
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::$S3_BUCKET_NAME/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control",
"AWS:SourceAccount": "$ACCOUNT_ID"
}
}
}
]
}
EOF
aws s3api put-bucket-policy \
--bucket "$S3_BUCKET_NAME" \
--policy file:///tmp/config-bucket-policy.json
# バケットのパブリックアクセスをブロック
aws s3api put-public-access-block \
--bucket "$S3_BUCKET_NAME" \
--public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
# 各リージョンでConfigを設定
for REGION in $REGIONS; do
echo ""
echo "=== Processing region: $REGION ==="
# 既存名の列挙
EXISTING_REC_NAMES=$(aws configservice describe-configuration-recorders --region "$REGION" \
--query "ConfigurationRecorders[].name" --output text || true)
EXISTING_CH_NAMES=$(aws configservice describe-delivery-channels --region "$REGION" \
--query "DeliveryChannels[].name" --output text || true)
# 1) Recorder停止
if [ -n "${EXISTING_REC_NAMES:-}" ]; then
echo "[*] Stopping existing recorders: $EXISTING_REC_NAMES"
for NAME in $EXISTING_REC_NAMES; do
aws configservice stop-configuration-recorder \
--region "$REGION" \
--configuration-recorder-name "$NAME" || true
done
fi
# 2) Delivery Channel削除
if [ -n "${EXISTING_CH_NAMES:-}" ]; then
echo "[*] Deleting existing delivery channels: $EXISTING_CH_NAMES"
for NAME in $EXISTING_CH_NAMES; do
aws configservice delete-delivery-channel \
--region "$REGION" \
--delivery-channel-name "$NAME" || true
done
# 消失待ち
for i in {1..20}; do
cnt=$(aws configservice describe-delivery-channels --region "$REGION" \
--query "length(DeliveryChannels)" --output text)
[ "$cnt" = "0" ] && break
sleep 2
done
fi
# 3) Recorder削除
if [ -n "${EXISTING_REC_NAMES:-}" ]; then
echo "[*] Deleting existing recorders: $EXISTING_REC_NAMES"
for NAME in $EXISTING_REC_NAMES; do
aws configservice delete-configuration-recorder \
--region "$REGION" \
--configuration-recorder-name "$NAME" || true
done
# 消失待ち
for i in {1..20}; do
cnt=$(aws configservice describe-configuration-recorders --region "$REGION" \
--query "length(ConfigurationRecorders)" --output text)
[ "$cnt" = "0" ] && break
sleep 2
done
fi
# 4) includeGlobalResourceTypes は東京だけ true
if [ "$REGION" = "ap-northeast-1" ]; then
INCLUDE_GLOBAL=true
else
INCLUDE_GLOBAL=false
fi
# 5) Recorder作成
echo "[+] Creating configuration recorder in $REGION"
aws configservice put-configuration-recorder \
--region "$REGION" \
--configuration-recorder name=default,roleARN="$IAM_ROLE" \
--recording-group allSupported=true,includeGlobalResourceTypes=$INCLUDE_GLOBAL
# 6) Delivery Channel作成
echo "[+] Creating delivery channel in $REGION"
aws configservice put-delivery-channel \
--region "$REGION" \
--delivery-channel name=default,s3BucketName="$S3_BUCKET_NAME"
# 7) Recorder開始
echo "[+] Starting configuration recorder in $REGION"
aws configservice start-configuration-recorder \
--region "$REGION" \
--configuration-recorder-name default
echo "[✓] AWS Config setup completed for $REGION"
done
# 一時ファイルを削除
rm -f /tmp/config-bucket-policy.json
echo ""
echo "[✓] AWS Config setup completed for all regions"
'
✅ 2. 確認用スクリプト(Config設定の整合性検証)
参考:全リージョンでAWS Configの記録対象を「すべて」に設定し、IAMロールをサービスリンクロールに一括変更してみた
以下のスクリプトは、各リージョンの AWS Config が正しく設定・起動されているかを検証します。
bash -c '
ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
EXPECTED_IAM_ROLE="arn:aws:iam::$ACCOUNT_ID:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig"
regions=$(aws ec2 describe-regions --query "Regions[].RegionName" --output text)
divider="============================================================"
function print_error() { echo -e "\e[41m\e[97m[ERROR]\e[0m $1"; }
function print_success() { echo -e "\e[42m\e[97m[OK]\e[0m $1"; }
for region in $regions; do
echo -e "\n$divider"
echo "Checking Config Recorder in Region: $region"
echo -e "$divider"
recorder_status=$(aws configservice describe-configuration-recorders --region "$region" --query "ConfigurationRecorders[0]" --output json 2>/dev/null)
if [[ -z "$recorder_status" ]]; then
print_error "No Config Recorder found in region: $region"
continue
fi
all_supported=$(echo "$recorder_status" | jq -r ".recordingGroup.allSupported")
include_global=$(echo "$recorder_status" | jq -r ".recordingGroup.includeGlobalResourceTypes")
role_arn=$(echo "$recorder_status" | jq -r ".roleARN")
recorder_status_details=$(aws configservice describe-configuration-recorder-status --region "$region" --query "ConfigurationRecordersStatus[0]" --output json 2>/dev/null)
recording_status=$(echo "$recorder_status_details" | jq -r ".recording")
last_status=$(echo "$recorder_status_details" | jq -r ".lastStatus")
last_status_change_time=$(echo "$recorder_status_details" | jq -r ".lastStatusChangeTime")
echo "IAM Role ARN: $role_arn"
echo "Recording Status: $recording_status"
echo "Last Status: $last_status"
echo "Last Status Change Time: $last_status_change_time"
echo "All Supported: $all_supported"
echo "Include Global Resource Types: $include_global"
[[ "$recording_status" != "true" ]] && print_error "Recording Status is not enabled."
[[ "$last_status" != "SUCCESS" ]] && print_error "Last Status is not SUCCESS: $last_status"
[[ "$all_supported" != "true" ]] && print_error "allSupported is not true"
[[ "$role_arn" != "$EXPECTED_IAM_ROLE" ]] && print_error "IAM Role ARN does not match expected value"
if [[ "$region" == "ap-northeast-1" && "$include_global" != "true" ]]; then
print_error "includeGlobalResourceTypes is not true for Tokyo region."
elif [[ "$region" != "ap-northeast-1" && "$include_global" != "false" ]]; then
print_error "includeGlobalResourceTypes is not false for region: $region."
fi
if [[ "$recording_status" == "true" && "$all_supported" == "true" && "$role_arn" == "$EXPECTED_IAM_ROLE" && "$last_status" == "SUCCESS" &&
(("$region" == "ap-northeast-1" && "$include_global" == "true") || ("$region" != "ap-northeast-1" && "$include_global" == "false")) ]]; then
print_success "Region $region recording strategy, IAM Role, and recording status are correct."
else
print_error "Region $region recording strategy is incorrect."
fi
done
echo -e "\n$divider"
echo "Config Recorder check completed."
'
📌 備考
- バケットリージョンは ap-northeast-1 固定(日本リージョン)
- バケットポリシー は必要に応じて追加可能(未設定でも基本的な動作は可能)
Discussion