コスト削減の提案を上司や顧客にしようとしたとき、「本当にそのサービスが問題なのか、具体的な根拠を示せ」と言われて詰まった経験はないだろうか。
AWS Cost Explorerは視覚的に使いやすく、日常的なコスト確認には十分だ。ただ、「先月と比べて請求が10万円増えた」その原因を特定しようとすると、グラフの粒度では限界にぶつかることがある。どのリソースが、どの時間帯に、なぜコストを跳ね上げたのかを突き止めるには、生の請求データを自分でクエリできる環境が必要だ。
その環境を実現するのが AWS Cost and Usage Report(CUR) だ。この記事では、CURをS3に書き出してAthenaでSQLクエリを実行する環境を整え、現場で実際に使えるクエリ例まで解説する。
AWS Cost and Usage Reportとは
AWS Cost and Usage Report(以下CUR)は、AWSアカウントのすべての利用明細を、リソースIDや時間単位の細粒度でCSVまたはParquetファイルとして出力するサービスだ。
「明細」といっても、普段目にするクレジットカードの明細とはスケールが違う。1か月分のCURを展開すると数百万行になることもある。EC2の1インスタンスを1時間動かすたびに1行、S3のGETリクエストが発生するたびに1行積み上がっていく。その粒度こそがCURの価値だ。
Cost Explorer・Budgets・CURの使い分け
同じ「コスト管理」でも、3つのサービスはまったく用途が異なる。
| ツール | 主な用途 | 粒度 | 分析の自由度 |
|---|---|---|---|
| AWS Cost Explorer / Budgets | 日常的なコスト確認・予算アラート | サービス別・日別 | 低(固定ビュー) |
| AWS Cost Anomaly Detection | 異常なコスト増加の自動検知 | サービス別 | 低(自動検知のみ) |
| AWS CUR | コスト原因の深掘り分析・部門別按分 | リソースID・時間別 | 高(SQL自由記述) |
Cost Explorerが「ダッシュボード」なら、CURは「生ログ」だ。普段はCost Explorerで十分だが、コスト最適化プロジェクトを本格的に進めるとき、CURなしには根拠のある分析ができない。
CUR v1(Legacy Exports)とData Exports(CUR v2)の違い
2023年後半から、AWSはCURの後継として AWS Data Exports を提供し始めた。コンソール上では「Data Exports」と「Legacy Exports(CUR v1)」の2つが選べる状態になっている。
| 比較項目 | CUR v1(Legacy Exports) | Data Exports(FOCUS形式対応) |
|---|---|---|
| ファイル形式 | CSV / Parquet | CSV / Parquet / FOCUS(業界標準) |
| Athena統合機能 | あり(CFnテンプレート自動生成) | あり(Glue Data Catalog) |
| マルチクラウドFinOps対応 | なし | FOCUS形式でAzure・GCPと統一分析が可能 |
| 将来性 | 新機能追加停止(廃止予定) | 今後の主力 |
新規に始めるなら Data Exports を選ぶのが無難だ。ただし既存のCUR v1を使っている現場も多く、本記事ではどちらにも共通するS3+Athena分析の考え方を中心に解説する。
CURをS3に書き出す設定手順
1. S3バケットを事前に作成する
CURの出力先となるS3バケットを、東京リージョン(ap-northeast-1)に用意する。バケット名はグローバルで一意にする必要があるため、アカウントIDや社名を含めると衝突しにくい。
# AWS CLI: S3バケット作成例(バケット名は自社名+アカウントIDで一意にする) aws s3api create-bucket \ --bucket your-company-cur-123456789012 \ --region ap-northeast-1 \ --create-bucket-configuration LocationConstraint=ap-northeast-1
2. S3バケットポリシーを設定する
AWSのBillingサービスがバケットにファイルを書き込めるよう、バケットポリシーで billingreports.amazonaws.com からのPutObjectを許可する。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "billingreports.amazonaws.com" }, "Action": ["s3:GetBucketAcl", "s3:GetBucketPolicy"], "Resource": "arn:aws:s3:::your-company-cur-123456789012" }, { "Effect": "Allow", "Principal": { "Service": "billingreports.amazonaws.com" }, "Action": "s3:PutObject", "Resource": "arn:aws:s3:::your-company-cur-123456789012/*" } ] }
3. CURレポートを作成する(コンソール操作)
AWSコンソール → Billing and Cost Management → Cost and Usage Reports → 「レポートを作成」の順に進む。設定時のポイントは以下のとおりだ。
・リソースIDの包含: 「個々のリソースIDを含む」に必ずチェックを入れる。これがOFFだとEC2インスタンスやRDSインスタンスを個別に特定できない
・時間粒度: 「時間単位(Hourly)」を選ぶ。日単位だと深夜のバースト課金を特定しにくい
・ファイル形式: 「Parquet」推奨。CSVは非圧縮だとファイルサイズが膨大になり、Athenaのクエリコストが増加する
・Athena統合: 「Athena統合を有効にする」をチェックしておくと後の設定が楽になる
設定後、最初のレポートがS3に配信されるのは翌日以降だ。CURはリアルタイムではなく、通常24時間後に前日分が書き出される。新規設定の場合は翌日以降まで待つ必要がある。
AthenaでCURデータを分析する
S3にCURが書き出されたら、次はAthenaでSQLクエリを実行できる環境を整える。
1. Athena統合機能でテーブルを自動作成する
CURのAthena統合を有効にしておくと、S3の出力先に crawler-cfn.yml というCloudFormationテンプレートが自動生成される。このテンプレートをCloudFormationでデプロイするだけで、Glue Data Catalog上にテーブルが作成され、AthenaからすぐにクエリできるようになるIだ。
・CFnスタックのデプロイ: S3の `<プレフィックス>/` 配下に生成された `crawler-cfn.yml` を CloudFormation で実行する
・自動作成されるリソース: Glueクローラー・Glueデータベース・Athenaテーブルが一括で作成される
・月次クローラー実行: 月が変わってファイルが増えるたびにクローラーを再実行してパーティションを更新する必要がある
2. Athenaのクエリ結果出力先S3を設定する
Athenaはクエリ結果をS3に書き出す。CURデータとは別のバケット(またはプレフィックス)を事前に作成しておくこと。
# Athenaクエリ結果用バケット(CURデータとは分離して管理する) aws s3api create-bucket \ --bucket your-company-athena-results-123456789012 \ --region ap-northeast-1 \ --create-bucket-configuration LocationConstraint=ap-northeast-1
AthenaコンソールのSettings → Manage で上記バケットのS3パスを設定すれば完了だ。
実務で使えるCURクエリ集
Athenaのテーブルが準備できたら、実際のクエリを実行してみよう。以下はオンプレからクラウドに移行したエンジニアが最初にぶつかる「なぜこのコストが?」を解決するクエリ集だ。テーブル名は cur_db.your_report_name の形式で自分の環境に合わせて読み替えてほしい。
1. サービス別の月次コスト(上位20件)
まず全体像を把握するための基本クエリだ。
SELECT line_item_product_code AS service, ROUND(SUM(line_item_unblended_cost), 2) AS total_cost_usd FROM cur_db.your_report_name WHERE year = '2026' AND month = '7' AND line_item_line_item_type NOT IN ('Tax', 'Credit') GROUP BY line_item_product_code ORDER BY total_cost_usd DESC LIMIT 20;
「EC2が全体の何%か」「RDSが予想より高い」といった全体像をつかむのに使う。
2. EC2インスタンス別のコスト(リソースID単位)
「EC2コストが全体の40%を占めているが、どのインスタンスが高いか」を特定するクエリだ。
SELECT line_item_resource_id AS instance_id, product_instance_type AS instance_type, ROUND(SUM(line_item_unblended_cost), 2) AS total_cost_usd FROM cur_db.your_report_name WHERE year = '2026' AND month = '7' AND line_item_product_code = 'AmazonEC2' AND line_item_line_item_type = 'Usage' AND line_item_usage_type LIKE '%BoxUsage%' GROUP BY line_item_resource_id, product_instance_type ORDER BY total_cost_usd DESC LIMIT 30;
このクエリで「特定のインスタンスIDが異様に高い」という発見につながることが多い。停止し忘れた開発用インスタンスや、本番よりも大きいサイズで動き続けているバッチ処理サーバーが露わになる。
3. コスト配分タグ別のコスト集計
コスト配分タグをリソースに付与している場合、タグ別にコストを集計できる。たとえば Env タグで「production」と「development」を分けている場合のクエリだ。
SELECT resource_tags_user_env AS environment, line_item_product_code AS service, ROUND(SUM(line_item_unblended_cost), 2) AS total_cost_usd FROM cur_db.your_report_name WHERE year = '2026' AND month = '7' AND line_item_line_item_type NOT IN ('Tax', 'Credit') GROUP BY resource_tags_user_env, line_item_product_code ORDER BY environment, total_cost_usd DESC;
タグ名が Env の場合、CURではカラム名が resource_tags_user_env になる(すべて小文字、ユーザータグには resource_tags_user_ プレフィックスが付く)。カラム名が不明な場合は DESCRIBE TABLE で確認するとよい。
4. 先月と今月のサービス別コスト比較
「先月より2万円増えた。どのサービスが増加したか」を特定するクエリだ。
WITH current_month AS ( SELECT line_item_product_code AS service, ROUND(SUM(line_item_unblended_cost), 2) AS cost_current FROM cur_db.your_report_name WHERE year = '2026' AND month = '7' AND line_item_line_item_type NOT IN ('Tax', 'Credit') GROUP BY line_item_product_code ), prev_month AS ( SELECT line_item_product_code AS service, ROUND(SUM(line_item_unblended_cost), 2) AS cost_prev FROM cur_db.your_report_name WHERE year = '2026' AND month = '6' AND line_item_line_item_type NOT IN ('Tax', 'Credit') GROUP BY line_item_product_code ) SELECT c.service, c.cost_current AS cost_current_usd, COALESCE(p.cost_prev, 0) AS cost_prev_usd, ROUND(c.cost_current - COALESCE(p.cost_prev, 0), 2) AS diff_usd FROM current_month c LEFT JOIN prev_month p ON c.service = p.service ORDER BY diff_usd DESC;
diff_usd が大きいサービスが今月のコスト増加の主因だ。プラスが増加、マイナスが削減を意味する。
5. データ転送コストの内訳
「データ転送コストが高い」という場合に、どのリソースからのトラフィックが高いかを特定するクエリだ。
SELECT line_item_usage_type, line_item_resource_id, ROUND(SUM(line_item_usage_amount), 2) AS usage_gb, ROUND(SUM(line_item_unblended_cost), 2) AS cost_usd FROM cur_db.your_report_name WHERE year = '2026' AND month = '7' AND line_item_product_code = 'AmazonEC2' AND line_item_usage_type LIKE '%DataTransfer%' GROUP BY line_item_usage_type, line_item_resource_id ORDER BY cost_usd DESC LIMIT 20;
CURを使う際の注意点と落とし穴
【注意1】ブレンドコストと非ブレンドコストの違い
CURには line_item_blended_cost と line_item_unblended_cost の2つのコスト列がある。
・非ブレンドコスト(unblended): そのリソースが実際に発生させたオンデマンド料金ベースのコスト
・ブレンドコスト(blended): Organizations のマルチアカウント環境でRI・Savings Plansを共有している場合に、割引を按分後の値が入る
単一アカウントなら非ブレンドコストで問題ない。マルチアカウント環境で部門別按分を行うなら、ブレンドコストを使うか savings_plan_savings_plan_effective_cost 列を参照する設計になる。
【注意2】CURの更新は1日遅れ
CURは当日のコストをリアルタイムに反映しない。通常24時間後に前日分が書き出される。「今日の課金額が急増しているかどうか」をリアルタイムで把握したい場合は、Cost Explorerを使うこと。
【注意3】AthenaクエリコストはParquetとパーティションで抑える
AthenaはスキャンデータTB単価で課金される($5.00/TB、2026年7月時点)。CURのCSVファイルは数百MBから数GB規模になるため、全期間フルスキャンすると思わぬコストが発生する。
対策は2つだ。
・Parquet形式: 列指向ストレージのため、SELECT で必要な列だけ読み込みスキャン量が激減する
・パーティション条件の必須化: WHERE 句に必ず year と month を含める。含めないと全期間のデータをフルスキャンしてクエリコストが急増する
Athena自体のコスト削減についてはこちらの記事でも詳しく解説しているので参照されたい。
【注意4】マルチアカウント環境はOrganizations管理アカウントで一元取得
各メンバーアカウントがCURを個別に取得することはできない。Organizationsの管理アカウントでCURを設定すると、すべてのメンバーアカウントの請求を一つのS3バケットにまとめて受け取れる。クエリ時は line_item_usage_account_id カラムでアカウントIDを絞り込める。
【注意5】line_item_line_item_type の除外漏れに注意
CURには line_item_line_item_type が複数存在する(Usage、Tax、Credit、Discount、Fee 等)。コスト集計では必ず NOT IN ('Tax', 'Credit') を条件に加えること。除外しないと、実際より高い数字が出たり、クレジット適用後と前の二重計上が起きたりする。
FinOpsの観点でCURをどう活用するか
CURは単に「コストの原因調査」だけでなく、FinOps実践の文脈では「部門別コスト按分レポートの自動化」「Reserved Instanceの消費率モニタリング」「Savings Plansのカバレッジ可視化」にも活用される。
実務での進め方として、最初はAthenaの手動クエリから始め、慣れてきたらAmazon QuickSightや社内のBIツールに接続してダッシュボード化するステップが現実的だ。毎月の請求会議で担当者が手動でグラフを作っているなら、CURとAthenaで自動化すれば数時間の手作業をゼロにできる。
まとめ
| やりたいこと | 使うもの | ポイント |
|---|---|---|
| 日常的なコスト確認 | Cost Explorer | サービス別・日別で十分 |
| コスト急増の自動検知 | Cost Anomaly Detection | 機械学習で閾値設定不要 |
| 特定リソースのコスト特定 | CUR + Athena | リソースIDで1インスタンス単位まで絞れる |
| 部門別コスト按分 | CUR + タグ + Athena | タグ設計と組み合わせると強力 |
| 前月比コスト増加の原因特定 | CUR + Athena(WITH句月次比較) | 差分をサービス別に一覧化できる |
| FinOpsダッシュボード化 | CUR + QuickSight / BIツール | 月次の手作業を自動化 |
CURは設定して翌日に最初のファイルが届くまでが最初の壁だ。しかし一度AthenaでSQLが通り、特定のEC2インスタンスIDがコストを食い散らかしている実態が見えた瞬間の感覚は格別だ。「このくらいはCost Explorerでわかる」と思っていたエンジニアほど、CURを触ると視界が変わる。まずはS3バケットの準備とCURの設定から始めてみてほしい。
PR
CURを活用したコスト分析からReserved Instance・Savings Plansの購入判断まで、AWS課金体系の「なぜ」に踏み込んだ実践書。コスト削減を組織に定着させたいエンジニアにおすすめの一冊。
