前の記事では、AIへ複数のToolを渡すとき、プロンプトで「このToolは使わないで」と指示するだけでは、実行可能な操作そのものは消えないことを扱いました。
OpenAI APIでAIが使えるツールを制限する。「使うな」とプロンプトに書くだけで安全なのか? | kuromica
OpenAI APIでAIに複数のツールを使わせるとき、プロンプトで「使うな」と書くだけで十分なのか。tool_choiceやallowed_tools、Function Callingを使い、AIが使えるツールと実際に実行してよい操作を分けて考えます。
https://kuromica.com/blog/openai-api-tool-control/
今回は、それを本番サーバーの運用に当てはめます。
AI Agentにサーバーの障害調査や復旧を任せようとすると、Shellを使わせる構成はかなり自然です。
AI Agent
↓
Shell
↓
journalctl / docker / systemctl / curl / ps ...
↓
production server
Shellがあれば、Agentは状況を見ながらコマンドを組み合わせられます。事前に用意していなかった調査方法にも進めるため、障害対応との相性はよく見えます。
ただ、本番環境でShellが使えるということは、調査用コマンドだけが使えるという意味ではありません。
Agentが動いているユーザーの権限次第では、ファイルの変更、プロセスの停止、ネットワーク通信、認証情報の読み取りなども同じ環境から可能になります。
そこで考えたいのが、本番サーバーをAIに操作させたいとしても、Shellまで必要なのかという点です。
Shellを渡すと「未知の操作」を組み立てられる
Shellの大きな利点は、事前に操作手順を決め切らなくてよいことです。
たとえばWebサービスの応答が遅くなったとします。
人間が調査するときも、最初から原因が分かっているとは限りません。
CPU使用率を見る
↓
メモリを確認する
↓
プロセスを見る
↓
コンテナの状態を見る
↓
ログを読む
↓
接続中のportを確認する
↓
設定ファイルを確認する
途中で見つかった情報によって次の操作が変わります。
Shellを使えるAgentなら、たとえば次のような既存コマンドを組み合わせて調査できます。
ps aux
free -h
ss -lntp
docker ps
docker inspect example-app
docker logs example-app
journalctl -u nginx -n 200
「ログを取得するTool」「プロセスを確認するTool」「portを確認するTool」を一つずつ事前実装しなくても、OSにすでに存在する仕組みを利用できます。
未知の障害を探索するとき、この自由度には明確な価値があります。
操作が決まっているならShellである必要はない
一方、Agentへ任せたい処理が最初から分かっているケースもあります。
たとえばSaaSの運用で、
コンテナの状態を確認する
CPU使用率を取得する
メモリ使用率を取得する
直近のログを読む
必要ならコンテナを再起動する
だけを実行したいとします。
これなら、Shellの代わりに次のようなToolを用意できます。
get_cpu_usage()
get_memory_usage()
get_container_status()
read_service_logs(service, lines)
restart_container(id)
構成も変わります。
AI Agent
↓
Agent Tool Gateway
├─ get_cpu_usage()
├─ get_memory_usage()
├─ get_container_status()
├─ read_service_logs()
└─ restart_container()
↓
internal API / infrastructure
Agentはdockerやsystemctlを直接実行しません。
restart_container()を受け取ったアプリケーションが対象を確認し、許可されたコンテナだけを再起動します。
この構成では、そもそもAgentにrmやiptables、任意のcurlなどを実行する経路がありません。
Shellと限定Toolでは得意な仕事が違う
2つの設計を単純化すると、次の違いがあります。
| 観点 | Shell | 限定したFunction / API |
|---|---|---|
| 未知の障害調査 | 強い | 事前定義した範囲に限定される |
| 既存CLIの利用 | そのまま使える | WrapperやAPIが必要 |
| 新しい操作への対応 | Tool追加なしでも対応しやすい | Toolの追加実装が必要 |
| 操作可能範囲 | 広くなりやすい | Function単位で決めやすい |
| 引数の制約 | コマンド文字列では難しい | Schemaで定義しやすい |
| 認可 | OS権限などと組み合わせる | Application Logicへ組み込みやすい |
| 監査 | コマンド単位の記録が必要 | 操作の意味を記録しやすい |
| 実装コスト | 既存環境を利用しやすい | Toolの実装と保守が必要 |
Shellが優れている、Functionが優れているという比較ではありません。
Agentにその場で調査方法を考えさせたいのか、決められた運用操作を実行させたいのかで向いている構成が変わります。
Function Callingにすれば安全になるわけでもない
ShellをやめてFunction Callingにすれば安全、と考えるのも危険です。
たとえばAgentへ次のToolだけを渡したとします。
restart_container(id)
任意のShellコマンドは実行できなくなりました。
それでもAgentが対象を間違えれば、正常に動いている本番コンテナを再起動する可能性があります。
DNSを変更できるToolなら、さらに影響は大きくなります。
update_dns_record(host, value)
このFunctionにはShellがありません。それでも使い方を誤ればサービス全体へ影響します。
そのため、Function側ではAIから渡された引数をそのまま信用せず、通常のアプリケーションと同じように実行条件を確認します。
restart_container("prod-api-01")
↓
入力形式を確認
↓
対象リソースを確認
↓
実行者の権限を確認
↓
environmentを確認
↓
必要ならHuman Approval
↓
実行
↓
監査ログへ記録
Function Callingで狭くできるのは、主にAgentが選択できる操作の種類です。
その操作を実行してよいかどうかは、別に確認する必要があります。
readとwriteを最初から分けておく
本番運用では、すべてのToolを同じ扱いにする必要もありません。
たとえば次のように分けられます。
read
- get_metrics
- get_container_status
- read_logs
- get_deploy_history
write
- restart_container
- rollback_deployment
- update_config
監視や原因調査に必要なのは、read系のToolが中心です。
Alert
↓
AI Agent
↓
metricsを確認
↓
logsを確認
↓
deploy historyを確認
↓
原因候補と対応案を出す
ここまでなら、本番環境へ変更を加えるToolは必要ありません。
修復まで自動化する場合だけwrite系を追加できます。
原因調査
↓
restart_containerを提案
↓
Human Approval
↓
restart_containerを実行
↓
復旧確認
環境ごとにPolicyを変えることもできます。
staging
→ restart_containerを自動実行可能
production
→ restart_containerはHuman Approvalが必要
Agentを導入したからといって、調査から修復まで全部を自律実行させる必要はありません。
本番障害の調査だけAIに任せる構成もある
本番サーバーへAIを導入すると聞くと、自動復旧まで想像しやすいですが、実際には調査だけでもかなり使えます。
監視システム
↓
障害を検知
↓
AI Agent
├─ metrics
├─ logs
└─ deploy history
↓
原因候補
↓
修復案
↓
Human
たとえば、
5分前のdeploy直後からHTTP 500が増加。
appコンテナのmemory使用量に大きな変化はない。
nginxではupstream connection refusedが増えている。
候補:
appコンテナが正常にlistenしていない可能性があります。
確認候補:
- appコンテナのhealth check
- application log
- 直前deployとの差分
というところまでAIが調べ、人間が最終的な操作を行う構成です。
この用途なら、Agentへwrite権限を与えない選択ができます。
本番運用でAIを使うことと、AIへ本番環境の変更権限を渡すことは同じではありません。
Shellを使うなら「本番サーバーのroot Shell」にする必要はない
未知の障害を調査するためShellを使いたい場合でも、無制限に実行できるShellへ直結する必要はありません。
たとえば次のような制約を組み合わせられます。
- filesystemをread-onlyにする
- 書き込み可能なdirectoryを限定する
sudoを使わせない- Agent専用ユーザーで実行する
- containerやsandbox内に隔離する
- network accessを必要な宛先だけに限定する
- SecretをAgentの実行環境から分離する
- 特定の操作をapproval対象にする
- 実行コマンドと結果を記録する
2026年8月28日時点のOpenAIのShell Toolでも、任意のShellコマンドを扱えるため、実行環境をsandbox化し、コマンドのallowlist / denylistやTool実行ログを組み合わせることが案内されています。
OpenAI管理のcontainerではnetwork_policyを設定でき、allowlistを使って接続先domainを限定できます。
Shell | OpenAI API
Run shell commands in hosted containers or your own local runtime.
https://developers.openai.com/api/docs/guides/tools-shell
Codexも、sandboxとapprovalを別の仕組みとして扱っています。
sandboxは「Agentが自動で操作できる技術的な範囲」を決め、approvalは「その範囲を越えるとき、人間へ確認するか」を決めます。
Sandbox | ChatGPT Learn
How sandboxing works across ChatGPT and Codex clients
https://learn.chatgpt.com/docs/sandboxing
Agent approvals & security | ChatGPT Learn
How to securely operate Codex with sandboxing, approvals, and network controls
https://learn.chatgpt.com/docs/agent-approvals-security
この設計はCodexだけに限った話ではありません。
Shellを使うAgent Harnessを自作するときも、
Agent
↓
Sandbox
↓
限定されたShell
↓
Production resources
のように、Agentと本番環境の間へ境界を置けます。
network accessはShellとは別に考える
Shellが使えるからといって、外部networkまで必要とは限りません。
障害調査で必要なのが、
journalctl
docker logs
ps
free
ss
程度なら、外部への接続を許可しなくても調査できる場合があります。
逆に、
curl https://example.com
や外部APIへのアクセスを許可すると、取得できる情報だけでなく、外部へ送信できる情報も増えます。
特にAgentが次の3つを同時に持っている場合は注意が必要です。
外部から情報を読む
+
Secretを読める
+
外部へ通信できる
Webページだけでなく、ログやIssue、ユーザー入力などにも第三者が書き込んだ文字列が含まれることがあります。
そこへAIを誘導する命令が埋め込まれていた場合、Prompt Injectionの入力経路になり得ます。
OpenAIもAgentのPrompt Injection対策について、悪意ある入力を完全に検出することだけに依存せず、仮にAgentが誘導された場合でも被害を制限できるよう、利用可能なCapabilityを制約する考え方を説明しています。
https://openai.com/index/designing-agents-to-resist-prompt-injection/
Shellを禁止すればPrompt Injectionが解決するわけではありません。
Functionしか持たないAgentでも、許可されているFunctionを誤用する可能性は残ります。
ただし、
read_logs()
get_metrics()
しか使えないAgentと、
shell
filesystem
secret access
outbound network
を持つAgentでは、誘導されたときに実行できる操作の範囲が違います。
専用のAI用APIを一から作らなくてもよい
Function方式には、Toolを一つずつ実装するコストがあります。
Shellなら、
journalctl -u nginx -n 200
で済む処理でも、Functionとして公開するなら、
read_service_logs({
service: "nginx",
lines: 200
})
のような仕組みが必要です。
対象となる操作が数十、数百と増えれば、Toolそのものの設計と保守も無視できません。
ただし、既存の管理APIがあるなら再利用できます。
GET /containers/:id/status
POST /containers/:id/restart
GET /deployments
POST /deployments/:id/rollback
すでに人間向けの管理画面がこれらのAPIを利用しているなら、その一部をAgentから呼び出せるToolへ変換できます。
そのまま公開すると権限が広すぎる場合は、Agent用のGatewayを間に置く方法もあります。
AI Agent
↓
Agent Tool Gateway
↓
Authorization / Validation / Approval
↓
Existing Internal APIs
Gateway側で、
このAgentはstatusを読める
restartはproductionでは承認が必要
rollbackは直近deployだけ許可
config変更は利用不可
といったルールを持たせます。
AI専用の運用基盤をすべて作り直すのではなく、既存の認証・認可・管理APIを利用できます。
ケースA:自宅サーバーの障害調査
個人で管理している自宅サーバーを考えます。
要件は次のようなものです。
Docker中心
管理者は自分だけ
未知の障害も調査したい
多少のリスクは許容できる
この環境で、
get_cpu_usage()
read_nginx_logs()
read_app_logs()
get_disk_usage()
get_port_status()
...
と一つずつToolを作るのは、運用コストの方が大きくなるかもしれません。
Agent専用ユーザーやcontainer、network制限などを組み合わせたShellを使い、必要な範囲で自由に調査させる方が実用的なケースです。
特に「何が壊れるか事前に分からない」環境では、Shellの探索能力を活かせます。
ケースB:SaaSの本番コンテナを再起動する
次は顧客が利用しているSaaSです。
Agentへ任せたい処理は、
container statusの確認
health checkの確認
restart
だけだとします。
この場合、Shellを公開する理由はあまりありません。
get_container_status(id)
get_container_health(id)
restart_container(id)
程度に絞れば目的を達成できます。
さらに、
get_container_status
get_container_health
→ 自動実行可能
restart_container
→ productionではHuman Approval
と分けられます。
操作内容が事前に分かっており、顧客影響も大きい環境では、限定したToolの方が設計しやすくなります。
ケースC:原因調査はAI、修復は人間
本番障害の原因調査にAIを使いたいものの、変更操作はまだ任せたくないケースです。
Agentには次の情報だけを渡します。
metrics
logs
deployment history
service status
Agentは原因候補を調べますが、再起動やrollbackは実行できません。
AI
↓
調査
↓
原因候補
↓
修復案
↓
Human
↓
既存の運用手順で修復
この構成なら、AIによる調査能力を利用しながら、本番環境へのwrite Capabilityを増やさずに済みます。
運用をAI Agent化するときの最初の段階としても採用しやすい形です。
どこまで渡すかは「必要な探索範囲」から決める
本番サーバーへAgentを接続するとき、判断材料を並べると次のようになります。
| 状況 | 構成候補 |
|---|---|
| 操作内容が数種類に決まっている | Function / Internal API |
| 定型的な復旧処理を実行したい | Function + Authorization |
| 本番への変更を伴う | Approval + Audit |
| 原因調査だけ任せたい | read-only Tool |
| 未知の障害を探索したい | 制限されたShell |
| 多数の既存CLIを組み合わせたい | Shell / Agent Harness |
| 外部networkが不要 | outbound networkを許可しない |
| 一部の外部APIだけ必要 | allowlistで限定 |
| Secretが不要 | Agent環境へ渡さない |
NISTのleast privilegeも、ユーザーやプロセスへ、その処理に必要な最小限の権限やリソースだけを与える原則として定義しています。
https://csrc.nist.gov/glossary/term/least_privilege
Agentだから特別な考え方が必要というより、既存のセキュリティ設計をAgentにも適用できます。
Shellを渡すかどうかを最初に決めなくてよい
AI Agentの構成を考えると、
Shellを渡すか
Function Callingにするか
という二択から入りたくなります。
実際には、その前にAgentの仕事を分解した方が設計しやすくなります。
何を読む必要があるか
↓
何を変更する必要があるか
↓
未知の操作を組み立てる必要があるか
↓
どの操作に人間の承認が必要か
↓
どこまでnetwork accessが必要か
↓
どのSecretへアクセスする必要があるか
ここまで決めると、Shellが必要な部分と、Functionで十分な部分が見えてきます。
未知の障害を探索させるなら、Shellを使う理由があります。
コンテナの状態確認と再起動だけなら、専用Toolで十分かもしれません。
原因調査だけなら、write Toolすら必要ない場合があります。
AI Agentへ与える権限は、「できると便利なこと」を全部並べて決めるものではありません。
そのAgentが仕事を完了するために、実際に必要な操作から決める。
本番サーバーへAIを接続するときも、この順番で考えると過剰なCapabilityを持たせにくくなります。