Contents
導入:自動集計の目的と最終成果物イメージ
AWS の請求データを Excel(Power Query)やスクリプトで定期集計し、経理や技術チームへ配布するための実務手順を示します。まず単月CSVで動作検証を行い、安定した集計ルートを作ったうえで CUR や API による自動化に移行することを推奨します。この記事は AWS 請求書 エクセル 自動集計 方法 を具体的なテンプレート、コード例、運用チェックリストでまとめ、セキュリティ・コンプライアンス上の留意点も含めて解説します。AWS 請求書 エクセル 自動集計 方法 を短期間で実運用に移すための実行手順が最終成果物です。
AWS 請求データの入手方法と選び方
ここでは利用可能なデータソースと、目的別の選び方を簡潔に示します。手早く検証したい場合は単月CSVを使い、定期運用や高粒度分析は CUR(Cost and Usage Report)へ移行します。
入手方法の一覧と特徴
代表的な取得方法と向き不向きを示します。用途(即時検証/スクリプト自動化/高粒度分析)に合わせて選んでください。
- 単月CSV(請求書画面からダウンロード)
- 手軽に Excel に取り込み、短時間で「動く状態」を作れます。
-
行粒度やタグ反映が限定的で、大量データや自動化には向きません。
-
AWS CLI / Cost Explorer API(get-cost-and-usage 系)
- JSON 出力でスクリプトから柔軟に抽出・集計できます。期間やグループ化を指定可能で自動化に向いています。
-
API のページング(NextToken)やスロットリングに注意が必要です。
-
Cost and Usage Report(CUR)
- 最も高粒度で resource IDs やタグを含められます。S3 配信で CSV または Parquet が選べ、Athena/Glue と連携しやすいです。
- データ量が大きく、配信遅延やパーティション設計、ストレージコストに注意が必要です。
選び方(手早さと粒度のトレードオフ)
短期検証なら単月CSVで Excel(Power Query)テンプレートを動かします。定期自動化や外部システム連携が必要なら CLI/API を使い、長期運用で高粒度分析が必要になったら CUR(Parquet 推奨)へ移行してください。まずは小さなデータセットで end-to-end を確認することが近道です。
事前準備:コストアロケーションタグ、リンクドアカウント、権限設定
運用で後戻りが発生しやすい項目を先に整備します。特にタグ運用と IAM 設計は早期に方針を決め、テストと自動化を組み合わせてください。
コストアロケーションタグの有効化と運用
タグは有効化以降に請求へ反映され、過去データには遡及されません。運用設計と命名規則、検出ルールを用意してください。
- 推奨タグ例と命名規則の考え方
- 必須例:project、costCenter、environment、owner。小文字化しハイフン/アンダースコアを許容するなど統一します。
- 仕様例:タグキー最大長は 128 文字、値は 256 文字まで(AWS の標準制限に合わせる)。キーはケースセンシティブである点に留意してください。
- 運用例:CloudFormation/CDK/Terraform のデプロイ時に自動付与、Config ルールや Lambda で未タグ検出をアラート化。
リンクドアカウントの扱い
リンクドアカウント(linked account)と請求支払者(payer)の関係を理解し、集計キーを決めてください。CUR にはアカウント識別子(たとえば identity/LinkedAccountId や bill/PayerAccountId のようなカラム)がありますので、集計設計時に使用するフィールドを明確にしておきます。
権限設計(最小権限ポリシーと AssumeRole)
自動化用にはクロスアカウントの IAM ロール(AssumeRole)を用い、長期固定キーは避けます。Secrets Manager や Parameter Store を使い認証情報を安全に管理します。
- 最小権限ポリシー(CUR の S3 取得・Cost Explorer 読取の例)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::example-cur-bucket", "arn:aws:s3:::example-cur-bucket/*" ] }, { "Effect": "Allow", "Action": [ "cur:DescribeReportDefinitions", "ce:GetCostAndUsage", "ce:GetCostAndUsageWithResources" ], "Resource": "*" } ] } |
- ロール信頼関係(AssumeRole のサンプル)
|
1 2 3 4 5 6 7 8 9 10 11 |
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::123456789012:role/AutomationRunner" }, "Action": "sts:AssumeRole" } ] } |
- Python での短期認証取得例(boto3, AssumeRole)
|
1 2 3 4 5 6 7 8 9 10 |
import boto3 sts = boto3.client('sts') r = sts.assume_role(RoleArn='arn:aws:iam::999888777666:role/CurReadRole', RoleSessionName='cur-session') creds = r['Credentials'] s3 = boto3.client('s3', aws_access_key_id=creds['AccessKeyId'], aws_secret_access_key=creds['SecretAccessKey'], aws_session_token=creds['SessionToken']) |
- Secrets 管理例(Secrets Manager)
- S3 バケット名やクロスアカウントロールの ARN などを Secrets Manager へ保管し、実行時に取得して利用します。
Cost and Usage Report(CUR)実装の詳細と Glue/Athena 連携
CUR を本番運用に使う際の技術的留意点を解説します。Manifest の扱いやパーティション設計、Parquet の利点、Glue/Athena 登録時の注意点を押さえてください。
Manifest とファイル命名・圧縮形式
CUR は S3 に複数ファイルで配信され、manifest(JSON)が配信ファイル一覧を提供します。ファイルは CSV(gzip)か Parquet を選べます。Manifest を使って到着済みファイルだけを処理する設計が堅牢です。
- manifest の構成(抜粋イメージ)
- reportKeys: 配信されたファイルキーの配列
- s3Bucket: バケット名
- s3Prefix: プレフィックス
- reportName: レポート名
ファイル名は報告設定に依存しますが、一般に日付や識別子を含む複数分割ファイルが格納されます。
Parquet の利点と圧縮 codec の選択
Parquet は列志向フォーマットで、必要列のみを読み込めるためクエリコストが削減できます。推奨 codec は以下です。
- Snappy:互換性が高く Athena/Glue で推奨されます。読み書きのバランスが良好です。
- ZSTD:圧縮率が高くコスト削減効果が大きいですが、Athena のエンジン/バージョン依存で利用可否を確認してください。
- GZIP:圧縮率は高いが CPU 負荷が大きく読み取りコストが上がる場合があります。
Parquet を選ぶと列プルーニングや predicate pushdown が効き、クエリ料金を減らせます。
パーティション設計とパーティション遅延
適切なパーティションはクエリ性能に直結します。一般的には year/月(あるいは billing_period)でパーティションすることが多いです。
- パーティション例:s3://bucket/cur/
/year=YYYY/month=MM/... - 遅延対策:CUR の配信は遅延する場合があるため、到着トリガー(S3 イベント/EventBridge の到着通知)や manifest を基に処理する方が安全です。
- パーティション追加:MSCK REPAIR TABLE や Glue API / Athena の ALTER TABLE ADD PARTITION、もしくはパーティションプロジェクションを利用して運用してください。
Glue / Athena 登録手順と注意点
Parquet を Athena で使う場合は外部テーブル定義を作成します。カラム名や小文字/大文字の違い、スキーマ変更への対応を設計に含めてください。
- Athena DDL(Parquet, year/month パーティション例)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
CREATE EXTERNAL TABLE IF NOT EXISTS cur_parquet ( payer_account_id string, linked_account_id string, product_name string, usage_start_date string, usage_end_date string, unblended_cost decimal(18,5), blended_cost decimal(18,5), amortized_cost decimal(18,5), usage_amount double ) PARTITIONED BY (year string, month string) STORED AS PARQUET LOCATION 's3://example-cur-bucket/cur/report-name/'; |
- 運用上の注意
- スキーマ変更(列追加)は Glue のスキーマ更新や ALTER TABLE で反映が必要です。Glue Crawler を使うと自動検出できますが、誤検知リスクもあるため変更管理を推奨します。
- Partition の登録は自動化(Lambda/Glue/Glue ETL)すると健全性が上がります。MSCK REPAIR はコストと時間がかかることがあるため、パーティション追加 API を使うかパーティションプロジェクションを検討してください。
Power Query と Python による前処理・正規化(実務例)
Excel(Power Query)と Python の双方で現場でよく使う前処理・正規化手順を示します。前提条件やよくある落とし穴も明示します。
列名の正規化とコスト列検出(Power Query: M 式)
Power Query では列名を一元的に正規化し、異なる入力フォーマットに対応することが重要です。以下は基本的な正規化パターンです。
|
1 2 3 4 5 6 7 8 9 |
// 列名を小文字化し、スラッシュ等をアンダースコアへ置換 Normalized = Table.TransformColumnNames(Source, each Text.Trim(Text.Lower(Text.Replace(Text.Replace(_, "/", "_"), " ", "_")))), // 存在チェックして不足列を追加(例) HasUnblended = if List.Contains(Table.ColumnNames(Normalized), "lineitem_unblendedcost") then Normalized else Table.AddColumn(Normalized, "lineitem_unblendedcost", each null), // 数値変換(通貨記号と千区切りを除去して en-US でパース) Parsed = Table.TransformColumns(HasUnblended, {{"lineitem_unblendedcost", each try Number.FromText(Text.Replace(Text.Replace(_, "¥", ""), ",", ""), "en-US") otherwise null, type number}}) |
列名が "lineItem/UnblendedCost" / "unblendedCost" / "unblended_cost" のように変わる場合、Table.ColumnNames をパターンマッチして正規名称へリネームするロジックを入れてください。
列名の正規化とコスト列検出(Python 実務例)
Python 側でも列名を正規化し、該当カラムをパターンで検出して統一カラムへリネームします。大規模データはチャンク処理でメモリ対策を行います。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
import boto3, io, re, pandas as pd from botocore.exceptions import ClientError s3 = boto3.client('s3') def normalize_cols(cols): out = [] for c in cols: c2 = c.strip().lower() c2 = re.sub(r'[\/\s\-]+', '_', c2) out.append(c2) return out def find_cost_col(cols, keys): for k in keys: matches = [c for c in cols if k in c] if matches: return matches[0] return None obj = s3.get_object(Bucket='example-cur-bucket', Key='cur/path/file.csv.gz') stream = io.BytesIO(obj['Body'].read()) # 小さなファイルならこれで単純 reader = pd.read_csv(stream, compression='gzip', iterator=True, chunksize=100000, dtype=str) agg = [] for chunk in reader: chunk.columns = normalize_cols(chunk.columns) unblended = find_cost_col(chunk.columns, ['unblendedcost','unblended_cost','lineitem_unblendedcost','unblended']) blended = find_cost_col(chunk.columns, ['blendedcost','blended_cost']) amortized = find_cost_col(chunk.columns, ['amortizedcost','amortized_cost']) if unblended: chunk['unblended_cost'] = pd.to_numeric(chunk[unblended].str.replace('[¥$,]', '', regex=True), errors='coerce') # 集約例(月次サービス別) chunk['usage_month'] = pd.to_datetime(chunk.get('lineitem_usagestartdate', chunk.get('usage_start_date'))).dt.to_period('M').astype(str) summary = chunk.groupby(['usage_month', 'product_name'])['unblended_cost'].sum().reset_index() agg.append(summary) result = pd.concat(agg).groupby(['usage_month','product_name'])['unblended_cost'].sum().reset_index() |
- 大容量対応のポイント
- pandas の chunksize を使ってチャンク処理する。
- S3 からのストリーミング読み込みでメモリピークを抑える(obj['Body'] はストリーミングオブジェクト)。ただし圧縮形式やファイル差により挙動が異なるためテスト必須。
- Parquet を使う場合は pyarrow.dataset で列選択と並列処理を検討する。
エラーハンドリングと監視のサンプル
処理にはリトライと障害通知を入れてください。例:S3 読み込みで ClientError が出たら指数バックオフで再試行し、最大再試行回数で SNS へ通知します。処理中の異常行は別ファイルに分離(dead-letter)する設計が望ましいです。
自動化オプション・運用設計・監視・コンプライアンス
自動化手段にはメリットと制約があります。制約を理解し、監視と障害時のフォールバックを設計してください。コンプライアンス要件(保持期間・PII・監査トレイル)も明確にします。
自動化オプション比較と実装上の制約
各自動化手段の特徴と注意点を示します。要件に応じて最適な組み合わせを選んでください。
- Office Scripts + Power Automate(Excel Online)
- 構成:OneDrive/SharePoint 上のブックに Power Query を置き、Power Automate で定期トリガー → Office Script でピボット更新・配布。
-
制約:Excel Online の Power Query は接続先が限定され、S3 など外部直接接続が使えないケースがあります。Office Scripts の実行時間や Power Automate の実行回数はテナント・ライセンスで制約されるため、大量データのクエリ刷新には向きません。
-
ローカル/サーバースクリプト(cron / Windows タスク / CI)
- 構成:定期ジョブで aws s3 sync → Python(boto3 + pandas)で ETL → Excel 出力(openpyxl/xlsxwriter)→ 共有保存。
-
制約:実行ホストの可用性、IAM 認証管理、ローカルリソース依存(メモリ/ディスク)を考慮します。
-
AWS Lambda + EventBridge(S3 イベント)
- 構成:CUR 到着をトリガーに Lambda を起動して軽量集計やパーティション登録を実施。重い処理は Glue/ECS へキューイング。
-
制約:Lambda は最大実行時間 15 分、メモリは最大 10,240 MB、/tmp はデフォルト 512 MB(必要に応じて増加可)などの制限があります。大容量処理は分割やバッチ処理が必要です。
-
Glue / ECS / Batch(大規模処理)
- 構成:大規模集計やスキーマ変換は Glue ETL(Spark)や ECS / Batch で実行。Lambda には向かない重いジョブを扱います。
- 制約:起動時間、コスト、スキーマ管理の複雑性を考慮してください。
運用設計・差分処理・監視
継続運用の設計例と監視ポイントを示します。
- 差分処理:処理済みファイル一覧や最終処理タイムスタンプを S3 メタデータや DynamoDB に保存し、新規ファイルのみ処理する運用を推奨します。
- エラー通知:失敗は SNS / Teams / Slack へ通知し、CloudWatch Logs に詳細を残します。
- 監視例(CloudWatch メトリクスフィルター)
- CloudWatch Logs で "ERROR" や "Exception" を検出し、メトリクス化してアラームを設定します。CLI サンプル(概念例):
|
1 2 3 4 5 6 |
aws logs put-metric-filter \ --log-group-name /aws/lambda/my-lambda \ --filter-name ErrorCount \ --filter-pattern '"ERROR" "Exception"' \ --metric-transformations metricName=ErrorCount,metricNamespace=BillingAutomation,metricValue=1 |
- ログとトレーシング:Lambda や Glue のログは CloudWatch、実行履歴は CloudTrail で保持し、監査可能な状態にします。
コンプライアンス(データ保持・PII・監査トレイル)
税務・会計の要件に従い保持期間を決定してください。具体的な運用例と注意点を示します。
- データ保持ポリシー例:
- 原本(CUR): 場合により 7 年等の法定保存期間に基づき S3 に保管(ライフサイクルで Glacier へ移行)。
- 集計結果:会計年度の要件に合わせて保持(例: 3〜7 年)。
- PII 保護:タグやリソース名に個人情報が含まれる可能性があるため、取り込み前にスキャンしてマスク/削除します。AWS Macie やカスタムスクリプトで検出すると良いです。
- 監査トレイル:S3 アクセスログ、CloudTrail、Glue/Athena の変更履歴を別バケットへ保存し、アクセスは KMS で制限します。必要に応じて S3 Object Lock(ガバナンス/コンプライアンスモード)を使います。
実行手順(番号化)と導入チェックリスト
ここでは導入の最短実行手順と初期チェック項目を示します。まず小さく確実に動く状態を作ることが重要です。
実行手順(簡潔な流れ)
- 単月CSVをダウンロードして Excel(Power Query)テンプレートで取り込み・整形を検証する。
- タグ方針と IAM ロール設計を決め、S3 バケットと CUR 設定(テスト用)を作る。
- CUR を Parquet(Snappy)で配信するテストを行い、Glue/Athena にテーブルを作成してクエリを検証する。
- Python または Glue で自動集計パイプラインを実装し、チャンク処理・例外処理・監視を組み込む。
- 本番化:S3 到着トリガーや定期スケジュールで自動実行し、運用監視とログ保存を有効化する。
導入チェックリスト(初期作業)
- CUR 設定:S3 バケット、ファイル形式(Parquet 推奨)、Include resource IDs / tags の確認。
- S3 バケット:バケットポリシー、暗号化(SSE-KMS)、バージョニング/ライフサイクルの設定。
- タグ設計:必須タグ、命名規則、未タグ検出ルール。
- IAM:請求閲覧用ロール、最小権限ポリシー、AssumeRole 信頼設定。
- テスト:単月CSVでテンプレート検証し、Power Query や Python の前処理を実行して結果を確認。
- 自動化:スケジューリング(cron / Task Scheduler / EventBridge / Power Automate)と失敗通知の設定。
- 監査:CloudTrail と S3 アクセスログを有効化し、ログ保管方針を確立する。
まとめ(導入後に維持すべき要点)
まず単月CSVで「動く状態」を作り、タグ運用・最小権限ポリシー・Secrets 管理を整備してから CUR(Parquet)への移行を検討してください。Parquet(Snappy)+適切なパーティション設計で Athena/Glue のコストと性能を最適化します。自動化は用途に応じて Office Scripts/Lambda/Glue を使い分け、監視・リトライ・死活監視とデータ保持・PII 保護・監査トレイルを運用ルールとして確立してください。要件によっては税務・会計担当や法務と最終確認を行ってください。