🕵

AWS Configの課金から学ぶECSネットワークモード

に公開

先端技術開発グループ(WAND)の小島です。福原、佐藤と私は、主に機械学習エンジニアが使うためのサンドボックス用のAWS環境(デモ環境)の保守運用を行っています。有志の協力もあり、かれこれ2年近く運用しているのですが、その間には「なにこの課金!?」という正体不明の請求がたびたび発生します。

前回はOpenSearchの謎課金を紹介しましたが、今回は実際にあったAWS Configの突如の高額請求についてその原因を含めて探っていきたいと思います。

AWS Configとは

AWS Configは、AWSリソースの設定変更履歴を記録・管理し、組織のポリシーに対するコンプライアンス違反を継続的に監視して自動で検出・通知するサービスです。

例えば、意図せずS3バケットが公開設定に変更された場合、AWS Configはリアルタイムでその設定変更を検知し、コンプライアンス違反として管理者に通知します。また、Systems Manager Automation ランブックと連携して、違反設定の自動修復が可能です。

AWS Configの高額請求は突然に😱

(※本請求画面はデモ環境のもので、プロダクトや案件等の本番のデータやリソースは入っていません)

このように一見便利なサービスなのですが、ある月、AWS Configだけで200ドル近く課金されていました。AWS Configは、ルール評価や記録数に応じて請求されるので、料金は安定して推移しやすい傾向にあるのですが、「なぜこんなにいきなり課金されたか」という点が気になります。

AWS Config 使用状況メトリクスを確認

請求書を見るとルール評価(ConfigRuleEvaluations)ではなく、記録(ConfigurationItemRecorded)が請求の主要因であることがわかります。

これらが「いつ、どれだけ」カウントされたかは、AWS Configのダッシュボードの「使用状況メトリクス」から確認できます。8月冒頭に異常な数の記録された設定項目が発生しています。「攻撃があったのではないか?」と疑いたくなる数ですね。

Configの記録をAthenaで探索する

Athenaテーブルの作成

Configの記録はS3バケットに保存されているので、Athenaで探索可能です。Athenaのテーブルを作成するためのクエリは、AWSの情報センターに記事があります。

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 > >
)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe' LOCATION 's3://BUCKET-NAME/AWSLogs/ACCOUNT-ID/Config/REGION/';

ここでBUCKET-NAME(Configの記録が保存されているバケット名)、ACCOUNT-ID(12桁の数字)、REGION(例:ap-northeast-1)は各自の値を入力します。

対象リソースの絞り込み

テーブルを作成したら、「どのリソースの記録が多いか」をクエリします。

SELECT configurationItem.resourceType,
         configurationItem.resourceId,
         COUNT(configurationItem.resourceId) AS NumberOfChanges
FROM awsconfig.awsconfig
CROSS JOIN UNNEST(configurationitems) AS t(configurationItem)
WHERE "$path" LIKE '%ConfigHistory%'
        AND configurationItem.configurationItemCaptureTime >= '<開始期間>'
        AND configurationItem.configurationItemCaptureTime <= '<終了期間>'
GROUP BY  configurationItem.resourceType, configurationItem.resourceId
ORDER BY  NumberOfChanges DESC

「<開始期間>」は2025-07-31T%、「<終了期間>」は2025-08-08T%としました。

VPCやサブネットは当たり前なのですが、特定のセキュリティグループに対する記録が突出して多い(1万回以上)というのが気になります。対象のセキュリティグループがわかれば、どのアプリケーションからきているかを特定しやすくなります。

CloudTrailからわかる原因

セキュリティグループというピンポイントなリソースがわかったので、このリソース名でCloudTrailを検索してみます。すると意外なことがわかりました。

「CreateNetworkInterface」というイベント名で、「ecs-eni-provisioning」というユーザー名によるものであることが確認できます。ECSのタスクが短期間に大量に実行され、実行と同時にENI(Elastic Network Interface)が大量に作成された結果、AWS Configの請求が跳ね上がったのではないかという仮説が考えられます。

ここまで、S3ログをAthenaで検索し、CloudTrailのログと突き合わせるという、運用でよく使われる手法を試しました。

ECSでタスク起動のログを確認する

セキュリティグループ名からどのようなECSタスク名か推測できたので、タスクの起動ログを見に行きます。するとビンゴで、当該の期間は毎分タスクが起動していたことが確認できました。

