3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code × Bedrock を組織展開するためのAWSコスト管理ノウハウ

3
Last updated at Posted at 2026-06-14

Claude Code on Bedrock を組織で展開するとき、避けて通れないのがコスト管理です。AWSは公式にOIDC認証 + OpenTelemetryベースの監視基盤を公開していますが、ECS等のインフラ運用が伴い、小規模チームには重い構成です。

LiteLLMをGatewayとして挟むパターンも見かけますが、ホスティングするサーバーの料金やメンテナンス負荷は無視できません。

この記事では、そうしたミドルウェアを自前で立てずに、AWSマネージドサービスだけで「個人別コストの可視化」「トークン使いすぎ時の自動停止」「APIキーの漏洩対策」を実現する方法をまとめます。

なお、IAM Identity Centerが使えず、長期APIキーで運用せざるを得ない環境を前提にしています。

突然ですが、メンバーアカウントだけ渡されてOrganizationsには触れないことってありませんか?

Claude Code on Bedrockの認証方式として、ベストプラクティスはIAM Identity Center(IIC)を使う方式です。ユーザーは aws sso login でIICにログインし、取得した一時的な認証情報でBedrockを操作します。APIキーを端末に保持する必要がなく、セッション期限が切れれば自動的にアクセスが失効するため、セキュリティ上も安全です。

しかし、IICを設定できるのはOrganizations の管理アカウント、または委任管理者アカウントに限られます。

実際には以下のようなケースで、IICが使えないことは珍しくありません。

  • パートナー企業からメンバーアカウントだけ払い出されている
    顧客やパートナーのOrganizations配下でアカウントを利用しており、管理アカウントへのアクセス権がない
  • 社内CCoEがOrganizationsを一元管理している
    クラウド推進部門がOrganizationsを管理しており、自部門にはメンバーアカウントだけ割り当てられている。IICの設定変更を依頼しても、組織全体のポリシーとの整合性から簡単には通らない

「IICが使えないからBedrock展開を諦める」のはもったいないことです。Bedrockの長期APIキーでも、適切な対策を組み合わせれば組織展開は十分に可能です。

なぜLiteLLMやOTEL基盤を使わないのか?

組織でのLLM利用を管理する手段として、LiteLLM GatewayやOTEL監視基盤がよく話題に上がります。どちらも優れたソリューションですが、小規模組織には合わないケースがあります。

LiteLLM Gateway は、Proxyサーバーとして立てることでユーザー別のトークン消費量やコストを管理画面で一元追跡できます。しかし、LiteLLM自体をホスティングするサーバー(EC2/ECS等)が必要です。アップデート追従、可用性の確保、ログ管理といった運用負荷が継続的にかかります。10〜数十名規模であればオーバーキルになりがちです。

AWSが公開しているguidance-for-claude-code-with-amazon-bedrock は、OIDC IdP連携(Okta, Azure AD等)を主軸に、オプションでOTELコレクター(ECS)+ Firehose + Ath
ena + CloudWatchの監視基盤を構築できるフルスタック構成です。エンタープライズ向けとして完成度は高いものの、OIDC IdPの準備やECSタスクの運用など、導入・維持のハードルは低くありません。

この記事では、Budgets、CUR 2.0、Athena、QuickSightなど、すべてAWSマネージドサービスで構築します。自前のサーバーを立てないので構築後の運用負荷を抑えられますし、Quick Sightを除けばAWS利用料もほぼゼロです。

Bedrockの長期APIキーには有効期限を短く設定し、定期ローテーションを必須にする

Bedrock APIキーには短期キー(有効期限12時間)と長期キーの2種類があります。短期キーは個人の一時的な検証には向きますが、12時間で失効するため組織的な日常利用には適しません。組織配布では長期キーを使うことになります。

ただし、長期キーだからといって有効期限を無期限にしてはいけません

長期APIキーでも、有効期限はできるだけ短く設定して作成するのが鉄則です。長くても90日を目安に設定し、定期的にローテーションする運用を仕組み化しましょう。

APIキーを安全に配布する — settings.jsonテンプレートとIAMポリシーによるIP制限

Claude CodeにAPIキーを読ませない — denyルールで漏洩経路を塞ぐ

Claude Codeはシェルコマンドを実行できるため、環境変数に設定したAPIキーを echo $AWS_*env | grep key などで読み取れてしまいます。また、APIキーを export している .bashrc.zshrccat で開かれれば、そこからもキーが露出します。キーの保管場所が環境変数であれ設定ファイルであれ、Claude Codeのツール経由でキーが露出しないようにすることが重要です。

settings.jsondeny ルールで、秘密情報を表示し得るコマンドを明示的にブロックします。

