Claude Codeでコスト配分タグを整える — default_tagsと未タグ洗い出し
AWSのコスト配分タグをTerraformのdefault_tagsで一括付与し、未タグやEnv/envの表記ゆれをClaude Codeに読み取り専用で集計させる手順です。権限設定とplan差分の確かめ方を示します。
AWSのコスト配分タグを整える作業は、Claude Codeに「タグを読むコマンドだけ」を許可して現状を集計させ、直し方はdefault_tagsの差分とplanで確かめる流れにすると、人が見る場所を絞れます。タグの付け外しをCLIで直接やらせず、Terraformのコードに戻して直す。この分担が本記事の設計です。
先に落とし穴を1つ。タグ付きリソースを一覧するAPIは、タグが1つもないリソースを返しません。未タグには2種類あり、拾う道具が違います。以下、その切り分けから順に進めます。
「未タグ」には2種類あり、拾う道具が違う
未タグの2種類と、見つける手段
タグが1つもない
resourcegroupstaggingapiのGetResourcesは、タグ付き、または過去にタグ付きだったリソースを返します。タグなしのリソースは返りません。公式の注記は、Resource Explorerのクエリtag:noneを使うよう案内しています。
タグはあるが必須キーがない
EnvironmentやCostCenterなどのキーだけが欠けているリソースは、GetResourcesの結果に現れます。返ってきたタグの一覧から、必須キーを持たないものを選び出します。
GetResourcesは、指定した1つのリージョンの結果を返します。複数リージョンを使っているアカウントでは、リージョンごとに繰り返します。結果は複数ページに分かれますが、AWS CLIは既定でページを順に取得します。
Resource Explorerを使う前提
tag:noneのクエリは、Resource Explorerのビューを通して検索されます。ビューを明示しなければ、呼び出したリージョンの既定ビューが使われます。ビューが未設定のアカウントでは、先に設定が要ります。設定は書き込みを伴うので、Claudeに任せず人が行う作業として切り分けます。
default_tagsの仕様を先に押さえる
洗い出した結果をTerraformに戻す前に、AWSプロバイダーのdefault_tagsが何をするかを確認します。
provider "aws" {
region = "ap-northeast-1"
default_tags {
tags = {
Environment = "production"
Owner = "platform-team"
CostCenter = "cc-1001"
}
}
}プロバイダーのドキュメントとタグ付けガイドから、運用に効く点を並べます。
default_tagsで押さえる仕様
- 付与先は、
tags引数を持つAWSリソース全般です。例外としてaws_autoscaling_groupは対象外と明記されています - リソース側の
tagsに同じキーを書くと、その値が優先されます。上書きはできても、特定のリソースだけ除外はできません - 結合後のタグは読み取り専用の
tags_all属性で確認できます。tagsにはリソースに直接書いた分だけが入ります - 環境変数
TF_AWS_DEFAULT_TAGS_<キー名>でも渡せます。同じキーがプロバイダー設定にもあれば、設定側が優先されます
もう1点、ガイドには次の記述があります。Terraformが管理するタグ以外、つまりTerraformの外から付いたaws:で始まらないタグは、次回の実行で削除が提案されます。コンソールで手付けしたenvタグが残っているリソースにdefault_tagsを入れると、planにそのタグの削除が出る可能性があります。後述のplan確認で最初に見るのはここです。
外部のシステムが付けるタグを残したいときは、プロバイダーのignore_tagsが使えます。keysで完全一致、key_prefixesで前方一致を指定できます。
Claude Codeに渡す権限
読み取りに使うコマンドだけをallowに並べ、タグの書き込み系は明示的にdenyします。プロジェクトの.claude/settings.jsonに置く例です。
{
"permissions": {
"allow": [
"Bash(aws resourcegroupstaggingapi get-resources *)",
"Bash(aws resource-explorer-2 search *)",
"Bash(jq *)",
"Bash(terraform validate *)",
"Bash(terraform plan *)"
],
"ask": [
"Bash(terraform apply *)"
],
"deny": [
"Bash(aws resourcegroupstaggingapi tag-resources *)",
"Bash(aws resourcegroupstaggingapi untag-resources *)",
"Bash(aws ec2 create-tags *)",
"Bash(aws ec2 delete-tags *)",
"Bash(terraform destroy *)"
]
}
}権限設定のページに書かれた、この構成で効く規則を3つ挙げます。
*はサブコマンドの後ろに置きます。末尾に空白付きの*だけがある規則は、引数なしのコマンドにも一致します。- パイプでつないだ複合コマンドは、各部分がそれぞれ許可されている必要があります。
jqは組み込みの読み取り専用コマンドの例に挙がっていないので、上のように個別に許可しています。 - 許可ルールは、コマンドの文字列で照合されます。
--profileと--regionは、サブコマンドの後ろに付けるようClaudeに書かせます。aws --profile audit resourcegroupstaggingapi ...の形では、上のルールに一致しません。
denyルールは、絶対パスでの呼び出しやsh -cの中身までは止めません。ページの表もBash(rm *)を例に同じ限界を示しています。書き込みを確実に防ぐには、Claudeが使う認証情報を、タグの読み取りとplanに必要な範囲のIAM権限に絞ります。ルールは振る舞いを整える層、IAMは最終防壁と役割を分けます。サンドボックスで範囲を絞る方法は、allowWriteとdenyWriteの記事にあります。
タグの現状を集計する
ここからは、Claude Codeに出させる集計の中身です。まず、使われているタグキーを頻度順に並べます。aws:で始まるキーはAWSが管理するので除きます。
aws resourcegroupstaggingapi get-resources \
--region ap-northeast-1 --profile audit --output json \
| jq '[.ResourceTagMappingList[].Tags[].Key
| select(startswith("aws:") | not)]
| group_by(.) | map({key: .[0], count: length})
| sort_by(-.count)'Environmentが120件、envが35件、environmentが8件といった結果になれば、表記ゆれが見えます。キーは文字列として別物なので、集計でも別の行になります。どれを正とするかは人が決め、決めた名前をClaudeに伝えます。
次に、必須キーEnvironmentを持たないリソースのARNを出します。
aws resourcegroupstaggingapi get-resources \
--region ap-northeast-1 --profile audit --output json \
| jq -r '.ResourceTagMappingList[]
| select(([.Tags[].Key] | index("Environment")) == null)
| .ResourceARN'タグが1つもないリソースは、Resource Explorerで拾います。
aws resource-explorer-2 search \
--region ap-northeast-1 --profile audit \
--query-string "tag:none"2つの結果を合わせれば、「キーが足りない」と「タグが1つもない」の両方を網羅できます。ARNからリソースタイプとサービスが分かるので、Claudeには次のように指示すると、Terraform側の作業単位に落とせます。
上の2つの出力から、リソースを種類ごとに分類してください。
- 対応する aws_* リソースの種類
- Terraform管理かどうか(terraform state list の結果と突き合わせる)
- 管理外のものは、候補として一覧にするだけで、タグ付けはしないTerraformの管理下にあるかは、terraform state listで確かめられます。このコマンドは上の許可リストに入れていないので、使うなら実行前にallowへ追加します。
直す場所はTerraformに集める
集計の結果を、直し方ごとに3つに分けます。
直し方の3分類
共通キーが欠けている
default_tagsに追加します。リソースごとのtagsに同じキーが書かれていれば、重複を取り除きます。表記ゆれがある
正とするキーに統一します。リソース側に古い表記の
tagsが書かれていれば、書き換えます。Terraform管理外
コードに取り込むか、タグ付けを別の手順に回します。取り込みはTerraform importの記事の流れで進めます。
CLAUDE.mdには、正とするキーの決まりを短く書いておくと、Claudeが新しいリソースを書くときにも守ります。
## AWSタグの規約
- 共通タグは provider の default_tags に置く。リソースの tags には書かない
- キーは Environment / Owner / CostCenter の3つ。env や environment は使わない
- リソース固有の値だけ tags に書く(値を上書きする場合を含む)
- terraform apply は実行しない。plan の結果を報告して止まるplanの差分で確かめる
default_tagsを足して表記を統一したら、terraform planを実行させて、差分を次の順に読ませます。
plan結果の確認順
- 1
作り直しや削除がないか
リソースの置き換えや削除が1件でもあれば、そこで止めます。タグの変更だけなら、リソースはその場で更新されます。
- 2
タグの削除が出ていないか
Terraformの外から付いたタグは、削除が提案されます。
envのような古い表記が消える差分は、意図どおりかを1件ずつ確認します。残したいタグはignore_tagsに回します。 - 3
tags_allに共通キーが入っているか
default_tagsの追加は、tags_allの変更として現れます。リソース側のtagsが空でも、tags_allに3つの共通キーが入っていれば意図どおりです。 - 4
差分の件数が洗い出しと合うか
集計で出した対象リソースの件数と、planの更新件数が大きくずれていないかを見ます。ずれが大きければ、管理外のリソースや別のリージョンが混ざっています。
適用は人が行います。上の設定でterraform applyはaskにしてあるので、Claudeが実行しようとすると確認が出ます。差分に作り直しや削除がないことを確かめてから承認します。
ドリフトを検出して分類する手順も、同じ考え方でplan差分を読みます。コンソールで付けたタグの食い違いは、ドリフトとして扱うこともできます。
コスト配分タグとして効かせる最後の一手
タグを揃えただけでは、請求の画面には現れません。AWSのドキュメントによると、コスト配分タグは次の手順を踏んでから使えます。
- ユーザー定義タグのキーを、Billing and Cost Managementのコンソールで有効化します。有効化はキー単位で、同じキーの値すべてに効きます
- 付与から有効化の候補に出るまで最大24時間、有効化されるまでさらに最大24時間かかります
- コスト配分タグの管理画面を使えるのは、組織の管理アカウント、または組織に属さない単独のアカウントだけです
UpdateCostAllocationTagsStatusというAPIで一括有効化もできます。これは課金のレポートに影響する操作なので、Claudeの許可リストには入れず、人が実行します。
有効化の効果は、Cost Explorerなどの画面で確認できます。コスト配分レポートには、タグ付きと未タグのリソースの両方が含まれます。未タグ分の金額が減っていけば、整理が効いている目安になります。請求額の増減を使用タイプまで分解する方法は、Cost ExplorerのCSVで急増を調べる記事にあります。
よくあるつまずき
落とし穴
aws_autoscaling_groupだけタグが付かない
default_tagsはaws_autoscaling_groupを対象外としています。このリソースには、個別のtagsブロックで明示します。
落とし穴
特定のリソースだけ共通タグを外せない
default_tagsは上書きはできても、除外はできません。外したいリソースが多いなら、プロバイダーを別名(alias)で分け、そのプロバイダーにはタグを定義しないという構成を検討します。
落とし穴
get-resourcesの結果に、既知のリソースが出てこない
指定したリージョンのリソースしか返りません。また、タグが1つもないリソースは返りません。後者はResource Explorerのtag:noneで拾います。
未使用のリソースを見つけて消す作業は、タグの整理とは別の作業です。そちらは未使用リソースの洗い出し記事にまとめています。コスト配分タグでは「誰のコストか」を付け、未使用の洗い出しでは「使われているか」を見る。順序としては、タグを先に揃えておくと、後者の判断材料にも使えます。
まとめ
タグ整理の安全性は、Claudeに任せる範囲を「読む」までに絞ることで決まります。書き込み系のコマンドをdenyし、直し方はdefault_tagsとtagsの差分としてコードに集め、planで作り直しとタグ削除がないことを確かめてから適用する。この3点が揃えば、人が見るのはplanの差分1か所です。
最後に、有効化を忘れると請求画面には何も現れません。Terraformの適用後、最大で48時間ほど待ってから、Cost Explorerでタグ別の表示を確認します。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。
- code.claude.com/docs/en/permissions
- registry.terraform.io/providers/hashicorp/aws/latest/docs
- registry.terraform.io/providers/hashicorp/aws/latest/docs/guides/resource-tagging
- docs.aws.amazon.com/cli/latest/reference/resourcegroupstaggingapi/get-resource…
- docs.aws.amazon.com/cli/latest/reference/resource-explorer-2/search.html
- docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html
- docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/activating-tags.html