AWS Configの設定を変更するときは料金に気をつけよう！ー 調査〜設定の見直し方まで ー

# 概要

弊社では現在、AWS Security Hubのスコア改善に取り組んでいます。
その中で、AWS Configの設定変更を行いましたが、想定よりも金額が上がってしまうことになりました。

今回は、対象のSecurity Hubコントロールの対応方法と、金額が上がった場合の調査・設定の見直し方をまとめます。


# AWS Configとは

AWSリソースの設定変更履歴を記録し、あらかじめ設定したルールに違反してないかチェックすることができるサービスです。

Security Hubと連携することで、[**CIS AWS Foundations Benchmark v3.0.0**](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/cis-aws-foundations-benchmark.html)や[**AWS 基礎セキュリティのベストプラクティス v1.0.0**](https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/fsbp-standard.html)などに準拠しているかを確認できます。


# [Config.1] AWS Config should be enabled and use the service-linked role for resource recordingへの対応

このコントロールには、以下3つのチェック観点があります。

1. AWS Config(レコーダー)が有効化されているか
2. 有効化されているすべてのSecurity Hubコントロールに対応するすべてのリソースタイプがConfigレコーダーで記録できているか
3. AWS Configのサービスリンクロール(AWSServiceRoleForConfig)が作成されているか

## AWS Configの設定について

設定項目は大まかに3つ

- 記録対象のAWSリソース
- 設定変更の記録頻度（日次 or 連続）
- 記録に用いるロール（サービスリンクロール or Classmethod管理ロールが基本）

Classmethod経由でAWSを利用する場合は、IAMロールを`cm-config-role-all-regions`から変更してはいけないようです。
しかし、その場合3つ目のチェック項目に通らないので、このコントロールが常に失敗してしまいます。そこで、後述の回避策を実施します。

> CMメンバーズに加入している場合、初期設定で AWS Config の IAM ロールにカスタムロール「cm-config-role-all-regions」を設定します。
この IAM ロール「cm-config-role-all-regions」は弊社管理のロールであるため、変更を実施しないようお願いいたします。そしてこの状態だと、コントロールの3つ目のチェック観点に違反してしまうため、このコントロールは常に失敗となります。

https://dev.classmethod.jp/articles/securityhub-fsbp-remediation-config-1/

# 設定変更

当初の設定では2・3について準拠できていなかったので、修正していきます。

## 2. 有効化されているすべてのSecurity Hubコントロールに対応するすべてのリソースタイプがConfigレコーダーで記録できているか

元々は、「特定のリソースタイプ」が設定されていました。

これは、指定したリソースのみの設定変更を記録するもので、記録対象を絞り料金を抑えることができます。
例えば、S3 Bucketのみ設定した場合は、これに関する変更記録のみ記録します。

一方で、Security Hubコントロールでは全てのリソースタイプの記録が推奨されているため、修正が必要です。

以下の画像のように「**カスタマイズ可能なオーバーライドのあるすべてのリソースタイプ**」を設定します。

![スクリーンショット 2025-03-12 9.08.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475547/ddd7b3cd-9d20-46b5-9a2e-6d1285e6d145.png)

### 記録頻度

以下の2パターンがあり、現在は「継続的な記録」が設定されています。
料金は以下の通りで、設定変更が1日4回以上であれば定期的な記録の方が安くなります。

まずはデフォルト設定通り「**継続的な記録**」を選択し、料金の推移を見て判断します。

対象リソースが増えるため料金が上がる可能性はありますが、そもそもリソースがないAWSサービスの場合「設定変更がない→記録されない」ため、リソースがないのに料金が発生することはなさそうです。

|  | 料金 |
| --- | --- |
| 連続的な記録（継続的な記録） | USD 0.003 |
| 定期的な記録（日次記録） | USD 0.012 |

- 継続的な記録

> 連続的な記録では、変更が発生するたびに設定項目が配信されます。これはセキュリティとコンプライアンスの要件を満たし、すべての設定変更を追跡するのに役立ちます。
> 
- 日次記録

> 変更が発生した場合にのみ 24 時間に 1 回設定データが配信されるため、運用計画や監査などのユースケースに役立つ場合があります。
>


## 3. AWS Configのサービスリンクロール(AWSServiceRoleForConfig)が作成されているか

前述の通りIAMロールを`cm-config-role-all-regions`から変更できない場合は、以下のチェック回避策が必要となります。

[Config.1]のカスタムパラメーター(includeConfigServiceLinkedRoleCheck)を`true`→`false`に変更します。
これによって、3つ目のチェック観点を無効化することができます。


![スクリーンショット 2025-02-06 11.24.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475547/a93c9565-7348-4e6f-aca4-b662e6a26870.png)

> Config.1は、AWS Configが有効かどうかをチェックし、サービスリンクされたロールを使用し、有効なコントロールのリソースを記録する。 Security Hubは、includeConfigServiceLinkedRoleCheckというカスタムコントロールパラメータを追加しました。 このパラメータをfalseに設定することで、AWS Configがサービスリンクされたロールを使用するかどうかのチェックをオプトアウトできます。
> 
> 
> https://docs.aws.amazon.com/securityhub/latest/userguide/controls-change-log.html
>

