全リージョンでAWS Configの記録対象を「すべて」に設定し、IAMロールをサービスリンクロールに一括変更してみた
はじめに
AWS Security Hubのコントロール「Config.1」には、以下の3つのチェック項目があります。
- AWS Config(レコーダー)が有効化されているか
- 有効化されているすべてのSecurity Hubコントロールに対応するすべてのリソースタイプがConfigレコーダーで記録できているか
- AWS Configのサービスリンクロール(AWSServiceRoleForConfig)が設定されているか
今回は、2点目と3点目のチェックに失敗していると仮定し、全リージョンでAWS Configの記録対象を「すべて」に設定し、IAMロールをサービスリンクロール(AWSServiceRoleForConfig)に一括変更する方法をまとめました。
AWSベストプラクティス
Security Hubのコントロールだけでなく、AWS Configのベストプラクティスにおいても、記録対象は「すべて」に設定することが推奨されています。
また、AWSの公式ドキュメントでも、サービスリンクロールAWSServiceRoleForConfig
の利用が推奨されています。
推奨: サービスにリンクされたロールを使用する
サービスにリンクされたロールを使用することをお勧めします。サービスにリンクされたロールは、 が期待どおりに実行 AWS Config するために必要なすべてのアクセス許可を追加します。
https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/manual-setup.title.html
AWSServiceRoleForConfig
は、AWS Configのサービスリンクロールであり、AWSによって自動的に作成されるIAMロールです。
このロールは、AWSサービスが必要とする権限のみを持ち、ユーザーがIAMポリシーを直接修正することはできません。また、サービスリンクロールは通常、SCP(Service Control Policy)の影響を受けません。
そのため、基本的にはAWSServiceRoleForConfig
の利用を検討しましょう。
前提条件
IAMロールを変更するにあたり、事前に確認すべき点がいくつかあります。以下については対応した前提とします。
- Configの配信チャネルのS3バケットのバケットポリシーで、Configへのアクセスを許可していること
- 配信をAWS KMSキーで暗号化している場合、キーポリシーには、Configへのアクセスを許可していること(デフォルトはSSE-S3にて暗号化されますので、対応不要です。)
KMSキーを設定しているかどうかは、AWS CLIで確認できます。以下の例では、KMSキーで暗号化されていませんので対応不要です。
$ aws configservice describe-delivery-channels
{
"DeliveryChannels": [
{
"name": "default",
"s3BucketName": "cm-members-config-xxxx"
}
]
}
- 配信チャネルにSNSトピックを設定している場合、SNSトピックのアクセスポリシーにConfigへのアクセスを許可していること
一括変更する
AWS CloudShellを開き、サービスリンクロールを作成します。すでに作成済みの場合は、この手順を省略できます。
aws iam create-service-linked-role --aws-service-name config.amazonaws.com
以下の一括変更コマンドを実行します。
bash -c 'ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text); \
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); \
for region in $regions; do \
echo "Processing region: $region"; \
if [ "$region" == "ap-northeast-1" ]; then \
aws configservice put-configuration-recorder \
--region $region \
--configuration-recorder name=default,roleARN=$IAM_ROLE \
--recording-group allSupported=true,includeGlobalResourceTypes=true; \
else \
aws configservice put-configuration-recorder \
--region $region \
--configuration-recorder name=default,roleARN=$IAM_ROLE \
--recording-group allSupported=true,includeGlobalResourceTypes=false; \
fi; \
done'
Processing region: ap-south-1
Processing region: eu-north-1
Processing region: eu-west-3
Processing region: eu-west-2
Processing region: eu-west-1
Processing region: ap-northeast-3
Processing region: ap-northeast-2
Processing region: ap-northeast-1
Processing region: ca-central-1
Processing region: sa-east-1
Processing region: ap-southeast-1
Processing region: ap-southeast-2
Processing region: eu-central-1
Processing region: us-east-1
Processing region: us-east-2
Processing region: us-west-1
Processing region: us-west-2
コマンドでは、AWS Security Hubのコントロール[Config.1]が是正されるように、以下の3点を実行しています。
- サービスリンクロールであるAWSServiceRoleForConfigをConfigレコーダーのIAMロールとして指定する
- 東京リージョンでは、グローバルリソース (IAM リソースなど) を含め、すべてのリソースタイプを記録する
- 東京リージョン以外のリージョンでは、グローバルリソースを除くすべてのリソースタイプを記録する
確認
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"
# Configレコーダーの設定を取得
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
# Configレコーダーの記録戦略とIAMロールを取得
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")
# Configレコーダーの有効化ステータスを取得
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."
'
============================================================
Checking Config Recorder in Region: ap-northeast-2
============================================================
IAM Role ARN: arn:aws:iam::111111111111:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
Recording Status: true
Last Status: SUCCESS
Last Status Change Time: 2025-01-20T03:46:44.867000+00:00
All Supported: true
Include Global Resource Types: false
[OK] Region ap-northeast-2 recording strategy, IAM Role, and recording status are correct.
============================================================
Checking Config Recorder in Region: ap-northeast-1
============================================================
IAM Role ARN: arn:aws:iam::111111111111:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
Recording Status: true
Last Status: SUCCESS
Last Status Change Time: 2025-01-20T02:30:08.824000+00:00
All Supported: true
Include Global Resource Types: true
[OK] Region ap-northeast-1 recording strategy, IAM Role, and recording status are correct.
============================================================
Checking Config Recorder in Region: ca-central-1
============================================================
エラーが出力されなければ、設定は正しく適用されています。
ConfigのファイルがS3バケットに保存されているか確認
Configの設定変更後、約6時間後に設定変更内容がS3バケットに保存されます。
- S3バケットの保存先プレフィックス例:s3://cm-members-config-111111111111/AWSLogs/111111111111/Config/ap-northeast-2/2024/12/18/ConfigHistory/111111111111_Config_ap-northeast-2_ConfigHistory_AWS::Config::ConfigurationRecorder_20250117T054209Z_20250117T054634Z_1.json.gz
year、month、dayには、実施日を記載します。Configレコーダー変更日を指定してください。例では2025年1月1日を指定しています。
Config配信チャネルであるS3バケット名(cm-members-config-${ACCOUNT_ID}
)は各自で変更ください。
bash -c '
year="2025";
month="1";
day="1";
ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text);
bucket_name="cm-members-config-${ACCOUNT_ID}";
base_prefix="AWSLogs/${ACCOUNT_ID}/Config";
regions=$(aws ec2 describe-regions --query "Regions[].RegionName" --output text);
divider="============================================================";
echo -e "\n$divider";
echo "Starting S3 file check for ConfigurationRecorder files...";
echo "Account ID: $ACCOUNT_ID";
echo -e "$divider";
for region in $regions; do
prefix="${base_prefix}/${region}/${year}/${month}/${day}/ConfigHistory/";
result=$(aws s3api list-objects-v2 --bucket "$bucket_name" --prefix "$prefix" --query "Contents[].Key" --output text 2>/dev/null | tr "\t" "\n" | grep "AWS::Config::ConfigurationRecorder");
echo -e "$divider";
if [[ -z "$result" ]]; then
echo -e "\e[41m\e[97m[ERROR]\e[0m No ConfigurationRecorder file found in region: $region";
echo "Prefix: $prefix";
else
echo -e "\e[42m\e[97m[OK]\e[0m ConfigurationRecorder file(s) found in region: $region";
echo "Prefix: $prefix";
echo "File(s):";
echo "$result" | while read -r file; do
echo " - $(basename "$file")";
done;
fi;
done;
echo -e "$divider";
echo "S3 file check completed.";
'
============================================================
[OK] ConfigurationRecorder file(s) found in region: ap-northeast-2
Prefix: AWSLogs/111111111111/Config/ap-northeast-2/2025/1/17/ConfigHistory/
File(s):
- 111111111111_Config_ap-northeast-2_ConfigHistory_AWS::Config::ConfigurationRecorder_20250120T002706Z_20250120T012642Z_1.json.gz
============================================================
[OK] ConfigurationRecorder file(s) found in region: ap-northeast-1
Prefix: AWSLogs/111111111111/Config/ap-northeast-1/2025/1/17/ConfigHistory/
File(s):
- 111111111111_Config_ap-northeast-1_ConfigHistory_AWS::Config::ConfigurationRecorder_20250120T002706Z_20250120T022952Z_1.json.gz
============================================================
[OK] ConfigurationRecorder file(s) found in region: ca-central-1
エラーが出力されず、リージョンごとにファイルを確認できれば、保存が成功していることになります。
Configレコーダーの記録の失敗やS3バケットへの保存を失敗していないか確認
Configレコーダーの記録やS3バケットへの保存が失敗していないかを確認するために、以下のメトリクスをチェックします。
- ConfigHistoryExportFailed:S3バケットへの保存が失敗していないか
- ConfigurationRecorderInsufficientPermissionsFailure:レコーダーのIAMロールが原因で失敗したアクセス許可の試行回数
AWS CloudShellで以下のコマンドを実行し、エラーが発生していないことを確認します。
start_time
、end_time
、regions
は、各自の環境に合わせて変更してください。
bash -c '
metric_names=("ConfigurationRecorderInsufficientPermissionsFailure" "ConfigHistoryExportFailed");
namespace="AWS/Config";
# 時間指定か前日か
start_time=$(date -u -d "1 day ago" +"%Y-%m-%dT%H:%M:%SZ");
# start_time="2025-01-01T00:00:00Z";
# 時間指定か現在時刻か
end_time=$(date -u +"%Y-%m-%dT%H:%M:%SZ");
# end_time="2025-01-02T00:00:00Z";
# 全リージョンか特定のリージョン
regions=($(aws ec2 describe-regions --query "Regions[].RegionName" --output text));
# regions=("us-east-1" "ap-northeast-1");
for region in "${regions[@]}"; do
echo "Checking metrics in region: $region";
for metric_name in "${metric_names[@]}"; do
echo " Metric: $metric_name";
# ディメンションの指定(ConfigHistoryExportFailed には不要)
if [[ "$metric_name" == "ConfigurationRecorderInsufficientPermissionsFailure" ]]; then
dimensions="--dimensions Name=ResourceType,Value=All"
else
dimensions=""
fi
result=$(aws cloudwatch get-metric-statistics \
--namespace "$namespace" \
--metric-name "$metric_name" \
$dimensions \
--start-time "$start_time" \
--end-time "$end_time" \
--period 86400 \
--statistics Sum \
--region "$region" \
| jq ".Datapoints[] | select(.Sum > 0)");
if [[ -z "$result" ]]; then
echo -e " \e[42m\e[97m[OK]\e[0m No failures since $start_time";
else
echo -e " \e[41m\e[97m[ERROR]\e[0m Failures detected since $start_time";
echo " Details: $result";
fi;
done;
done
'
Checking metrics in region: us-east-1
Metric: ConfigurationRecorderInsufficientPermissionsFailure
[OK] No failures since 2025-01-19T07:22:36Z
Metric: ConfigHistoryExportFailed
[OK] No failures since 2025-01-19T07:22:36Z
Checking metrics in region: us-east-2
Metric: ConfigurationRecorderInsufficientPermissionsFailure
[OK] No failures since 2025-01-19T07:22:36Z
Metric: ConfigHistoryExportFailed
[OK] No failures since 2025-01-19T07:22:36Z
エラーが出力されなければ、失敗はしていないことになります。