AI ワークフローのサービスアカウント権限:最小権限の設計
AI ワークフローのサービスアカウント権限は、多くの場合、便利なクレデンシャル 1 つから始まります。CRM を読み取り、チケットを更新し、メッセージを送信し、ドキュメントを変更できる共有アカウントです。デモでは、これで問題なく動きます。しかし本番環境では、どのワークフロー実行にも同じ権限を与えることになり、実行を開始した従業員本人にはその操作を行う権限がない場合でも、ワークフローは実行できてしまいます。さらに監査ログも、「どのサービスがこれを実行したか」しか答えられず、「誰が要求し、どのワークフローが動作し、何が許可されていたか」には答えられなくなります。
トリガーごとにアイデンティティモデルを選びましょう。そのうえで、1 つのツールと目的に限定した短命なクレデンシャルを発行し、ツールの境界で認可を再度チェックします。本ガイドでは、判断ルール、トークンの形、実装の手順、拒否テスト、そして展開時のチェックを解説します。
共有サービスアカウント 1 つでは不十分な理由
モデル自体にクレデンシャルは必要ありません。必要とするのは、モデルが選んだツールを実行する決定論的なコードです。これらのレイヤーが 1 つの広範なクレデンシャルを共有していると、誤ったツールの選択、プロンプトインジェクション、あるいは通常のプログラミングミスによって、そのアカウントが利用できるあらゆるリソースに到達できてしまいます。
無関係なジョブでアイデンティティを使い回すと、権限の問題はさらに深刻になります。スケジュール実行の請求書インポーターは、下書きレコードの作成が必要かもしれません。サポートアシスタントは、顧客履歴の読み取りと非公開メモの追加が必要かもしれません。マネージャー承認の返金フローは、支払いレコードの変更が必要かもしれません。これらのジョブを 1 つのアカウントにまとめると、権限の和集合ができあがります。こうして各ワークフローは、他の 2 つに属するシステムにも到達できてしまいます。
監査証跡も曖昧になります。ターゲットシステムからは、呼び出し元が共有アカウントに見えます。ワークフローのデータベースには要求した従業員が記録されているかもしれませんが、調査担当者は 2 つのログを突き合わせたうえで、アプリケーションがそのフィールドを改ざんしていないと信頼するほかありません。認可コンテキストには、2 つのアイデンティティ、すなわち作業を要求したサブジェクトと、それを実行したワークロードの両方を持たせてください。
これはプロンプトの書き方の問題ではなく、認可設計の問題として扱ってください。OWASP のエージェント型脅威ガイドは、自律システムがもたらすリスクに対して、脅威モデルに基づくアプローチを推奨しています。このワークフローでは、トリガー、オーケストレーター、モデル、ツールゲートウェイ、クレデンシャル発行者、ターゲットシステムを囲むように信頼境界を描きます。そのうえで、信頼できないテキストがアクションに影響を与え得るすべての箇所に印を付けます。
まず委譲アイデンティティかワークロードアイデンティティかを選ぶ
委譲アイデンティティは、サインイン済みの人物がワークフローを開始し、そのアクションがその人物の権限を決して超えてはならない場合に使います。例としては、顧客レコードの検索、ユーザーのキュー内での返信の下書き作成、ユーザーがすでに編集できるドキュメントの更新などが挙げられます。
ワークロードアイデンティティは、ジョブが現在のユーザーとは独立して、承認された独自の権限を持つ場合に使います。スケジュール実行の突合、受信ドキュメントの処理、キューのクリーンアップなどは、通常このモデルに当てはまります。アプリケーション全体で 1 つのデフォルトアカウントを共有するのではなく、ジョブごと、あるいは密接に関連するワークフローのまとまりごとに専用のアイデンティティを与えてください。
委譲されたワークフローがより強い権限のアクションを必要とする場合は、明示的な承認による遷移を使います。承認は、元の実行内の真偽値を切り替えるのではなく、新しい認可の判断を生成すべきです。承認者、アクション、リソース、有効期限、ポリシーのバージョンを記録します。新しいクレデンシャルは、その判断を通過した後にのみ発行してください。
下流のログを見慣れた形にするためだけに、ユーザーになりすます(impersonation)のはやめましょう。OAuth 2.0 Token Exchangeは、アクターがサブジェクトのアイデンティティを引き受けるなりすまし(impersonation)と、アクターがサブジェクトに代わって動作する委譲(delegation)を区別しています。その actor クレームは、この 2 つ目のアイデンティティを表現する標準的な方法を提供します。委譲は通常、社内 AI ワークフローにとってより明確な記録を残します。ターゲット側が、人間であるサブジェクトとワークフローのアクターの両方を保持できるからです。
実用的な判断表は次のようになります。
| トリガーとアクション | アイデンティティモデル | 権限の上限 |
|---|---|---|
| 従業員が顧客アカウントの要約を依頼する | 委譲 | 要求した従業員の読み取り権限 |
| 従業員が担当チケットの更新を依頼する | 委譲 | 従業員の権限に加えてチケット更新スコープ |
| 夜間インポーターが請求書の下書きを作成する | ワークロード | 専用のインポーターアイデンティティ、下書き作成のみ |
| マネージャー承認後にワークフローが返金を実行する | 承認による遷移 | 正確な返金アクションと承認された金額 |
| モデルがレコードの削除を提案する | 既定ではどちらも使わない | 人間が管理する別個の管理経路 |
提案されたツールについてチームがいずれの行も選べないなら、そのツールは本番運用の準備ができていません。
認可エンベロープを定義する
ユーザーの元の Web セッショントークンを、すべてのステップにそのまま渡してはいけません。信頼できるバックエンドで、より狭いクレデンシャルに交換します。RFC 8693 は、サブジェクトトークン、要求するオーディエンス、リソース、スコープのリクエストフィールドを定義しています。また、委譲のためのオプションの actor トークンも定義しています。これらの要素は、社内ワークフローの認可エンベロープにうまく対応します。
プロバイダーが異なるトークン名を使っていても、ワークフロー内部の認可レコードは明示的に保ちましょう。
{
"run_id": "wf_7f3c",
"subject": "employee:1842",
"actor": "workflow:support-assistant",
"tool": "ticketing.update_private_note",
"resource": "ticket:93815",
"scopes": ["ticket.note:create"],
"policy_version": "support-tools-v4",
"approval_id": null,
"expires_at": "2026-07-29T10:05:00Z"
}
これは説明のためのアプリケーションレコードであり、あらゆるアイデンティティプロバイダーがこの正確なフィールドを発行するという主張ではありません。重要なのは、サブジェクトとアクターを分けること、意図するツールを 1 つに絞ること、可能な場合はリソースを制約すること、スコープを狭くすること、ポリシーの出所、そして有効期限です。
クレデンシャルは、該当するツールゲートウェイだけが受け入れるオーディエンスにバインドします。チケット更新のために発行されたトークンは、ドキュメントサービスでは失敗すべきです。認可システムがリソースレベルの付与に対応している場合は、1 つのリソースにバインドします。そうでない場合は、ゲートウェイがターゲット API を呼び出す前に、リソースのチェックを強制してください。
プロバイダーの生のクレデンシャルは、モデルのコンテキストとワークフローの状態の外に置きます。モデルは、型付けされたツールリクエストを生成すべきです。信頼できるコードがそのリクエストを検証し、クレデンシャルを取得し、ターゲットを呼び出し、結果を記録します。モデルが自分で HTTP リクエストを組み立てられるように、リフレッシュトークン、サービスアカウントキー、ベアラートークンをプロンプトに入れることは絶対に避けてください。
AI ワークフローのサービスアカウント権限を実装する
モデルではなく、ツールカタログから始めます。呼び出し可能なすべての操作を、その入力スキーマ、副作用、必要なアイデンティティモデル、権限、許可されるリソースパターン、承認ルールとともに一覧化します。広範な操作は分割します。crm.execute は安全に認可するには曖昧すぎますが、crm.contact.read と crm.contact.add_note であれば、それぞれ異なるポリシーを設定できます。
次に、専用のワークロードアイデンティティを作成します。Google Cloud のサービスアカウントガイダンスは、アプリケーションごとに専用のサービスアカウントを用意すること、デフォルトアカウントへの自動付与を避けること、可能な場合は一時的なクレデンシャルを使うことを推奨しています。同じ原則は Google Cloud の外でも当てはまります。ジョブを分離し、静的なキーを避け、意図する操作に必要なロールだけを付与してください。
続いて、オーケストレーションとツールの間にクレデンシャルブローカーを置きます。ブローカーは認証済みのワークフローコンテキストを受け取り、ポリシーを評価し、短命なクレデンシャルか拒否のいずれかを返します。オーケストレーターには、任意のスコープを発行する権限を持たせるべきではありません。オーケストレーターは名前付きのツールアクションを要求し、ブローカーがそのアクションを、許可される最大のオーディエンスとスコープに対応づけます。
簡略化したフローでは、次のようなチェックを用いることができます。
def authorize_tool_call(run, request):
tool = catalog.require(request.tool_name)
policy = policies.for_tool(tool.name)
require(run.actor == policy.allowed_actor)
require(request.arguments.matches(tool.input_schema))
require(policy.subject_can_act(run.subject, request.arguments))
require(policy.resource_allowed(run.subject, request.arguments))
if policy.requires_approval(request.arguments):
require(approvals.matches(run.approval_id, request))
return credential_broker.issue(
actor=run.actor,
subject=run.subject,
audience=tool.audience,
scopes=tool.scopes,
resource=tool.resource_from(request.arguments),
ttl=policy.credential_ttl,
)
ゲートウェイは、重要なチェックを繰り返し実行しなければなりません。認可はすでに通過したというオーケストレーターの言葉に頼ってはいけません。ツールを所有する境界で、クレデンシャルのオーディエンス、有効期限、アクター、スコープ、リソースを検証します。モデルの出力をパースした後に、引数を再度検証します。これにより、オーケストレーションコードのエラーが封じ込められ、ポリシー評価から実行までの間にツールリクエストが改変されることを防げます。
最後に、認可の判断を API の結果とは別に記録します。サブジェクト、アクター、要求されたツール、リソース、付与されたスコープ、ポリシーのバージョン、承認の参照、判断、理由コードを記録します。トークンそのものは除外します。拒否された呼び出しも監査証跡に含めるべきです。ポリシーが想定外の挙動を捕捉できているかどうかを示すからです。
サポートチケットの例で考える
従業員がアシスタントに、チケット 93815 を要約し、非公開メモを追加するよう依頼したとします。このワークフローには 2 つのツール、ticket.read と ticket.note.create があります。このチケットは従業員のサポートキューに属しているため、従業員はそれを閲覧できます。
読み取りステップでは、ブローカーが従業員のセッションアイデンティティを、オーディエンスがチケットゲートウェイであり、スコープがチケットの読み取りを許可するクレデンシャルに交換します。ゲートウェイは、チケット 93815 がそのサブジェクトから見えることを確認します。ワークフローは、返ってきたチケットのテキストをモデルに送信できますが、アクセストークンは送信できません。
モデルはメモを下書きし、ticket.note.create を提案します。これは別個の認可リクエストです。ゲートウェイは、同じサブジェクトがまだアクセス権を持つことを検証し、メモのスキーマとサイズを検証し、メモ作成のみのクレデンシャルを取得します。読み取り用のクレデンシャルではメモを作成できず、メモ用のクレデンシャルでは別のチケットを読み取れません。
次に、チケットの本文に、すべての顧客レコードをエクスポートするようアシスタントに求める悪意あるテキストが含まれているとします。モデルは、利用できないツールや不正な形式の呼び出しを提案するかもしれません。カタログは、クレデンシャルの発行前に未知のツールを拒否します。仮にモデルが既知のエクスポートツールを呼び出しても、サポートアシスタントのアクターにはそのアクションを要求する権限がないため、ポリシーがそれを拒否します。この拒否は有用な証拠になりますが、トークンを生成することは決してありません。
プロンプトによる防御は、認可の境界ではありません。良いプロンプトは不正なリクエストを減らせるかもしれませんが、リクエストが外部アクションになれるかどうかを決めるのは、認可の境界です。
アクセスを広げずに障害に対処する
クレデンシャルの有効期限切れは、通常の障害です。元の実行アイデンティティと認可コンテキストを持ってブローカーに戻ることで、リトライします。一時的なクレデンシャルの発行が失敗したときに、長命なキーへフォールバックしてはいけません。それは可用性の問題を、セキュリティのバイパスに変えてしまいます。
ターゲット API は、オーディエンス、スコープ、リソースが誤っているために、トークンを拒否することがあります。これは一時的なプロバイダーエラーではなく、認可エラーとして分類してください。やみくもなリトライでは解決せず、監査ログを溢れさせるおそれがあります。アクションを停止し、拒否の理由を保存し、ワークフローが安全に継続できない場合は、実行をオペレーターに振り分けます。
長時間実行されるジョブの途中でサブジェクトがアクセス権を失った場合は、重要な呼び出しのたびに再評価します。実行開始時点の認可が有効なままだと想定してはいけません。ワークロードジョブでは、クレデンシャル発行時にワークロードのロール付与を再評価し、取り消された権限が速やかに反映されるよう、クレデンシャルの有効期間を十分に短く保ってください。
クレデンシャルブローカーが利用できない場合、書き込み操作についてはフェイルクローズ(安全側に倒す)にします。ターゲットとデータの機密区分が許すなら、文書化された読み取り専用の縮退経路を選んでもかまいませんが、その経路をインシデントの最中に即興で作ってはいけません。ローンチ前に定義し、テストしておいてください。
権限と拒否の両方を検証する
正常系のテストは、ワークフローが動作できることを証明します。しかし、権限の境界が機能することは証明しません。サブジェクト、アクター、ツール、リソース、スコープ、承認、時刻について、許可される組み合わせと拒否される組み合わせを網羅するマトリクスを作成してください。
少なくとも、次のケースをテストします。
- 認可された従業員が、許可された 1 件のレコードを読み取れる。
- 同じ従業員が、割り当てられた範囲外のレコードを読み取れない。
- 読み取り用のクレデンシャルで書き込みができない。
- あるツール用のクレデンシャルが、別のツールのオーディエンスチェックで拒否される。
- 有効期限切れのクレデンシャルが、静的なキーへフォールバックすることなく拒否される。
- スケジュール実行のワークロードが、委譲されたユーザー専用のツールを使えない。
- 承認が欠落・期限切れ・不一致の場合、より強い権限のアクションがブロックされる。
- モデルが提案した未知のツールが、クレデンシャルブローカーに決して到達しない。
- サブジェクトまたはワークロードのロールを取り消すと、以降のクレデンシャル発行がブロックされる。
- ログに、トークンを露出させることなく、サブジェクト、アクター、リソース、判断、ポリシーのバージョンが記録される。
拒否のテストスイートは、ポリシー変更に対して継続的インテグレーションで実行します。ステージング環境では、ターゲットシステムの監査イベントを取得し、ワークフローの判断レコードと突き合わせます。この 2 つは、同じアクター、アクション、リソース、時間帯を指し示すはずです。不一致があれば、展開前に調査してください。
本番環境の拒否は、理由コード別に監視します。未知のツールやスコープ外のリクエストの増加は、プロンプトの操作、モデルのリグレッション、カタログのドリフト、あるいは意図的な設計を必要とする新しいユーザーワークフローを浮き彫りにすることがあります。アラートを消すために、不足しているスコープを自動的に付与してはいけません。
今週、1 つのワークフローをこの設計に通す
現在最も広範なクレデンシャルを持つ社内 AI ワークフローを選びます。そのツール呼び出しを棚卸しし、各呼び出しが委譲アイデンティティとワークロードアイデンティティのどちらを使うかを決め、1 つの共有クレデンシャルを、1 つの操作に限定した短命でオーディエンスにバインドされたクレデンシャルに置き換えます。そのクレデンシャルが、2 つ目のツールと認可されていないリソースに対して失敗することを証明するテストを追加してください。
監査レコードが、すべての呼び出しについて 4 つの問い、すなわち誰が要求したか、どのワークフローが動作したか、正確にどのリソースに触れたか、なぜポリシーが許可または拒否したかに答えられるようになるまで、展開を拡大してはいけません。これらの答えが信頼できるものになったら、同じツールカタログとクレデンシャルブローカーのパターンを次のワークフローに適用します。
参考文献
- OAuth 2.0 Token Exchange, RFC 8693は、トークン交換、委譲となりすまし(impersonation)のセマンティクス、サブジェクトとアクターのクレーム、オーディエンス、リソース、スコープを定義しています。
- Google Cloud service-account best practicesは、専用のサービスアカウント、一時的なクレデンシャル、最小権限のロール設計を裏付けています。
- OWASP Agentic AI threats and mitigationsは、自律システムのリスクに対して脅威モデルに基づくアプローチを用いることを裏付けています。