settings.json(配布テンプレート例)
{
  "permissions": {
    "allow": [
      "Bash(npm run *)",
      "Bash(git *)"
    ],
    "deny": [
      "Bash(cat *credentials*)",
      "Bash(cat *secret*)",
      "Bash(cat *.env*)",
      "Bash(cat *bashrc*)",
      "Bash(cat *zshrc*)",
      "Bash(cat *profile*)",
      "Bash(echo $AWS_*)",
      "Bash(echo $ANTHROPIC_*)",
      "Bash(env | grep -i key)",
      "Bash(env | grep -i secret)",
      "Bash(env | grep -i token)",
      "Bash(printenv *)"
    ]
  }
}

APIキー自体は環境変数で注入します。各ユーザーの .bashrc.zshrc に以下を設定してもらいます。

export AWS_BEARER_TOKEN_BEDROCK="xxxxxxxxxxxxxxxxxxxxxxxx"
export AWS_REGION="ap-northeast-1"

Claude Codeは認証時にこの環境変数を内部的に参照しますが、上記の deny ルールにより、シェルコマンド経由で値を画面に表示したりログに出力したりすることはブロックされます。

この settings.json テンプレートをチーム内に配布し、全員が同じセキュリティベースラインで運用できるようにします。

IAMポリシーでAPIキーの利用元IPを制限する

長期APIキーの漏洩リスクをさらに下げるために、IAMユーザーポリシーに aws:SourceIp 条件を付与します。

IAMポリシー例(IP制限)
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "AllowBedrockFromOfficeOnly",
			"Effect": "Deny",
			"Action": "*",
			"Resource": "*",
			"Condition": {
				"NotIpAddress": {
					"aws:SourceIp": [
						"203.0.113.0/24",
						"198.51.100.0/24"
					]
				},
				"Bool": {
					"aws:ViaAWSService": "false"
				}
			}
		}
	]
}

自社プロキシがある場合はプロキシのグローバルIPアドレスを、VPN環境であればVPNゲートウェイのCIDRを指定しておけば、万が一キーが漏洩しても、許可IP以外からのBedrock呼び出しは拒否されます。Deny + NotIpAddress の組み合わせにより、ホワイトリスト方式で制御できます。

AWS Budgetsで個人ごとにコスト上限アラートを仕掛ける

APIキーの漏洩や意図しない大量利用を早期に検知するために、AWS Budgetsで個人単位のコストアラートを設定します。

ポイントは IAMプリンシパルタグ の活用です。設定は以下の2ステップです。

  1. IAMユーザー(Bedrock APIキー)に個人を識別するタグを付与する(例:Name = k-gamo
  2. そのタグをIAMプリンシパルのコスト配分タグとして有効化する — Billing and Cost Managementコンソールの「コスト配分タグ」から、IAMプリンシパルタグとして有効化します

コスト配分タグの有効化はOrganizations管理アカウント上で行う必要があります。メンバーアカウント単独では有効化できないため、管理アカウントの管理者に依頼してください。冒頭で述べたようにOrganizationsに触れない環境では、この点が唯一の管理アカウント依頼事項になります。

コスト配分タグが有効化されると、Budgetsのフィルタ条件で個人を指定できるようになります。Bedrock専用のAPIキーとしてIAMユーザーが作成されるため、そのユーザーのコスト=Bedrock利用コストとなり、サービスフィルタを別途指定しなくてもBedrock利用に限定されます。

1つの月次バジェット複数のしきい値を設定し、段階的にアラートとアクションを発動させる以下の構成がおすすめです。

しきい値 種別 用途 アクション
50%(ACTUAL) 異常検知 月半ばで半額消費は明らかに異常 → 使いすぎ・漏洩の早期検知 メール通知(本人+管理者)
80%(ACTUAL) 使いすぎ警告 予算上限が近づいていることを本人に自覚させる メール通知(本人+管理者)
100%(ACTUAL) 自動遮断 予算超過時にAPIキーを自動無効化(サーキットブレイカー) Budget Actionsで DenyAllService ポリシーを自動適用
100%(FORECASTED) 予測アラート 月末に超過しそうな場合の事前警告 メール通知(本人+管理者)

月次一本にまとめることで、後述するBudget Actions(しきい値超過時のIAMポリシー自動適用)が使えるようになります。Budget Actionsは月次・四半期・年次のバジェットで利用可能で、日次バジェットでは利用できません。

# 月次コスト予算($500/月 — 複数しきい値 + Budget Actions)
aws budgets create-budget \
  --account-id $ACCOUNT_ID \
  --budget '{
    "BudgetName": "Bedrock-Monthly-k-gamo",
    "BudgetLimit": {"Amount": "500", "Unit": "USD"},
    "TimeUnit": "MONTHLY",
    "BudgetType": "COST",
    "CostFilters": {
      "TagKeyValue": ["user:iamPrincipal/Name$k-gamo"]
    }
  }' \
  --notifications-with-subscribers '[
    {
      "Notification": {
        "NotificationType": "ACTUAL",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 50,
        "ThresholdType": "PERCENTAGE"
      },
      "Subscribers": [
        {"SubscriptionType": "EMAIL", "Address": "k-gamo@example.com"},
        {"SubscriptionType": "EMAIL", "Address": "ai-admin@example.com"}
      ]
    },
    {
      "Notification": {
        "NotificationType": "ACTUAL",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 80,
        "ThresholdType": "PERCENTAGE"
      },
      "Subscribers": [
        {"SubscriptionType": "EMAIL", "Address": "k-gamo@example.com"},
        {"SubscriptionType": "EMAIL", "Address": "ai-admin@example.com"}
      ]
    },
    {
      "Notification": {
        "NotificationType": "FORECASTED",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 100,
        "ThresholdType": "PERCENTAGE"
      },
      "Subscribers": [
        {"SubscriptionType": "EMAIL", "Address": "k-gamo@example.com"},
        {"SubscriptionType": "EMAIL", "Address": "ai-admin@example.com"}
      ]
    }
  ]'

