
2026/02/28 0:03
安全でスケーラブルなエージェントサンドボックスインフラストラクチャの構築
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
概要
この記事では、OpenAI の隔離エージェントが、単純なブラウザ専用 Lambda 関数から Unikraft で構築された完全にサンドボックス化されたマイクロ VM へと進化した経緯を説明しています。新しい設計は パターン 1(バックエンドエージェント上のツール隔離)から パターン 2(秘密情報を保持しないサンドボックス内に完全に隔離されたエージェント)へ移行し、各エージェントをディスポーザブルにして認証情報漏洩を排除します。
本番環境では、すべてのエージェントが Unikraft マイクロ VM 内で実行され、起動時間は 1 秒未満です。開発時には同じイメージを Docker コンテナとして起動します。サンドボックスには
SESSION_TOKEN、CONTROL_PLANE_URL、SESSION_ID の 3 つの環境変数のみが渡され、AWS キーやデータベース認証情報は公開されません。
強化策には以下が含まれます:
- バイトコード専用実行(エージェントは
ファイルのみを使用).pyc - 権限の削減:非 root ユーザーへ昇格
- 秘密情報読み取り後に環境から除去
ステートレス FastAPI コントロールプレーン は、セッショントークンを検証し、LLM 呼び出し時に完全な会話履歴を転送、費用上限を適用、請求処理、および presigned S3 URL を介したファイルアップロード/ダウンロードのプロキシを行います。ファイル同期は、サンドボックスがコントロールプレーンから presigned URL を要求し、直接 S3 にアップロードすることで実現され、AWS 認証情報を保持しません。
コンポーネント間の通信は AgentGateway プロトコルで抽象化されています:本番用 HTTP 呼び出しには
ControlPlaneGateway、ローカル評価には DirectGateway を使用します。スケーリングは、各セッションごとに Unikraft VM を独立して拡張し、ステートレスなコントロールプレーンインスタンスをロードバランシングし、バックエンドサービスを ECS Fargate にデプロイすることで実現します。
パターン 2 の主なトレードオフは、操作ごとに追加のネットワークホップが発生することですが、より強固な隔離と認証情報管理の簡素化を提供します。コア原則は「エージェントには盗む価値のあるものや保持すべきものを一切持たせない」ということであり、すべての秘密はコントロールプレーンに残ります。
このアーキテクチャにより、企業は LLM 主導のワークロードを安全に実行でき、機密データを保持できないディスポーザブルエージェントで運用できます。
本文
私たちがここまで来た経緯
Browser Use では数百万の Web エージェントを稼働させています。
最初は AWS Lambda 上でブラウザ専用エージェントを使用しており、各呼び出しは完全に分離されて即座にスケールでき、秘密情報も不要でした。
その後コード実行機能を追加しました。エージェントは Python を書いて実行したり、シェルコマンドを走らせたり、ファイルを作成することができます。この機能は「ツール」として隔離されたサンドボックス内で動作させ、コードはバックエンドではなくそのサンドボックス上で走ります。
しかしエージェントのループ自体は REST API と同じバックエンド上で実行されていました。再デプロイするとすべてのエージェントが停止し、メモリを大量に消費するエージェントは API を遅くしました。根本的に異なる 2 つのワークロードが同じプロセスを共有していたわけです。
2 つのパターン
エージェントが任意コードを実行できると、環境変数や API キー、データベース資格情報、内部サービスなどマシン上の何でもアクセス可能になります。したがってインフラストラクチャや秘密情報から完全に隔離する必要があります。
| パターン | 隔離対象 |
|---|---|
| 1 | ツール(コード実行・ターミナルアクセス)を別サンドボックスで動かし、エージェント自体は自社インフラ上に残す。エージェントは HTTP 経由でサンドボックスへ呼び出します。 |
| 2 | エージェント全体 をサンドボックス内で実行し、ゼロ秘密で動かします。外部と通信する際はすべて制御プレーン(クレデンシャルを保持)経由にします。 |
エージェントは「使い捨て」になります――盗むべき秘密も保存すべき状態もありません。必要なら停止・再起動・スケールが自由です。真実は制御プレーンにあります。
当初はパターン 1 で始め、後にパターン 2 に移行しました。
サンドボックス
同じコンテナイメージをどこでも使います:
-
本番:Unikraft micro‑VM(起動 < 1 秒)。
各エージェントは AWS の専用ベアメタルマシン上で Unikraft Cloud の REST API を通じてプロビジョニングされ、独自の VM を取得します。
サンドボックスには
、SESSION_TOKEN
、CONTROL_PLANE_URL
の 3 つだけが渡されます。AWS キーやデータベース資格情報、API トークンは一切ありません。SESSION_ID -
ローカル開発 / 評価:Docker コンテナ(同じイメージ、エントリポイント、制御プレーンプロトコル)。
sandbox_mode: 'docker' | 'ukc' という単一の設定スイッチでプロビジョニングコードがどちらの経路を取るか決定します。
本番での Unikraft
- 各エージェントはアイドル時に停止し、次のリクエストで即座に再開する micro‑VM を持ちます。
- サンドボックスは複数の Unikraft メトロ間で分散され、ボトルネックを回避します。
開発 / 評価での Docker
- 同じイメージがローカルまたは評価パイプライン上で Docker コンテナとして動作します。
- 評価時には数百エージェントを並列起動し、本番では Unikraft にデプロイします。
ハードニング
サンドボックスはエージェントコードが走る前にいくつかの手順を踏みます:
- バイトコードのみ実行 – Docker ビルド時にすべての Python ソースを
にコンパイルし、.pyc
ファイルは削除します。フレームワークコードは root でメモリ上にロードされ、一度ロードされたらソースは消えます。.py - 権限低減 – エントリポイントは root で起動(root 所有のバイトコードを読むため)し、すぐに
でサンドボックスユーザーへ切り替わります。以降は非特権で実行されます。setuid/setgid - 環境変数削除 –
、SESSION_TOKEN
、CONTROL_PLANE_URL
を Python 変数に読み込み後、SESSION_ID
から削除します。エージェントが環境を調べてもこれらは無い状態です。os.environ
VM はプライベート VPC 内で動作し、制御プレーンとのみ通信する権限しか持ちません。
制御プレーンの働き
制御プレーンはプロキシサービスとして機能します。サンドボックスは外部へ直接アクセスできず、すべてのリクエストが制御プレーンを経由します。
- ステートレス FastAPI – サンドボックスから送られる各リクエストには
ヘッダーがあります。Bearer: {session_token}
制御プレーンはトークンでセッションを検索し、有効か確認後、実際の資格情報で処理を行います。
LLM プロキシ
LLM 呼び出しごとにサンドボックスは新しいメッセージだけを送ります。
制御プレーンはデータベースに保存された完全な会話履歴を取得し、再構築してプロバイダーへ転送します。これでサンドボックスはステートレスになります――停止しても再起動すれば会話は続きます。
また、費用上限の適用と請求処理も制御プレーンが行います。
ファイル同期(プリサイン URL)
サンドボックスには
/workspace ディレクトリがあります。ファイル同期サービスは変更を監視し、定期的に S3 へ同期しますが、サンドボックスは AWS 資格情報を持ちません。代わりに制御プレーンからプリサイン URL を取得します:
- サンドボックスが
の変更ファイルを検知。/workspace
にファイルパスを送信。POST /presigned-urls- 制御プレーンがセッション限定の S3 アップロード用プリサイン URL を生成。
- サンドボックスはその URL で直接 S3 にアップロード。
ダウンロードも同様に逆方向で行われます。
ゲートウェイルール
サンドボックス内ではエージェントが制御プレーンへ Gateway プロトコルを通じて通信します:
class AgentGateway(Protocol): async def invoke_llm(self, new_messages, tools, tool_choice) -> LLMResponse: ... async def persist_messages(self, messages) -> None: ...
- 本番では
が HTTP リクエストを制御プレーンへ送信。ControlPlaneGateway - ローカル開発・評価時は
が直接 LLM を呼び出し、履歴はメモリに保持。DirectGateway
インターフェースは同じなので、エージェントコード側でどちらを使っているかは意識せず同じ振る舞いが得られます。
スケーリング
制御プレーンはステートレスです:トークン検証 → 処理 → 結果返却。
- エージェント数増やしたい? サンドボックスを追加起動。
- 処理スループットが足りない? ロードバランサー後ろに制御プレーンインスタンスを追加してオートスケール。
各層は自身のボトルネックでスケールします。
バックエンドは ECS Fargate をプライベートサブネットで ALB 背景に配置し、CPU 使用率に応じて自動スケール。
サンドボックスは Unikraft により独立してスケールし、各セッションが専用 VM を持ちます。
まとめ
コード実行可能なエージェントをサンドボックス化する方法には 2 通りあります:
- ツールだけ隔離 – コード実行を別サンドボックスで動かし、エージェントは自社バックエンドに残す。
- エージェント全体隔離 – エージェント全体をサンドボックスに入れ、外部との通信は制御プレーン経由にする。
私たちはパターン 2 を採用しました。制御プレーンがすべての資格情報を保持し、LLM 呼び出し・ファイルストレージ・請求などをプロキシします。サンドボックスには 3 つの環境変数だけが渡され、他にアクセスできません。本番では Unikraft micro‑VM、開発と評価では Docker コンテナとして同じイメージを使います。
トレードオフは「操作ごとにネットワークホップが増える」ことと、「サービスが 1 つ増える」点ですが、実際の遅延は LLM 応答時間と比べて無視できるほどであり、運用上も既存の Ops チームが扱える複雑さです。
キーポイント:エージェントには盗む価値のあるものも保持する価値のある状態もなくすべきです。