Security Hub > セキュリティ基準 > CIS AWS Foundations Benchmark v3.0.0 > AWS Config should be enabled and use the service-linked role for resource recording > パラメータタブ > 設定 から以下のように設定します。

![スクリーンショット 2025-03-12 9.26.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475547/a8cc0089-7516-46e4-bcb9-f0272771e354.png)


# テスト環境で料金の様子見

テスト環境で料金の様子見をした結果、設定変更後は一時的に料金が上昇し、その後元に戻りました。
これは、今まで記録されていなかったAWSリソースに対しての記録が実施されて料金が上がり、その後リソースの設定変更がないため元に戻ったと思われます。

本番環境では、過去にAWS Configを有効化した際も同様の動きをしていた記録がありました。
したがって、今回の変更を本番環境に適用した場合も最終的に料金が落ち着くと予想していました。

# 想定より料金が高い...？？？

以下の画像は本番環境でのAWS Configの料金推移です。
2/12に設定変更を行なってから料金が一気に上昇し、調査と修正を繰り返して2/27以降は料金が元通りになりました。


![スクリーンショット 2025-03-12 10.05.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475547/8f3b74ab-0329-4ea8-853b-91e624ae8e77.png)


# 原因

原因の大部分は以下の2点でした。

- インスタンスを使用するaws BatchやEC2（spot）などが動くたびに、ENIやEBSの作成・アタッチ等が発生し、それらに関わる設定変更が全て記録されていたこと
- 全ての変更に対して、AWS::Config::ResourceCompliance（設定がルールに準拠しているかのチェック）が記録されていたこと


# 原因調査

どのように原因を特定したかを説明していきます。

## Athenaで確認

まずは、Athenaを使って、リソースタイプや、リソースIDごとのAWS Configによる記録回数を調べました。

最初にAthenaのクエリエディタにて以下のクエリを実行し、テーブルを作成します。
バケット名やアカウントIDは自身のものに差し替えてください。

```sql
CREATE EXTERNAL TABLE `awsconfig` (         
         fileversion string,
         configSnapshotId string,
         configurationitems ARRAY < STRUCT < configurationItemVersion : STRING,
         configurationItemCaptureTime : STRING,
         configurationStateId : BIGINT,
         awsAccountId : STRING,
         configurationItemStatus : STRING,
         resourceType : STRING,
         resourceId : STRING,
         resourceName : STRING,
         ARN : STRING,
         awsRegion : STRING,
         availabilityZone : STRING,
         configurationStateMd5Hash : STRING,
         resourceCreationTime : STRING > >
)
PARTITIONED BY (`year` string,`month` string,`day` string)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
LOCATION 's3://BUCKET-NAME/AWSLogs/ACCOUNT-ID/Config/REGION/'
TBLPROPERTIES (
  'projection.enabled'='true',
  'projection.year.interval'='1',
  'projection.year.range'='2021,2121',
  'projection.year.type'='integer',
  'projection.month.interval'='1',
  'projection.month.range'='1,12',
  'projection.month.type'='integer',
  'projection.day.interval'='1',
  'projection.day.range'='1,31',
  'projection.day.type'='integer',
  'storage.location.template'='s3://BUCKET-NAME/AWSLogs/ACCOUNT-ID/Config/REGION/${year}/${month}/${day}/ConfigHistory/')

```


次に、以下のようにリソースIDごとに記録回数を取得します。

```sql
SELECT configurationItem.resourceType,           
         configurationItem.resourceId,
         COUNT(configurationItem.resourceId) AS NumberOfChanges
FROM default.awsconfig
CROSS JOIN UNNEST(configurationitems) AS t(configurationItem)
WHERE "$path" LIKE '%ConfigHistory%'
        AND configurationItem.configurationItemCaptureTime >= '2025-02-01T%'
        AND configurationItem.configurationItemCaptureTime <= '2025-02-28T%'
GROUP BY  configurationItem.resourceType, configurationItem.resourceId
ORDER BY  NumberOfChanges DESC
```

## CloudWatchでも確認できた

CloudWatchでも確認できました。
方法は、CloudWatch > 全てのメトリクス に移動し、
1. 参照タブでメトリクス名「**ConfigurationItemsRecorded**」で絞り込み
2. グラフ化したメトリクスタブ > 統計で「**合計**」を指定
3. オプションタブ > ウィジェットタイプで「**棒**」や「**円**」を指定

これで、以下の画像のようにグラフ化して確認することができます。

![スクリーンショット 2025-03-12 10.33.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475547/1b1eac66-87ea-4b1e-b05b-fecc342d0f76.png)


## AWS Configのリソースタイムライン確認

AWS Config > リソース 画面で検索します。

その後、確認したいリソースを選択 > リソースタイムライン に遷移すると、タイムライン形式で変更内容を確認できます。

# 設定の修正

上記調査の結果、以下の2点が分かりました。