以下、マネジメントコンソール上でのフィルタ設定画面です。

image.png

image.png

TagKeyValue のフィルタ書式は "user:iamPrincipal/Name$<ユーザ名>" です。Budgetsのタイプはコスト予算(COST)を選択してください。

通知先は本人 + 管理者の同報にしておくと、本人が気づかなくても管理者がキャッチできます。

AWS Budgetsが参照する課金データの更新は日次です。リアルタイムではないため、しきい値超過の検知からアラート発行まで最大24時間程度の遅延が発生する可能性があります。50%しきい値による早期検知と、100%しきい値での自動遮断を組み合わせることで、この遅延の影響を最小限に抑えられます。

Budget Actionsで予算超過時にAPIキーを自動無効化する「サーキットブレイカー」

前述のIP制限が適用できている環境であれば、キー漏洩による外部からの不正利用リスクは大幅に下がります。ただし、グローバルIPを固定できないケースには対応できません。そうした場合に備えて、もう一歩踏み込んだ仕組みとしてBudget Actionsを使い、予算超過時にIAM Denyポリシーを自動でアタッチするサーキットブレイカーを構築します。

Budget ActionsはAWS Budgetsのネイティブ機能で、しきい値超過時に以下のアクションを自動実行できます。

  • IAMポリシーの適用(任意のアカウントで利用可能)
  • SCPの適用(Organizations管理アカウントのみ)
  • EC2/RDSインスタンスの停止

SNSやLambdaを自前で組む必要がありません。

Denyポリシーを事前に作成する

まず、Budget ActionsがアタッチするDeny ALLポリシーをIAMカスタマー管理ポリシーとして作成しておきます。

DenyAllService ポリシー
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyAllService",
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*"
    }
  ]
}

このポリシーは通常時はどのユーザーにもアタッチしません。Budget Actionsがしきい値超過を検知したときに、対象ユーザーへ自動でアタッチされます。

Budget Actionsの実行ロールとアクションを設定する

Budget Actionsがユーザーにポリシーをアタッチするには、Budgetsサービスが引き受けるIAMロールが必要です。信頼ポリシーで budgets.amazonaws.com を許可し、iam:AttachUserPolicy / iam:DetachUserPolicy の権限を付与します。

