# エージェントに渡す鍵の形——短期・スコープ・上限の三点セット

> AWS Japan の認可疲れ論、Retty の $OPENAI_API_KEY 廃止、Gemini の無制限キー拒否——同じ週の三つの話は同じ一点を指す。権限はダイアログではなく鍵の形に。600 秒・300 秒・3600 秒から設計と請求書を整理します。

- Published: 2026年8月21日
- Author: Leo Kaka, Engineering
- Tags: security, api-keys, agents
- Canonical: https://pirouter.ai/ja/blog/agent-credentials

---
**エージェントに権限を渡す場所は、実行時の確認ダイアログではなく、鍵そのものの形です。**
今週、別々に見える三つの話がその一点に収束しました。AWS Japan の icoxfog417 氏による[「AI エージェントの『認可疲れ』に効く処方箋」](https://zenn.dev/aws_japan/articles/2b62886aa8735e)、
Retty の pikatenor 氏による[「NO MORE $OPENAI_API_KEY」](https://engineer.retty.me/entry/openai-aws-identity-federation)、
そして Gemini API が[無制限 API キーのリクエストを拒否する](https://ai.google.dev/gemini-api/docs/api-key)という方針。
三つを一枚の表に並べると、残る結論はこれ一つです。鍵の形は三つの要素で決まります——
**短期**（長期キーを配らず、数分のトークンに交換する）、**スコープ**（エンドポイント・操作・モデルを
鍵の中に書く）、**上限**（鍵ごとの予算とレート）。言い換えると、有効期限・権限範囲・予算上限が
キーの属性として最初から付いている状態です。以下、三つの一次情報を順に読み、最後に
その設計の請求書を書きます。

## 今週の三つの出来事

| 出来事 | 何が変わったか | 一次情報 |
|---|---|---|
| AWS Japan が「認可疲れ」の処方箋を公開 | エージェントの認可要求を、実行時のダイアログから一度の認証＋トークン交換（RFC 8693）へ | [Zenn 記事](https://zenn.dev/aws_japan/articles/2b62886aa8735e)（2026-08-16） |
| Retty が本番アプリから `$OPENAI_API_KEY` を撤去 | ECS タスクロール（IAM ロール）を STS が署名した JWT で証明し、OpenAI の短期トークンに交換 | [Retty Tech Blog](https://engineer.retty.me/entry/openai-aws-identity-federation)（2026-08-20） |
| Gemini API が無制限キーを拒否 | 無制限 standard キーを拒否（開始日 6/19 はフォーラム告知）、2026 年 9 月には standard キー全体を拒否し auth キーへ移行 | [Google 公式ドキュメント](https://ai.google.dev/gemini-api/docs/api-key)、[公式フォーラム告知](https://discuss.google.dev/t/gemini-api-update/375447) |

三つとも主語が違います。一つ目はエージェント基盤を作る側、二つ目はエージェントを使う
アプリを作る側、三つ目はモデルを提供する側です。立場の異なる三者が同じ週に同じ方向へ
動いたことに意味があります。なお、同じ週の Zenn には ito 氏の[「AI エージェントはなぜテストを握り潰すのか」](https://zenn.dev/ito/articles/6b042aa27d65bc)もあり、
エージェントは「完了」までの最短経路を選ぶ、と整理されています。権限の境界をプロンプトの
お願いではなく環境の側に置くべき理由は、この一文で足ります。

## 認可疲れの正体——要求が飛ぶのは実行時

AWS Japan の記事が整理する流れは三段階です。(1) ユーザーが社内 IdP（ID プロバイダ。Google や
Entra ID のような認証基盤）で認証し、エージェントが `id_token` を受け取る。(2) エージェントが
ツール（MCP サーバー経由の外部サービス）ごとに認可をユーザーへ求める。
(3) 認可済みのツールを代理実行する。問題は (2) の発生タイミングで、認可要求はツールを
実行しようとした瞬間にしか飛びません。「仕事を任せたと思ったら認可待ちで止まっていた」
という記事の表現は、エージェントを運用したことがある人なら身に覚えがあるはずです。

記事の処方箋は、ダイアログを減らすことではなく、**(2) を (1) の結果から機械的に導く**ことです。
IdP が発行した `id_token`（「誰が認証したか」の証明）を外部サービスの認可サーバーに提示し、
そのサービス宛の `access_token`（「何をしてよいか」の許可）に交換する。RFC 8693 のトークン交換、その中でも「ユーザーの代理として」の
用法を OBO（On-Behalf-Of）と呼びます。交換後のトークンには、元の `id_token` になかった
二つのクレームが入ります。

| クレーム / 応答値 | 値 | 意味 |
|---|---|---|
| `scope` | `order:read order:write` | このトークンで許される操作の範囲 |
| `act.sub` | エージェントの `client_id` | 誰が代理で取得したか |
| `expires_in` | 600 | 有効期間は 10 分（記事の実装例） |

つまり、権限の範囲と代理実行者のアイデンティティが、**鍵の中に書かれた状態で**エージェントに渡ります。
スコープが足りない操作は、ダイアログではなく 403 で止まります。

![デモ画面：受注一覧は成功、発注一覧は「スコープ不足で拒否されました（purchase_order:read が必要）— HTTP 403」](/blog/images/agent-credentials-scope-403.png "図 1 — 同じユーザー、同じエージェント。scope に無い操作は実行時に 403 で落ちる。確認ダイアログは出ない。出典：[Zenn・icoxfog417 氏（AWS Japan）の記事](https://zenn.dev/aws_japan/articles/2b62886aa8735e)より引用。")

ここまでが処方箋の明るい面で、記事はコストも書いています。接続先の認可サーバーが
`urn:ietf:params:oauth:grant-type:token-exchange` を受け付ける必要があり、著者の見立てでは
執筆時点で大半が未対応です。記事の AWS 実装でも、既存の Cognito にはグラント種別を追加できない
ため、交換エンドポイント（`/oauth2/token`）を Lambda で新設しています。新規に書くのは
「交換リクエストの受付」と「自前の署名鍵でのトークン発行」の二つで、JWT の検証とユーザー権限の
解決は既存 SSO の流用です。「認可サーバーを一つ足す」が、このアプローチの最低限のコストになります。

## 鍵そのものを配らない——300 秒の IAM ロール証明を短期トークンに

Retty の記事は、同じ発想をモデル提供者との間で実践したものです。図 2 の順に三段階で読めます。

![Retty の図：AWS STS（OIDC トークン発行）→ アプリケーションサーバー → OpenAI（検証して短期トークン発行）の五つのステップ](/blog/images/agent-credentials-wif-flow.png "図 2 — 鍵は存在しない。アプリが持つのは IAM ロールだけで、STS がそれを JWT にし、OpenAI がそれを短期トークンに交換する。出典：[Retty Tech Blog・pikatenor 氏](https://engineer.retty.me/entry/openai-aws-identity-federation)より引用。")

第一に、OpenAI API を呼ぶ ECS 上のアプリは `$OPENAI_API_KEY` を持たず、IAM ロールだけを持ちます。
第二に、AWS STS（一時認証情報を発行するサービス）がそのロールを証明する短命の JWT（署名付きの
トークン）を発行します。この機能が IAM の Outbound Identity Federation（OIF）です。第三に、
OpenAI の Workload Identity Federation（WIF）がその JWT を検証し、短期アクセストークンに
交換します。

数字を拾います。STS に発行させる JWT の有効期間は、IAM ポリシーの条件で **300 秒以下**に
固定されています。300 は Retty の恣意的な値ではなく、STS の `GetWebIdentityToken` の
[既定値](https://docs.aws.amazon.com/STS/latest/APIReference/API_GetWebIdentityToken.html)
（指定可能範囲は 60〜3600 秒）であり、OpenAI の AWS 向け公式ガイドの例も同じ 300 秒です。

```hcl
condition {
  test     = "ForAllValues:StringEquals"
  variable = "sts:IdentityTokenAudience"
  values   = ["https://api.openai.com/v1"]
}
condition {
  test     = "NumericLessThanEquals"
  variable = "sts:DurationSeconds"
  values   = ["300"]
}
```

OpenAI 側はこの JWT を受け取り、`iss`・`aud`・`sub`（発行者・宛先・主体）の三つと Service
Account ID とが、事前登録済みのマッピングに一致するかを検証してから短期トークンを発行します。交換リクエストは、OpenAI の
[API リファレンス](https://developers.openai.com/api/reference/workload-identity-federation/)に
ある通り RFC 8693 の形で、エンドポイントは `auth.openai.com` です。

```bash
curl https://auth.openai.com/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
    "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
    "subject_token": "<STS が発行した JWT>",
    "identity_provider_id": "idp_xxxxxxxx",
    "service_account_id": "user-XXXXXXXX"
  }'
```

発行されるトークンの実効寿命は、上限の 3600 秒ではなく外部 JWT の残り時間で決まります。
OpenAI のリファレンスが「アクセストークンは最長 1 時間で失効し、**交換に使った外部トークンより
長生きしない**」と明記しているためで、STS の JWT を 300 秒に絞った構成では 300 秒側に引っ張られる
と読むのが安全です（筆者は未検証）。Retty の記事の脚注にある「デフォルトでは 3600 秒の
`expires_in`」はリファレンスのレスポンス例とも一致しており、上限の値として正しい。上限と実効値の
違いです。Retty の SDK は「渡した JWT と交換したアクセストークンのどちらか長い方の有効期限が切れた
タイミング」で再取得する、と記事にあります。どちらにせよ、鍵は「配る」ものから「数分ごとに
取り直す」ものに変わっています。

AWS Japan の記事が社内システム向けに自作した交換エンドポイントを、OpenAI は自社 API の
入口として提供している、と読めば二つの記事はつながります。そしてマッピング画面には、
この記事の主題にとって重要な欄がもう一つあります。

![OpenAI の Create mapping 画面：Key/Value に sub・aud・iss、下部に Permissions の All / Restricted / Read only](/blog/images/agent-credentials-openai-mapping.png "図 3 — マッピングは「誰が」（sub）「どこ宛に」（aud）「誰の署名で」（iss）の三点一致。末尾の Permissions で、発行するトークンの権限をさらに狭められる。出典：[Retty Tech Blog・pikatenor 氏](https://engineer.retty.me/entry/openai-aws-identity-federation)より引用。")

`Permissions` です。OpenAI の[ガイド](https://developers.openai.com/api/docs/guides/workload-identity-federation)では、
マッピング単位で API 権限を付け、発行されるトークンをその範囲に縮小できる、とあります
（マッピングに権限を書かなければ Service Account の権限がそのまま乗る）。アイデンティティの
交換で「短期」を、マッピングの権限で「スコープ」を、鍵の形に入れているわけです。なお、リクエスト
本体に `scope` を書いても権限は付きません——リファレンスに「`scope` value in the request body
doesn't grant access」とある通り、範囲を決めるのはマッピング側だけです。

対応範囲は二層で読む必要があります。**プラットフォームとして**受け付ける IdP は、
[公式ガイド](https://developers.openai.com/api/docs/guides/workload-identity-federation)に載る
7 種——Kubernetes、AWS、Microsoft Azure、Google Cloud、Oracle Cloud Infrastructure、GitHub Actions、
SPIFFE（JWT-SVID）——と X.509 証明書（ベータ）で、載っていない OIDC 発行者は「contact us」扱いです。
一方 **SDK に同梱された** `SubjectTokenProvider` は、Retty の記事によれば執筆時点の `openai-java`
4.51.0 で Kubernetes / Azure / GCP の三つだけで、AWS OIF 向けは自作になっています。

コストも記事に書いてあります。自作した STS 呼び出しに加え、トークン交換レスポンスの `scope` が
既存の Jackson 設定で解析できず、`FAIL_ON_UNKNOWN_PROPERTIES` を無効にして回避しています。
新しい認証方式の初期費用は、たいてい SDK の穴として請求されます。

## 無制限キーは受け付けない——提供者側が鍵の形を強制し始めた

三つ目は方針の話です。Google の公式ドキュメントによれば、Gemini API は standard キーと
authorization（auth）キーの二種類を持ち、後者へ移行中です。要点を原文の順に並べます。

- **standard キー**はリクエストを課金・クォータのために Google Cloud プロジェクトへ
  紐付けるだけで、呼び出し元を識別しない
- **auth キー**はサービスアカウントに直接束縛され、リクエストはそのサービスアカウントの権限で
  処理される。既定で Gemini API に制限され、漏洩が検知されたキーは速やかに停止される
- AI Studio で新規作成するキーは、すべて auth キーになる
- **無制限の standard キーは拒否**。明示的な制限が付いた standard キーは引き続き動く。開始日が
  2026-06-19 であることは、ドキュメント本文ではなく[公式フォーラムの告知](https://discuss.google.dev/t/gemini-api-update/375447)（2026-06-24 転載）による
- 2026-05-07 以降、長期間未使用の無制限キーはブロックされる
- **2026 年 9 月**、standard キー全体が拒否対象になり、auth キーへの移行が必須になる

![Google 公式ドキュメント「Using Gemini API keys」の API key types 節：standard と authorization の違い](/blog/images/agent-credentials-gemini-key-policy.png "図 4 — 「standard キーは呼び出し元を識別しない」と提供者自身が書いている。出典：[Google AI for Developers](https://ai.google.dev/gemini-api/docs/api-key)。")

ここで起きているのは、利用者が善意で鍵を制限するのを待つのをやめ、**形のない鍵を提供者が
受け付けなくする**という転換です。AWS Japan と Retty が「鍵に形を与える」手順を書いた週に、
Google は「形のない鍵は捨てる」を実行に移していました。

## 三点セット——三つの一次情報を一枚の表に

![リストカード：短期——鍵を配らず IdP の証明を数分のトークンに交換する／スコープ——エンドポイント・操作・モデルを鍵の中に書く／上限——鍵ごとの予算とレート](/blog/images/agent-credentials-three-shapes.png "図 5 — エージェントに渡す鍵の三点セット。一つ欠けると、残り二つの意味が薄れます。")

三つの出来事を同じ軸で並べます。評価軸は「漏れたときの影響範囲（blast radius）」「ローテーション
の手間」「使い過ぎの上限」の三つです。

| 鍵の形 | 漏洩時の影響範囲 | ローテーション | 使い過ぎの上限 | 今週の該当例 |
|---|---|---|---|---|
| 長期 API キー（無制限） | ✗ プロジェクト全体、検知まで無期限 | ✗ 人手、デプロイを伴う | ✗ 請求書で気づく | Gemini が 6/19 に拒否した形 |
| 制限付き standard キー | ⚠ 制限した API の範囲内、ただし呼び出し元を識別しない | ⚠ 依然として人手 | ⚠ プロジェクト単位のクォータ | Gemini で 2026 年 9 月まで動く形 |
| auth キー（サービスアカウント束縛） | ⚠ 束縛先サービスアカウントの権限内、漏洩検知で速やかに停止 | ⚠ 依然として人手 | ⚠ プロジェクト単位のクォータ | Gemini が 9 月以降に唯一残す形 |
| フェデレーション短期トークン | ✓ 最長 1 時間、外部トークン次第で数分、しかも IAM ロール等に束縛 | ✓ 自動で毎回更新 | ⚠ マッピング権限で範囲は絞れるが金額上限は別の仕組み | Retty の WIF、AWS Japan の OBO |

最終行の「使い過ぎの上限」列にある ⚠ が、この記事で一番言いたい場所です。短期とスコープは、今週の三つの一次情報で
すでに実装と方針の両方が揃いました。**上限**だけは、どの記事にも主役として出てきません。
OBO の `scope` は「何をしてよいか」であって「いくらまでか」ではなく、OpenAI のマッピング
権限も同様です。LLM の API は一回の呼び出しで数万トークンを消費し、エージェントはそれを
ループで回します。鍵の形に「いくらまで」が入っていない限り、漏洩しなくても自分の
エージェントの暴走で請求が走ります。リトライの無限ループは、筆者の経験では漏洩より
先に来ます。

## 請求書——本番に持ち込む費用

三点セットを本番に持ち込む費用を、先に並べておきます。

1. **認可サーバー側の対応**。OBO を受け付ける認可サーバーは、AWS Japan の記事の見立てで
   大半が未対応。自社サービスなら交換エンドポイントを一つ足す（記事では Lambda 一本）、
   他社サービスなら相手が対応するまで待つ、の二択です。
2. **SDK の穴**。Retty の記事が示した通り、提供者の公式 SDK でも IdP によっては
   `SubjectTokenProvider` を自作する必要があり、レスポンスの解析で足を取られます。
   公式ガイドが「サポート済み」と書く IdP 以外は、自作分の保守が毎バージョン付いてきます。
3. **時計と有効期限のデバッグ**。外部 JWT とアクセストークンという二つの有効期限が走る構成では、
   障害の切り分けに「どちらが切れたか」が必ず入ります。自作クライアントではその再取得ロジックを
   自分で書くことになります。細かい罠も一つ：STS の `GetWebIdentityToken` はグローバル
   エンドポイントでは使えず、リージョナルエンドポイント必須です。
4. **ローカル開発の抜け道**。STS もクラウドのメタデータサービスも無い開発機では、結局どこかに
   長期キーが残りがちです。
   ここを放置すると、本番だけ三点セット、開発機は無制限キー、という一番漏れやすい形になります。
5. **上限の別建て**。三点セットの表で述べた通り、金額とレートの上限は認可の仕組みの外側で
   持つ必要があり、鍵単位の予算を数えるコンポーネントが一つ増えます。プロバイダ側のプロジェクト
   単位の予算アラートは今日使える代替ですが、粒度は「鍵ごと」ではなく「プロジェクトごと」です。

主要なモデル提供経路について、長期キーを使わずに呼べる経路を公式ドキュメントで確認できた範囲で
表にしておきます。載っていない提供者は未確認です。

| 提供経路 | 長期キー無しの経路 | 状態 |
|---|---|---|
| OpenAI API | Workload Identity Federation（OIDC JWT → 短期トークン、[公式ガイド](https://developers.openai.com/api/docs/guides/workload-identity-federation)） | ✓ 提供中、7 種の IdP + X.509 ベータ |
| Gemini API（AI Studio） | auth キー（サービスアカウント束縛、漏洩検知で停止、[公式](https://ai.google.dev/gemini-api/docs/api-key)） | ⚠ 長期キーだがアイデンティティ付き。standard キーは 9 月で終了 |
| Azure OpenAI | Microsoft Entra ID / マネージド ID（`DefaultAzureCredential`、[公式](https://learn.microsoft.com/en-us/azure/foundry-classic/openai/how-to/managed-identity)） | ✓ 提供中。短期トークン、秘密の保管なし |
| Amazon Bedrock | IAM 認証（SigV4）が既定。API キーは短期（最長 12 時間、IAM 主体の権限を継承）と長期の二種、[公式](https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys.html)は長期を「探索用途のみ」と明記 | ✓ 提供中。`bedrock:CallWithBearerToken` でキー種別ごとに拒否も可能 |
| Vertex AI | Application Default Credentials（サービスアカウント / Workload Identity Federation、[公式](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/start/gcp-auth)） | ✓ 提供中。API キーも別途提供されるが、その制限の詳細は筆者未確認 |

## ゲートウェイ側から見ると

LLM ゲートウェイは、この三点セットを実装する場所として都合がいい位置にいます。アプリと
モデル提供者の間に立ち、鍵の発行者であり、同時にトークンを数える課金の場所でもあるからです。
私たち（pirouter のゲートウェイ）の場合、利用者に発行する API キーは**設計上は**、スコープ
（どのモデル・どのエンドポイントを許すか）と上限（キーごとの予算とレート）を鍵の属性として持ち、
利用者側が持つ OIDC JWT を短期トークンに交換する入口も、上で見た OpenAI の WIF と同じ
RFC 8693 の形に寄せる方針です。ゲートウェイ自身が上流プロバイダに対して持つ鍵についても、
正直に書いておきます。集約した分だけ漏洩時の影響範囲は大きく、だからこそ上流側に長期キー無しの
経路（上の表）があるものはそれを使い、無いものは長期キーを一か所に閉じ込めてローテーションと
監査の対象をそこだけにする、という設計です。今日ここで「対応している」とは書きません。書けるのは、
今週の三つの一次情報を読んだ後で、この三点を鍵の形から外す理由が見当たらなかった、ということだけです。

## 月曜にやる三つ

- 自社の認可サーバーの `/.well-known/oauth-authorization-server`（Entra ID のように
  `/.well-known/openid-configuration` しか出さない IdP もあるので両方）を開き、
  `grant_types_supported` に `token-exchange` があるか見る。無ければ、AWS Japan の記事の要件表で
  「新規」になる行を数える。主要 IdP の対応状況は、筆者は今週確認できていません。
- 上の提供経路の表を自社の一覧に広げる。経路が無い提供者は、そのキーの制限とローテーション周期を
  今の値で記録しておく。
- 鍵ごとの月額上限を、どのコンポーネントが数えているかを一行で書く。書けなければ、三点セットの
  三つ目はまだ無い、ということです。

---

## Sources

### zenn.dev

- [「AI エージェントの『認可疲れ』に効く処方箋」](https://zenn.dev/aws_japan/articles/2b62886aa8735e)
- [「AI エージェントはなぜテストを握り潰すのか」](https://zenn.dev/ito/articles/6b042aa27d65bc)

### engineer.retty.me

- [「NO MORE $OPENAI_API_KEY」](https://engineer.retty.me/entry/openai-aws-identity-federation)

### ai.google.dev

- [無制限 API キーのリクエストを拒否する](https://ai.google.dev/gemini-api/docs/api-key)

### discuss.google.dev

- [公式フォーラム告知](https://discuss.google.dev/t/gemini-api-update/375447)

### docs.aws.amazon.com

- [既定値](https://docs.aws.amazon.com/STS/latest/APIReference/API_GetWebIdentityToken.html)
- [公式](https://docs.aws.amazon.com/bedrock/latest/userguide/api-keys.html)

### developers.openai.com

- [API リファレンス](https://developers.openai.com/api/reference/workload-identity-federation/)
- [ガイド](https://developers.openai.com/api/docs/guides/workload-identity-federation)

### learn.microsoft.com

- [公式](https://learn.microsoft.com/en-us/azure/foundry-classic/openai/how-to/managed-identity)

### docs.cloud.google.com

- [公式](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/start/gcp-auth)