このタスク環境は「Fargate」で定義されており、ネットワークモードは「awsvpc」でした。

ここで仮説の解像度がより上がります。

  • FargateタイプのECSタスクは、awsvpcのネットワークモードであるため、タスクの起動時にENIを作成する。大量に起動すると、それに伴いAWS Configの記録も大量に行われ、請求が発生してしまいます。
  • ECS on EC2の場合は、すでに作成したEC2上でタスクを実行するため、この対象とならないかもしれない。ただし、これはネットワークモード(awsvpcbridgehostなど)に依存する。

ECSのネットワークモードとは

ECSネットワークモードは、コンテナがホストEC2インスタンスやVPCとどのように通信するかを定義する設定で、タスクごとに専用IPを割り当てる awsvpc やホストのネットワークを共有する bridgehost などの方式があります。

FargateとECS on EC2のネットワークモードについて、表でまとめると以下の通りになります。

ネットワークモード 対応起動タイプ タスク起動時にENIを作成するか 解説
awsvpc Fargate (唯一), EC2 する 各タスクに専用のENI(Elastic Network Interface)を割り当て、独立したネットワーク環境を提供します。
bridge EC2 (Linux) しない Dockerの仮想ネットワークブリッジを介してホストのネットワークに接続し、ポートマッピングを利用します。
host EC2 (Linux) しない コンテナがホスト(EC2インスタンス)のネットワークを直接利用し、最高のパフォーマンスを発揮します。
none EC2 (Linux) しない コンテナに外部ネットワーク接続を一切提供しない、完全に分離されたモードです。
default EC2 (Windows) しない Windowsコンテナでデフォルトで利用される、natドライバーを使ったDockerの仮想ネットワークです。

awsvpcモードでECSを動作させた場合、タスク起動時にENIが作成されるため、タスクを大量に起動した際、AWS Configの記録が大量に行われるのではないかという点が示唆されます。この表は、AWSのECSのネットワークモードのドキュメントと、AWS Documentation MCP Server、各種生成AIの力を借りて作成したものです。

生成AIの結果はハルシネーションが含まれる可能性があるため、実際に調べてみましょう。

ECSのネットワークモード別のタスク起動実験

上記の仮説を検証するため、以下の実験を行います。

実験定義

  • 4つのモードでECSクラスタを作成
    • Fargate (awsvpcモード)
    • ECS on EC2 (awsvpcモード)
    • ECS on EC2 (bridgeモード)
    • ECS on EC2 (hostモード)
  • ECSのタスクとして、ランダムに5~15秒待機して終了するシンプルなPythonコードを実行
  • 4つのモードそれぞれのECSクラスタに対し、ローカルから短期間に大量のタスクを連続的に起動し、AWS Configのレコード数の変化を調べる
    • 各モードにつき500タスクで、タスクの同時実行数は10
    • ECSのタスクあたりのリソースは、1/4vCPU、512MBとする
    • EC2はt3.mediumを5台立ち上げ、タスクの並列処理が十分間に合う状態にする
  • モードとモードの間に10分間のインターバルを置く

結果

「Fargate (awsvpcモード)」→「ECS on EC2 (awsvpcモード)」→「ECS on EC2 (bridgeモード)」→「ECS on EC2 (hostモード)」の順で実行しています。当初の想定通り、最初の2回のawsvpcモードのときはAWS Configの記録が発生し、以降は発生していません。調べた範囲内のモードでは、表の内容が正しいことがわかりました。

ECSタイプ ネットワークモード 所要時間
Fargate awsvpc 0:56:33
EC2 awsvpc 0:43:50
EC2 bridge 0:16:57
EC2 host 0:16:09

また、短期間でタスクを大量に起動する場合は、ネットワークのオーバーヘッドが支配的になるということがわかりました。全500タスクを完了するのに、Fargateの場合は最も所要時間がかかりました(56分33秒)。EC2のawsvpcがそれに続き、最短で終わったのはEC2のhostモード(16分9秒)でした。ただ、これはEC2のオートスケーリングが完了した状態でテストを始めているため、EC2の起動のオーバーヘッドは含んでいません

実験からわかったAWS Configの突如の高額請求の理由