- リソースID 1つあたりに対する変更が多く、リソース数が少ないものは`AWS::EC2::VPC`、`AWS::EC2::SecurityGroup`、`AWS::EC2::Subnet`、`AWS::AutoScaling::AutoScalingGroup`

- リソースID 1つあたりの変更は少ないが、リソースID数が多く、合計の変更記録が多くなっているものは`AWS::Config::ResourceCompliance`、`AWS::EC2::NetworkInterface`、`AWS::EC2::Volume`、`AWS::EC2::EC2Fleet`

## 対応1 AWS::Config::ResourceComplianceを記録から除外

以下のようなクエリで、日毎の記録件数を確認したところ、AWS::Config::ResourceComplianceの件数が非常に多くなっていました。

```sql
SELECT
    COUNT(configurationItem.resourceId) AS TotalNumberOfChanges
FROM
    default.awsconfig
CROSS JOIN
    UNNEST(configurationitems) AS t(configurationItem)
WHERE
    "$path" LIKE '%ConfigHistory%'
    AND configurationItem.resourceType = 'AWS::Config::ResourceCompliance'
    AND configurationItem.configurationItemCaptureTime >= '2025-02-20T00:00:00Z'
    AND configurationItem.configurationItemCaptureTime <= '2025-02-20T23:59:59Z'

```

これは、あらゆるリソースに対して設定変更が発生すると、その度にAWS::Config::ResourceComplianceが記録されてしまうことが原因です。

この項目はSecurity Hubでのセキュリティチェックに不要なため、記録から除外しました。

> Security Hub は、 AWS Config 設定項目を更新することで、AWS::Config::ResourceCompliance設定レコーダーのコストに影響を与える可能性があります。更新は、 AWS Config ルールに関連付けられた Security Hub コントロールがコンプライアンス状態を変更する、有効または無効になる、またはパラメータが更新されるたびに発生する可能性があります。 AWS Config 設定レコーダーを Security Hub にのみ使用し、他の目的でこの設定項目を使用しない場合は、その記録をオフにすることをお勧めします AWS Config。これにより、 AWS Config コストを削減できます。Security Hub でセキュリティチェックを行うために AWS::Config::ResourceCompliance を記録する必要はありません。

https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-setup-prereqs.html#config-cost-considerations

## 対応2 リソースID数が多く、変更記録件数も多いリソースタイプ、使い捨てが主であるものは、記録から除外

`AWS::EC2::NetworkInterface`、`AWS::EC2::Volume`、`AWS::EC2::EC2Fleet`が対象です。

これらは1リソースIDあたりの変更記録件数が4以下の場合がほとんどですが、リソースID数が多いです。

料金削減の選択肢としては
- 日次記録にする
- 記録から除外する

の2択です。

ただし、1日あたりの記録件数が4以下の場合、かえって料金が上がってしまいます。
今回は、これらのリソースは使い捨てが主であることを考慮し、記録から除外しました。

|  | 料金 |
| --- | --- |
| 連続的な記録（継続的な記録） | USD 0.003 |
| 定期的な記録（日次記録） | USD 0.012 |


例えば、CloudTrailのイベント履歴からCreateNetworkInterfaceを検索すると、ユーザー名`ecs-eni-provisioning`によって発生していました。
このユーザーは、Amazon Elastic Container Service (ECS) がタスクの起動時に Elastic Network Interface (ENI) を作成・管理するために内部的に使用するシステムユーザーです。

このパターンによる生成は大量に実施されており、CreateNetoworkInterfaceに関する9割以上を占めていました。これが全て`AWS::EC2::NetworkInterface`の変更として記録されます。怖い...


## 対応3 リソースID数は少ないが、変更記録数が多い場合、記録から除外したくないものは、日次記録に変更

`AWS::EC2::VPC`、`AWS::EC2::SecurityGroup`、`AWS::EC2::Subnet`、`AWS::AutoScaling::AutoScalingGroup`が対象です。

これらはリソースIDごとの記録数が4を大幅に超えており、日次記録にすることで料金を下げられそうです。
また、記録から除外したくないということもあり、日次記録に変更しました。

例えば、`AWS::EC2::Subnet`の設定変更記録は、CreateNetworkInterfaceイベントによって発生していました。
これは、ネットワークインターフェイスを作成する際に、作成先のサブネットを指定する必要があることが原因です。具体的には以下の理由です。

1. **サブネットのリソースリストの更新**: 新しい ENI が作成されると、その ENI はサブネット内のリソースとして追加されます。これにより、サブネットのリソースリストが更新され、その変更が記録されます。
2. **サブネットの IP アドレス使用状況の更新**: ENI の作成時に、サブネット内のプライベート IP アドレスが割り当てられます。この割り当てにより、サブネット内の使用中および未使用の IP アドレスのリストが更新され、その変更が記録されます。

# 解消

上記対応で、料金を削減することができました。（2/27以降）よかった...

![スクリーンショット 2025-03-12 10.05.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475547/8f3b74ab-0329-4ea8-853b-91e624ae8e77.png)


### <font color="red">設定を大きく変更する場合は、しばらく料金を様子見しましょう…</font>