AIエージェントの権限設計とは?道具を使えることと実行してよいことを分ける
AIエージェントへメール、予定表、顧客管理、ファイル操作などの道具を渡すと、回答するだけでなく仕事を進められるようになる。しかし、道具へ接続できることと、今この利用者の代わりに実行してよいことは同じではない。
権限設計の中心は、モデルの判断をそのまま認可に使わないことである。モデルが操作を提案し、アプリケーション側が利用者、対象、操作、時刻、承認状態を検証してから実行する。プロンプトに「重要な操作はしない」と書くだけでは、間接プロンプトインジェクションや誤解による操作を止められない。
認証と認可を分ける
認証は誰であるかを確認する仕組みで、認可はその人が何をしてよいかを決める仕組みである。ログイン済みだからといって、全顧客の閲覧、全ファイルの削除、管理者設定の変更まで許されるわけではない。
AIエージェントでは、さらに二つの主体を区別する必要がある。
- エージェントを利用している人
- 外部サービスへ接続するアプリケーション
実行時には、利用者の権限とアプリケーションの権限が重なる範囲だけを許可する。アプリケーションが強い管理者権限を持ち、モデルが利用者の依頼だけを見て操作できる構成は避ける。
道具の一覧を権限表として扱わない
モデルへ渡す道具の一覧を減らすことは有効だが、それだけでは認可にならない。例えば delete_file をモデルから隠しても、汎用的な run_command や request_url から同じ削除へ到達できる場合がある。
認可は最終的な副作用が起きる境界で実施する。ファイル削除ならファイルサービス、送金なら決済サービス、メール送信なら送信APIが、呼び出しごとに権限を検証する。モデルの出力や会話履歴だけを信頼しない。
道具を設計するときは、対象と操作を曖昧にしない。manage_account のような広い道具より、read_invoice、create_refund_request、approve_refund のように権限境界が分かれる単位にする。
最小権限を対象と操作の両方へ適用する
OAuth 2.0のセキュリティ推奨では、アクセストークンの権限を用途に必要な最小限へ制限し、利用先のサービス、対象資源、操作も限定することが推奨されている。
AIエージェントでも、単に「予定表を操作できる」という権限では広すぎる。次のように分解する。
- 読み取りか書き込みか
- 自分の予定表か共有予定表か
- 予定の作成か変更か削除か
- どの組織やテナントか
- いつまで有効か
一つのトークンを複数の外部サービスへ使い回さない。利用先を表すaudienceを限定し、サービス側でも自分向けのトークンかを毎回検証する。scopeも必要な操作だけに絞る。
トークンが漏れたときの被害は、期限、利用先、対象、操作が広いほど大きくなる。長期間使える万能トークンをエージェントへ渡すのではなく、必要な仕事の直前に短期トークンを発行する方がよい。
利用者の代理か、サービス自身の仕事かを区別する
利用者のメールを読む、本人の予定を作るといった処理は、利用者の代理として実行する。一方、夜間集計やシステム監視は、サービス自身の仕事として実行することがある。
この二つを同じ資格情報で処理すると、誰の権限で何をしたかが曖昧になる。利用者代理の処理には利用者と同意範囲を結び付け、サービス処理には専用のサービスアカウントを使う。監査ログにも、利用者、アプリケーション、実行したエージェント、対象を別々に残す。
利用者Aの会話から利用者Bの資源へ到達できないように、テナント識別子も認可条件へ含める。URLや道具の引数に別テナントのIDを入れられても、サービス側で拒否する。
読み取りにも承認が必要な場合がある
書き込みだけを危険と考えると、機密資料、個人情報、未公開の財務情報を読む操作を見落とす。読み取った情報は回答、ログ、別の道具への入力を通じて外へ出る可能性がある。
したがって、承認の要否はHTTPメソッドや「読む・書く」だけで決めない。対象情報の機密度、送信先、副作用、元に戻せるか、金額、件数で判断する。
日常的な低リスク操作は事前に定めた範囲で自動化し、高リスク操作だけを人へ確認する。すべてを毎回承認させると確認が形骸化しやすいため、危険度に応じて段階を分ける。
承認画面には実際の操作を表示する
「続行しますか」だけでは、利用者は何を許可するのか判断できない。承認時には少なくとも次を表示する。
- 実行する操作
- 対象となる資源や相手
- 変更前後の内容
- 件数や金額
- 外部送信先
- 元に戻せるか
- 使用する利用者権限
モデルが作った自然言語の要約だけではなく、実際に道具へ渡す確定済み引数を基に表示する。承認後に引数を変更せず、承認した操作と実行した操作を同じIDで結び付ける。
OpenAI Agents SDKの承認フローでは、道具の実行前に処理を中断し、保留中の操作を承認または拒否して同じ実行状態から再開する。この考え方を使えば、承認後に最初から推論し直して別の操作へ変わることを避けられる。
承認には期限と一回性を持たせる
昨日承認した操作を今日も実行できる状態は危険である。承認は特定の操作、引数、対象、実行IDに結び付け、短い期限と一回性を持たせる。
承認待ちの間に対象データが変わった場合も注意が必要だ。例えば承認時より送信先や金額が変わったなら、古い承認を使わず再確認する。承認サービスが停止したり時間切れになったりした場合は、危険な操作を既定で拒否する。
複数の操作を一括承認する場合は、範囲と上限を明示する。「今後すべて許可」ではなく、「このフォルダ内の20ファイルをこの実行中だけ移動」のように限定する。
読み取りと行動の間に認可を置く
エージェントが外部文書を読んで、その内容に基づいて道具を呼ぶと、文書内の命令が操作へ流れ込むことがある。そこで、情報を読む段階と行動する段階を分離する。
読み取り結果から、対象ID、金額、操作種別など必要な項目だけを構造化して取り出す。その後、別のポリシー層が許可範囲を検証し、必要なら人へ承認を求める。外部文書の文章をそのまま道具の引数や承認理由として使わない。
検証は道具の直前にも置く。エージェント全体の入口と出口だけに検査を置くと、途中の引き継ぎや入れ子になった道具呼び出しを見逃す可能性がある。
失敗時に権限を広げない
権限不足で処理が失敗したとき、エージェントが自動的に広いscopeを取り直したり、管理者資格情報へ切り替えたりしてはいけない。失敗は不足している具体的な権限として利用者へ示し、追加許可が本当に必要かを判断してもらう。
再試行時も同じ認可条件を使う。最初は1件だった操作が、再試行で全件処理へ広がらないようにする。権限変更、承認、実行、失敗の記録は、生成コードが変更できない監査基盤へ残す。
権限設計を試験する
正常に操作できることだけでなく、境界を越えられないことを確認する。
- 読み取り専用トークンで更新できないか
- 別利用者や別テナントのIDを指定できないか
- あるサービス向けのトークンを別サービスで使えないか
- 承認後に対象や引数を差し替えられないか
- 期限切れや使用済みの承認を再利用できないか
- 拒否やタイムアウト時に実行されないか
- 汎用道具から禁止操作へ迂回できないか
- ログやエラーへトークンが残らないか
モデルの回答が適切かを見る評価とは分けて、認可層は通常のセキュリティテストとして検証する。モデルを変更しても越えられない境界にしておくことが重要である。
まとめ
AIエージェントの権限設計では、道具を使えることと、今その操作を実行してよいことを分ける。利用者とアプリケーションの両方を識別し、利用先、対象、操作、期限を最小限へ絞り、副作用が起きる直前にアプリケーション側で認可する。
高リスク操作は、確定した対象と引数を人へ示して承認を受ける。承認には期限と一回性を持たせ、失敗時は安全側で停止する。こうした境界をモデルの外側に置くことで、誤判断やプロンプトインジェクションが起きても被害を限定できる。
参考資料
- Safety in building agents | OpenAI Developers
- Guardrails and human review | OpenAI Developers
- Programmatic Tool Calling | OpenAI Developers
- RFC 9700: Best Current Practice for OAuth 2.0 Security | RFC Editor
- RFC 8707: Resource Indicators for OAuth 2.0 | RFC Editor
- RFC 9068: JSON Web Token Profile for OAuth 2.0 Access Tokens | RFC Editor