ロールを作成したら、月次バジェットの100%しきい値に対してBudget Actionsを設定します。Budgetsコンソールでバジェットを編集し、「Attach actions」から以下を指定します。

  • IAM role: 上で作成した実行ロール
  • Action type: IAM Policy
  • IAM policy: DenyAllService
  • Target user: 対象のIAMユーザー(例: k-gamo_bedrock_apikey
  • Auto execute: Yes

処理フローは以下のとおりです。

  1. AWS Budgets が100%しきい値超過を検知
  2. Budget Actions が自動実行される
  3. 対象IAMユーザーに DenyAllService(Deny ALLポリシー)が自動アタッチ
  4. そのIAMユーザーのAWS API呼び出しが即座に拒否される

以下、Budgets Actionの設定画面です。

image.png

CUR 2.0 + Athena + QuickSightで「誰がいくら使ったか」を可視化する

ここまでで「APIキー漏洩防止」と「トークン使いすぎ時の自動停止」はカバーできました。あとは「誰がどのモデルをいくら使っているか」を全員が見られるようにします。

CUR 2.0のIAMプリンシパルデータが個人別追跡の鍵

AWS Data Export でCUR 2.0(Cost and Usage Report 2.0)を出力する際に、「Include caller identity (IAM principal) allocation data」を有効化します。これにより、line_item_iam_principal カラムにAPI呼び出し元のIAMユーザーARNが記録されるようになります。

arn:aws:iam::123456789012:user/k-gamo_bedrock_apikey
arn:aws:iam::123456789012:user/suzuki_bedrock_apikey

さらに、IAMユーザーに付与したタグ(Nameteam 等)をコスト配分タグとして有効化すると、CUR 2.0上で tags['iamPrincipal/Name'] のようにタグ値でも集計できます。Budgetsのフィルタと同じタグを流用できるので、一度タグを付けておけばアラートと可視化の両方で使えます。

Data Export → S3 → Glue → Athena のパイプラインは月額約$1

構成はシンプルです。

Data Export(日次・Parquet形式)
    ↓
S3バケット
    ↓
Glue Crawler(スキーマ自動検出)
    ↓
Athena(SQLで個人別コスト集計)

月額コストの内訳は、S3が約0.5 USD、Glueが約0.01 USD、Athenaが0.01 USD未満で、合計約1 USD/月です。数十名規模のBedrock利用データであれば、この程度で収まります。

AthenaでBedrockの利用料だけを抽出するSQLは、以下のようになります。

SELECT
    tags['iamPrincipal/Name'] AS user_name,
    billing_period,
    SUM(line_item_unblended_cost) AS total_cost_usd
FROM cur_data_export_db.cur_data
WHERE line_item_line_item_description LIKE '%Token%'
  AND line_item_line_item_type != 'Tax'
  AND line_item_unblended_cost > 0
GROUP BY
    tags['iamPrincipal/Name'],
    billing_period
ORDER BY total_cost_usd DESC;

Bedrockの line_item_product_code にはLLMのモデル固有のMarketplace製品IDが入るため、'AmazonBedrock'などのサービス名でフィルタできません。line_item_line_item_description LIKE '%Token%' でトークン課金行を捕捉するのがおすすめです。

QuickSightでダッシュボード化すれば全員がコストを確認できる

AthenaをデータソースにAmazon Quick Sight(Amazon QuickのBI機能)のSPICEに日次で取り込めば、ブラウザからダッシュボードを閲覧できます。

コストは Author 1名で$24/月、閲覧者(Reader)は $3/月/人 です。まずAuthor 1名でダッシュボードを構築し、完成後に必要な人数分のReaderを追加する段階的なスケールが可能です。

個人別の日次コスト推移、モデル別の利用比率、チーム別の集計など、カスタムSQLで加工したデータをそのままビジュアライズできます。

以下、私が構築したダッシュボードの例です。

ユーザ別のBedrock利用料が可視化できます。

image.png

ユーザごとのモデル別トークン消費量やトークン消費パターン(INPUT/OUTPUT/CacheRead/ChacheWrite)も可視化できます。
image.png

Quick Sightのサインアップ時、デフォルトで「Admin Pro」ロールが設定される場合があります。Proロールのユーザーが1人でもいると $250/月のAmazon Qインフラ費 が発生します。サインアップ直後にロールが「Admin」(Proなし)であることを必ず確認してください。

全体像 — 3層のコスト管理で「使わせる」と「守る」を両立する

ここまで紹介した仕組みを整理すると、以下の3層構成になります。

目的 構成要素 月額コスト
第1層: APIキー漏洩防止 事前防御 APIキーローテーション + settings.jsonテンプレート + IP制限 $0
第2層: 異常検知&自動停止 即時対応 Budgets(複数しきい値)+ Budget Actions サーキットブレイカー $0
第3層: 可視化 日常モニタリング CUR 2.0 + Athena + QuickSight ~$25〜(Author 1名)

第1層と第2層はAWS利用料がかかりません。SNSやLambdaすら不要で、Budgetsの標準機能だけで完結します。Quick Sightは Author 1名で月$25程度かかりますが、LiteLLMのサーバー運用やOTEL基盤のメンテナンスと比べれば、構築後の運用負荷は段違いに低いです。

まとめ

IAM Identity Centerが使えない環境でも、AWSマネージドサービスの組み合わせだけでClaude Code on Bedrockのコスト管理は十分に実現できます。

  • まず第1層・第2層から始めるのがおすすめです。Budgets + Budget Actions + IP制限 + APIキーローテーションで最低限のガードレールを敷くのは即日でできます
  • 並行して第3層の可視化基盤を整える。 CUR 2.0のData Exportは初回データ出力まで最大24時間かかるので、早めに設定しておくと後が楽です
  • 長期APIキーの有効期限は短く。 ローテーション運用を仕組み化しておくことで、キー漏洩時の影響範囲を時間的に限定できます

組織でAIツールを展開するとき、コスト管理は「あると嬉しい」ではなく「ないと始められない」ものです。同じ悩みを抱える方の参考になれば幸いです。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?