はじめに
AWS Cost Categoriesは、AWS利用料をルールに基づいてカテゴリ分類しコスト状況を把握・整理できる機能です。
アカウント、タグ、サービスなどに基づいてルールを定義できます。機能の詳細は公式ドキュメントをご覧ください。
この記事では、AWS Cost Categoriesによる分類を、AWS Organizationsの「組織単位(OU)」に自動的に同期するアプローチを紹介します。
*図1: Cost Categoriesの利用(マネジメントコンソールから手動設定)
*図2: OrganizationsのOU階層でコスト可視化
仕組み
アプローチの詳細
- 自動化の必要性: OUの構成変更やアカウント追加するたびにCost Categoriesを手動更新するのは手間がかかり、ミスも発生しやすいです。直接OUに紐づける設定は2025年9月時点では存在しません
-
実装: Cost Categoriesのルールは直接OUに紐付けができないため、簡単なスクリプトで以下のロジックを実装します:
ListAccounts
を使用してすべてのアカウントを一覧表示- 各アカウントに対して
ListParents
を使用してOUパスを特定 - 特定したOUパス名に相当するコストカテゴリ名をアカウントを割り当て。OU階層はパラメータで指定した
depth
の深度まで細分化。 - Cost Categories上に、OUパス名のカテゴリにアカウントIDのリストを
Dimensions
にマッピングするルールを作成
図3: 今回構築する構成
- 実行: Python3.x/Boto3を使用。AWS CloudShellなどの環境からの実行を想定。スケジュールされたLambda実行にも対応可能(パラメータ入力の変更と実行制限の考慮が必要)。
スクリプトの機能
- 階層カテゴリ:
Level1OU-Level2OU-...
のような名前を作成 - 深度制御:
depth
引数で粒度を設定
注意点
- このスクリプトはサンプルです。本番環境で使用する前に十分にテストしてください。
- 必要なOrganizations APIとCost Explorer APIにアクセスするため、管理アカウント上での実行を前提としています。
- 最小権限の原則: 管理者権限でスクリプトを実行しないでください。 最小限の必要な権限のみを持つ専用のIAMロールを作成し、そのロールを使用して実行してください(例:CloudShell、EC2、Lambda)。
スクリプト
スクリプトはGitHubで公開しています。
リポジトリ:
https://github.com/shu85t/PutOuCostCategory
前提条件
- Python: バージョン3.9以降
- Boto3: Python用AWS SDK(
pip install boto3
)。最新バージョンを使用してください - AWSアカウント: AWS Organizationの管理アカウントへのアクセス
実行環境
- このスクリプトは、必要なIAM権限(下記参照)を持つAWS Organizationの管理アカウント上で実行する必要があります。
- 管理アカウント上でAWS CloudShellを利用するのがわかりやすい例です。
- 必要な権限を持つ実行ロールが提供されていれば、管理アカウント内のEC2インスタンスやAWS Lambda関数でも実行できます。
使用方法
コマンドライン実行
python3 put_ou_cost_category.py <CostCategoryName> <EffectiveStartMonth> <Depth>
引数
(必須): 作成または更新するCost Categoriesの名前(例:OrganizationStructure
、OUHierarchy
)
(必須):YYYY-MM
形式の有効開始月(例:2025-04
)。スクリプトはAPI呼び出しでこの月の初日(UTC午前0時)を使用します
(必須): カテゴリを作成するOU階層の最大深度を指定する整数(1以上)
* 1
: Root
と第1レベルOUのカテゴリを作成
* 2
: Root
、第1レベルOU、第2レベルOU(例:OU1-OU1A
)のカテゴリを作成
* アカウントは常に指定された深度までの最も深いカテゴリに割り当てられます
ログレベル設定
LOG_LEVEL
環境変数を使用してログの詳細度を制御できます。デフォルトはINFO
です。
# 例: DEBUGログで実行 export LOG_LEVEL=DEBUG python3 put_ou_cost_category.py MyOUCategory 2025-04 2 # または一時的に1つのコマンドで LOG_LEVEL=DEBUG python3 put_ou_cost_category.py MyOUCategory 2025-04 2
IAM権限
このスクリプトを実行するIAMプリンシパル(ユーザーまたはロール)には以下の権限が必要です:
必要なアクション:
organizations:ListAccounts
organizations:ListParents
organizations:DescribeOrganizationalUnit
organizations:ListRoots
ce:ListCostCategoryDefinitions
ce:CreateCostCategoryDefinition
ce:UpdateCostCategoryDefinition
実行例
サンプルOU構造での動作例を紹介します。
サンプルOU構造
Root ├── Management Account │ ├── Management OU │ ├── Management Tool Account1 │ └── Management Tool Account2 │ ├── Sandbox OU (直接アカウントなし) │ ├── Security OU │ ├── Audit Account │ └── Log Archive Account │ └── SDLC OU ├── Dev OU │ └── Workload Dev Account └── Stg OU └── Workload Staging Account
depth=1
での結果
コマンド:
python3 put_ou_cost_category.py OUStructure 2025-01 1
結果:
depth=2
での結果
コマンド:
python3 put_ou_cost_category.py OUStructure 2025-01 2
結果:
OU階層に沿ったカテゴリ分類を実現することができました
図4: 実際のソリューション実行結果とコスト分析画面
スクリプトの動作原理
組織構造の取得
# --- Core Functions --- def get_organization_structure(max_depth): """ Retrieves Org structure assigning accounts to deepest category up to max_depth. Returns dict or None. Propagates exceptions. """ logger.info(f"Fetching organization structure (assigning accounts to deepest path up to depth {max_depth})...") ...
list_accounts
を使用してすべてのアカウントを一覧表示することから開始- 各アカウントについて、
list_parents
APIを使用してRootまでの親OUの完全なパスをトレース describe_organizational_unit
を使用してOU名を取得(効率向上のためget_ou_name
でローカルキャッシュ)- OUパスと提供された
max_depth
に基づいて、最終的なカテゴリ名(例:L1OU-L2OU
)を構築 - 重要なのは、各アカウントが深度制限内での最も深いOU配置を表す単一のカテゴリに一意に割り当てられること
- 最終的に、生成されたカテゴリ名をキー、対応するアカウントIDのリストを値とするPython辞書を返す
Cost Categoriesルールの構築
def build_cost_category_rules(org_structure): """ Builds rule list. Skips categories with empty accounts. Propagates exceptions. """ logger.info("Building Cost Categories rules...") ...
- 入力辞書(カテゴリ名とアカウントリストのマッピング)を受け取り、アカウントを持つ各カテゴリをAPI用にフォーマットされたルールオブジェクトに変換
- 実際にアカウントが割り当てられたカテゴリに対してのみ生成されたルールを含むリストを返す
Cost Categoriesの設定
def put_cost_category(cost_category_name, rules, default_value, effective_start_iso_str): """ Creates/Updates Cost Categories. Returns True on success. Raises exceptions on failure. Logs raw parameters. """
- まず
find_cost_category_arn
を使用して指定されたcost_category_name
のCost Categoriesが既に存在するかチェック。結果に基づいて、create_cost_category_definition
またはupdate_cost_category_definition
API呼び出しに必要なパラメータを準備 - API呼び出し前に、ドキュメント化された制限に対してルール数とルールあたりのアカウント数の事前チェックを実行
- 検証に合格した場合、適切なAPI呼び出し(作成または更新)を実行してAWSで変更を適用
参考資料
今回はPythonでコードを書き、AWSへのアクセスはboto3を使用しています。参考としてSDKドキュメントのリンクを記載します。
余談ですが、APIで定義されている引数やレスポンスの仕様を公式ドキュメントで読んでおくと、AWSサービス自体の理解、動作、様々なオプションを把握するのに役立ちます。
あわせてCloudWatchメトリクスでとれる情報、クォータ制限にも目を通しておくと非機能要件として留意すべき観点も学べます。
まとめ
AWS Cost CategoriesをAWS Organizations OU構造と自動的に同期する方法を提供します。
これによりOU分類という断面でコスト把握・分析ができるようになりました。