AWS Configの突如の高額請求は以下のような連鎖的な理由で発生したという説が濃厚であることがわかりました。

  • 何らかのアプリケーションの関係で、Fargate(awsvpcモード)で定義されたECSのタスクが短期間内に大量に実行された
  • awsvpcのネットワークモードの仕様上、タスク起動時にENIが作成される。その結果、AWS Configの設定項目が短期間に大量に記録される
  • AWS Configの設定項目の記録は「USD 0.003 / 件(連続的な記録)」であるため、塵が積もって請求額が跳ね上がった
  • これはECSのawsvpcモード特有のもの。Fargateの場合は必ず発生する

AWS Configの突如の高額請求を避けるにはどうすればいいか

このケースから考えていきましょう。アカウント管理者側とアプリケーション制作者側の両方から対策が考えられます。

アカウント管理者側の対策:AWS Configを「定期的な記録」に変える

AWS Configの公式の料金説明には、以下のようにあります。

AWS Config では、定期的な記録と継続的な記録の 2 つの頻度で設定項目を配信できます。定期的な記録では、変更が発生した場合にのみ 24 時間に 1 回設定データが配信されるため、運用計画や監査などのユースケースに役立つ場合があります。連続的な記録では、変更が発生するたびに設定項目が配信されます。これはセキュリティとコンプライアンスの要件を満たし、すべての設定変更を追跡するのに役立ちます。

各 AWS リージョンの AWS アカウントごとに配信される設定項目あたりのコスト
連続的な記録 USD 0.003
定期的な記録 USD 0.012

単価が「連続的な記録」のほうが安いためこちらを選びがちです。しかし、今回のように短期間で大量の記録が作成され、それが請求に直結し、記録がリアルタイムでいらない場合は、「定期的な記録」に変えて1日1回のレコードにするのが一つの解決方法でしょう。

この解決方法は、以下の記事が詳しいです。

AWS Configの料金がなんか思ったより高かったので見直してみた

また類似の例が、クラウドワークスさんのTechBlogでも紹介されています。VPC、サブネット、セキュリティグループ、ENIという配信頻度の高いリソースに対して同様の対策をとっています。

AWS Configのアップデートで課金増えていませんか?

アプリケーション制作者側の対策

Configは管理者側の理由でつけていることが多いため、コスト対策の責任は基本管理者側にあるのですが、このへんの事情を頭の片隅に入れながらアーキテクチャーを考えると「かなり通」だと思います。対策は複数考えられます。

  • Fargateでなくて良いのならタスクをLambdaに切り出してしまう
    • これが一番わかりやすいが、ECSタスクやサービス間の連携が取りづらくなる
  • 大量にジョブを起動し、Fargateを使いたいなら、常駐サービスにしてしまう
    • Fargateのタスク起動にパフォーマンス面のオーバーヘッドがあるため、常駐サービスがポーリングするほうがわかりやすい。一方でコストは増す
  • どうしても「タスク」という形で大量起動したいなら、ECS on EC2を使い、awsvpcモード以外(例:bridge, hostモードなど)を利用する
    • Fargate特有の管理の容易さは失われるため、一長一短
  • タスクの起動という形で残したいなら、AWS Batchを使い、hostモードを使用する
    • ECS on EC2が抽象され、ジョブキュー付きで実装されるため、比較的わかりやすい

ユースケースによりけりかと思いますが、Lambdaあたりから検討するのが良いかなと思いました。

なぜタスクが短時間に大量起動されたのか

このアプリの作成者にヒアリングしたところ(課金を責めるのではなく、「原因調査のため状況を再現したい」という文脈でコミュニケーションするのがポイントです)、「もともとJiraのチケットに対して処理する意図で作ったが、タスクの大量起動は意図していない。短時間に大量にタスクが起動した原因は不明」とのことでした。タスクの起動失敗によるリトライループも可能性としては考えられますが、タスク大量起動の本当の原因はよくわかりません(本人掲載許可済み)。

これからAIエージェントが普及してきて「人間が意図しないタスクの大量起動みたいなのが増えてくるのかなー」と漠然と感じたところで本記事を締めたいと思います。

また、本内容は勉強会のときに、アカウント管理の皆さんで原因調査したのですが、「それをテックブログ化できたらいいよね」ということで記事化しました。

まとめ

AWS Configの高額請求は、FargateのECSタスクが短期間に大量起動され、設定項目の記録が急増したことが原因でした。これは、タスクごとにネットワークインターフェースを作成するawsvpcネットワークモードの仕様により、変更履歴が大量に記録された結果、意図せず請求額が跳ね上がったものでした。

エクサウィザーズ Tech Blog

Discussion