言語を切り替える
テーマを切り替える

Agent Sandbox 構築ガイド:AIコードを安全に実行する完全ソリューション

2025年の春、セキュリティ研究者たちがあることを実施しました——Y Combinator の Spring バッチで公開された16個の AI Agent をすべてテストしたのです。結果はどうだったでしょうか。7個が突破されました。ユーザーデータを漏洩したもの、リモートでコードを実行されたもの、さらにはデータベースを丸ごと削除されたものまでありました。

これが、AI Agent にコードを実行させる代償です。自由を与えれば、落とし穴を掘られます。

誰もが AI でコードを書き、スクリプトを動かし、データを処理しています。しかし考えたことはあるでしょうか——大規模モデルが生成したあのコードを、サーバー上で直接実行する勇気はあるのか、と。もし rm -rf / を実行されたり、AWS のキーをこっそり外部サーバーに送信されたりしたら、泣くに泣けません。

これこそが、Agent Sandbox が存在する意義です。

AI Agent と従来のアプリケーションの最大の違いはどこにあるでしょうか。会話できることでも、指示を理解できることでもありません。自分でコードを書いて実行できることです。

こんな場面を想像してください。データ分析 Agent に1GBの売上データを処理してもらおうとすると、それは読み込み、分析、グラフ生成のための Python コードを書きます。このコードは完全に大規模モデルが自動生成したもので、あなたは一度もレビューしていません。そして?それは実行されます。

ここには、いくつかの致命的なリスクがあります。

任意コード実行。大規模モデルはセキュリティ境界を理解していません。os.system()subprocess.run() といった関数を、後先を考えずに使ってしまいます。巧妙に設計されたプロンプト1つで、任意のシステムコマンドを実行させられてしまうのです。

リソース枯渇攻撃。Agent が書くコードにはリソースの意識がありません。無限ループ1つで CPU を食い尽くし、無限再帰1つでメモリを溢れさせます。サーバーは一瞬でダウンします。

ファイルシステム侵害。ファイルアクセスのパスを制限していなければ、ディスク全体を読み取り、任意のファイルに書き込めます。設定ファイル、キー、ユーザーデータ、すべてがその手中に渡ります。

ネットワークデータ流出。コードの中にこっそり HTTP リクエストを仕込み、機密データを攻撃者のサーバーに送信されても、まったく気づけません。

OWASP は2025年に AI Agent セキュリティの脅威 Top 10 を発表し、第1位に挙げられたのが「Agent ツール連携の操作(Agent Tool Interaction Manipulation)」でした。簡単に言えば、攻撃者がプロンプトインジェクションなどの手段で、Agent によるツールの呼び出し方をあなたの想定から逸脱させられる、ということです。

すでに現実の攻撃事例も出ています。

  • Langflow の RCE 脆弱性:Horizon3 が発見したリモートコード実行の脆弱性で、攻撃者は悪意ある入力を通じてサーバー上で任意のコードを実行できました。
  • Cursor の自動実行脆弱性:Cursor が特定の MCP コマンドを自動実行することを発見した研究者がおり、攻撃者は悪意あるプロンプトを構築して発火させられました。
  • Replit のデータベース消去:AI が生成したコードが、データベース全体を誤って削除しました。

サンドボックスはオプションではありません。これは AI Agent アプリケーションのインフラです。ファイアウォールなしでサーバーを公開インターネットにさらさないのと同じように、サンドボックスなしで AI にコードを実行させてはいけません。

サンドボックスのコアバリューは3つです。隔離——リスクのあるコードを檻に閉じ込める。制限——CPU、メモリ、ネットワーク、ファイルアクセスに上限を設ける。監査——何をしたかを記録し、何かあったときに追跡できるようにする。

主流サンドボックス技術の比較

さて、サンドボックスが必要だとわかったら、何を使えばよいのでしょうか。現在、市場には主に3つの技術路線があります。コンテナ(Docker)、gVisor、Firecracker マイクロ仮想マシンです。

まずは比較表で全体像をつかんでおきましょう。

ソリューションセキュリティ隔離起動速度リソースオーバーヘッド適用シーン
Docker コンテナ★★☆☆☆★★★★★★★★★★開発・テスト、低リスクコード
gVisor★★★★☆★★★★☆★★★☆☆本番環境、中程度リスク
Firecracker★★★★★★★★★☆★★★☆☆高セキュリティ要件、本番デプロイ

Docker コンテナ:高速だが安全性は不十分

Docker は最も一般的な選択肢です。起動が速く、リソース消費が低く、エコシステムも成熟しています。しかし問題は、Docker コンテナがホストとカーネルを共有していることです。

どういう意味でしょうか。コンテナ内のプロセスは namespace で隔離されていますが、攻撃者がカーネルの脆弱性を突けば、コンテナの境界を突破してホストの root 権限を奪えてしまいます。

2024年だけでも、複数のコンテナ脱出(container escape)脆弱性が公開されました。AI が生成した信頼できないコードに対して、Docker のセキュリティ境界は不十分なのです。

gVisor:ユーザー空間に「偽のカーネル」を作る

gVisor は Google がオープンソース化したプロジェクトで、その発想はとても面白いものです——ホストのカーネルを直接使うのではなく、ユーザー空間に「偽のカーネル」(Sentry と呼ばれる)を実装します。

コンテナ内のプログラムがシステムコールを発行すると、gVisor がそれを遮断し、Sentry が処理します。Sentry は安全な操作だけを許可し、危険な操作は拒否します。こうすることで、コードが破壊を試みても、本物のカーネルには触れられません。

gVisor の利点は互換性のよさで、ほとんどの Docker イメージがそのまま動きます。欠点は一定の性能オーバーヘッド(おおよそ10〜20%)があることと、一部の特殊なシステムコールがサポートされない可能性があることです。

GKE(Google Kubernetes Engine)は gVisor をネイティブにサポートしており、Pod 設定に runtimeClassName: gvisor を1行加えるだけで使えます。

Firecracker:真のハードウェアレベル隔離

Firecracker は AWS がオープンソース化したマイクロ仮想マシン技術です。各サンドボックスは小型の仮想マシンであり、それぞれ独立したカーネルを持ちます。

これは何を意味するでしょうか。たとえ攻撃者がサンドボックス内の root 権限を奪い、カーネルの脆弱性を突いたとしても、それは1つの仮想マシンの中で暴れているだけで、ホストにはまったく影響しません。

Firecracker の起動速度は100〜800ミリ秒に達し、リソースオーバーヘッドは従来の仮想マシンよりはるかに小さく済みます(仮想マシン1台あたり最小128MBのメモリで足ります)。

E2B や AWS Bedrock AgentCore といった専門的な AI コードサンドボックスサービスは、いずれも基盤に Firecracker を使っています。

選定の判断フレームワーク

どう選べばよいでしょうか。シンプルな決定木を示します。

  1. ローカル開発・テストだけ? Docker で十分です。手軽で速いです。
  2. 本番環境にデプロイする
    • セキュリティ要件は中程度で、性能を追求する → gVisor
    • セキュリティ要件が高く、コンプライアンス要件を満たす必要がある → Firecracker
  3. 自分でインフラを運用したくない? そのままマネージドサービス(E2B、Bedrock AgentCore)を使いましょう。

実践:ローカル開発サンドボックスの構築

理論をたくさん語ってきたので、実際に1つ構築してみましょう。構成は FastAPI + Jupyter Kernel + gVisor コンテナ です。

なぜこの組み合わせなのでしょうか。

  • FastAPI はシンプルな HTTP インターフェースを提供し、AI Agent は REST API を通じてコード実行リクエストを送れます
  • Jupyter Kernel はインタラクティブな Python 実行環境を提供し、変数の永続化をサポートします
  • gVisor コンテナはセキュリティ隔離を提供し、悪意あるコードがホストに影響するのを防ぎます

ステップ1:FastAPI サービスを書く

main.py ファイルを作成します。

# main.py
import asyncio
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException
from jupyter_client.manager import AsyncKernelManager
from pydantic import BaseModel

app = FastAPI()

class CodeRequest(BaseModel):
    code: str

class ExecutionResult(BaseModel):
    output: str

@asynccontextmanager
async def kernel_client():
    """Jupyter Kernel のライフサイクルを管理する"""
    km = AsyncKernelManager(kernel_name="python3")
    await km.start_kernel()
    kc = km.client()
    kc.start_channels()
    await kc.wait_for_ready()
    try:
        yield kc
    finally:
        kc.stop_channels()
        await km.shutdown_kernel()

async def execute_code(code: str, timeout: int = 30) -> str:
    """コードを実行して結果を返す"""
    async with kernel_client() as kc:
        msg_id = kc.execute(code)
        try:
            while True:
                reply = await asyncio.wait_for(
                    kc.get_iopub_msg(),
                    timeout=timeout
                )
                if reply["parent_header"]["msg_id"] != msg_id:
                    continue
                msg_type = reply["msg_type"]
                if msg_type == "stream":
                    return reply["content"]["text"]
                elif msg_type == "error":
                    return f"Error: {reply['content']['evalue']}"
                elif msg_type == "status" and reply["content"]["execution_state"] == "idle":
                    break
        except asyncio.TimeoutError:
            return "Error: Execution timed out"
    return ""

@app.post("/execute", response_model=ExecutionResult)
async def execute(request: CodeRequest):
    """コード実行エンドポイント"""
    try:
        output = await execute_code(request.code)
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
    return ExecutionResult(output=output)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

このコードの核心となるロジックは、実行リクエストを受け取るたびに独立した Jupyter Kernel を起動し、コードを実行し、結果を返し、その後 Kernel を破棄する、というものです。

ステップ2:Dockerfile を書く

FROM jupyter/base-notebook:latest

WORKDIR /app

COPY main.py /app/main.py
COPY requirements.txt /app/requirements.txt

RUN pip install --no-cache-dir -r requirements.txt

# 非 root ユーザーを使用(セキュリティのベストプラクティス)
USER jovyan

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

あの USER jovyan に注目してください。これはセキュリティの実践です。非 root ユーザーでコンテナを動かせば、たとえコードが脱出しても、得られる権限は限られます。

ステップ3:GKE にデプロイする(gVisor を有効化)

GKE を使っているなら、Pod 設定に1行加えるだけです。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: agent-sandbox
spec:
  template:
    spec:
      runtimeClassName: gvisor  # 重要:gVisor を有効化する
      containers:
      - name: sandbox
        image: your-registry/agent-sandbox:latest
        ports:
        - containerPort: 8000
        resources:
          limits:
            memory: "512Mi"
            cpu: "500m"

これで、あなたのコード実行環境はすでに gVisor サンドボックスの中で動いています。

ステップ4:セキュリティ制限を追加する

上の設定はまだ完璧ではありません。本番環境では、少なくとも以下の制限を追加する必要があります。

# ネットワークポリシー:必要な API のみアクセス可能に制限
# ファイルシステムを読み取り専用に
securityContext:
  readOnlyRootFilesystem: true
  allowPrivilegeEscalation: false

# 実行タイムアウトを設定
# FastAPI のコード内で既に timeout パラメータを追加済み

応用:Kubernetes クラスターへのデプロイ

あなたの AI Agent アプリケーションが大規模なデプロイを必要とするなら、単一コンテナでは足りません。そこで Kubernetes の Agent Sandbox コントローラーを使えます。

Google は2025年に Agent Sandbox というプロジェクトをオープンソース化し、宣言的なサンドボックス管理 API を提供しています。

Sandbox CRD のコアコンセプト

Agent Sandbox はいくつかのカスタムリソースを定義しています。

  • Sandbox:単一のサンドボックスインスタンス。安定した ID、永続ストレージ、ライフサイクル管理を持つ
  • SandboxTemplate:サンドボックステンプレート。標準化された設定を定義する
  • SandboxClaim:オンデマンドでサンドボックスインスタンスを申請する

シンプルな Sandbox 設定の例です。

apiVersion: sandbox.k8s.io/v1alpha1
kind: Sandbox
metadata:
  name: my-agent-sandbox
spec:
  template:
    spec:
      runtimeClassName: gvisor
      containers:
      - name: executor
        image: python:3.11-slim
        command: ["sleep", "infinity"]
      # 永続ストレージ
      volumes:
      - name: workspace
        emptyDir: {}
      # リソース制限
      resources:
        limits:
          memory: "1Gi"
          cpu: "1"

ライフサイクル管理

Agent Sandbox のハイライトの1つは、一時停止/再開をサポートしていることです。

# サンドボックスを一時停止する(CPU と大部分のメモリを解放)
kubectl patch sandbox my-agent-sandbox --type=merge -p '{"spec":{"paused":true}}'

# サンドボックスを再開する
kubectl patch sandbox my-agent-sandbox --type=merge -p '{"spec":{"paused":false}}'

これは断続的に実行される AI Agent に特に役立ちます——タスクがないときは一時停止すればほとんどリソースを使わず、タスクが来たら秒単位で復帰できます。

ウォームプール(Pool)

起動レイテンシをさらに減らすため、Agent Sandbox は「ウォームプール」をサポートしています——一時停止状態のサンドボックスをあらかじめまとめて作成しておき、必要になったらすぐにアクティブ化します。

この手法で、サンドボックスの「コールドスタート」時間を秒単位からミリ秒単位まで下げられます。

マネージドサービス選定のおすすめ

自分でインフラをいじりたくないなら、マネージドサービスはよい選択肢です。現在の主流には次のようなものがあります。

E2B:オープンソース + クラウドホスティングのデュアルモード

E2B は AI Agent 専用に設計されたコードサンドボックスサービスです。2つのバージョンがあります。

  • E2B Cloud:彼らのクラウドサービスを直接使い、従量課金で支払う
  • E2B on AWS:オープンソース版を自分の AWS アカウントにデプロイする

E2B は基盤に Firecracker を使っており、安全性は保証されています。SDK もとてもシンプルです。

from e2b import Sandbox

# サンドボックスを作成
sandbox = Sandbox()

# コードを実行
result = sandbox.run_code("print('Hello, World!')")

# サンドボックスを閉じる
sandbox.close()

E2B on AWS は、データ主権の要件がある企業に特に適しています——すべてのデータが自分のアカウント内にあるので、サードパーティを心配する必要がありません。

AWS Bedrock AgentCore

AWS は2025年に Bedrock AgentCore を発表し、AI Agent 向けにコード実行とブラウザ操作の能力を専門的に提供しています。

Code Interpreter は Python/JavaScript/TypeScript のランタイムを提供し、各セッションは独立したマイクロ仮想マシンで実行され、最大5GBのファイル処理をサポートします。

Browser Tool は AI Agent にブラウザ操作を可能にします——ページを開く、フォームに入力する、ボタンをクリックする、といった操作です。これはウェブページのスクレイピングや SaaS アプリケーションの操作が必要な Agent に特に役立ちます。

課金モデルも合理的です。vCPU とメモリの実際の使用時間に応じて課金され、インスタンスの稼働時間ではありません。コードの実行が終わればリソースは解放されるので、無駄に費用がかかりません。

選定のおすすめ

シーン推奨ソリューション
迅速な検証、小規模アプリE2B Cloud
エンタープライズ向け、データのローカライズが必要E2B on AWS または Bedrock AgentCore
既に AWS エコシステムを深く使っているBedrock AgentCore
ブラウザ自動化が必要Bedrock AgentCore Browser Tool
完全に自分で制御したい、運用能力がある自前の Kubernetes + Agent Sandbox

結論

ここまで多くを語ってきましたが、核心は実はひと言です。セキュリティはオプションではなく、AI Agent アプリケーションのインフラである、ということです。

技術選定の観点からは、次のとおりです。

  • 小チームで迅速に検証するなら、Docker か gVisor で十分
  • エンタープライズ向けアプリで高いセキュリティ要件があるなら、Firecracker かマネージドサービス
  • 既に Kubernetes を使っているなら、そのまま Agent Sandbox コントローラーを導入

どれを選ぶにせよ、まずはローカルテストから始めましょう。最もシンプルな FastAPI + Docker の構成を書いて動かし、それからセキュリティの強化と本番デプロイを検討します。

覚えておいてください。サンドボックスは早く導入するほどよいのです。セキュリティ事故が起きてから対処しようとすると、そのときのコストははるかに高くつきます。

AI Agent サンドボックス環境の構築

安全な AI コード実行環境をゼロから構築する

⏱️ 目安時間: 60 分

  1. 1

    ステップ1: FastAPI サービスの作成

    main.py ファイルを作成し、コード実行エンドポイントを実装します:

    • AsyncKernelManager で Jupyter Kernel を管理
    • 実行タイムアウトを設定(デフォルト30秒)
    • 実行結果またはエラー情報を返す
  2. 2

    ステップ2: Dockerfile の作成

    jupyter/base-notebook イメージをベースにビルドします:

    • 依存パッケージをインストール(FastAPI、uvicorn)
    • 非 root ユーザー(jovyan)で実行
    • ポート8000を公開
  3. 3

    ステップ3: Kubernetes へのデプロイ

    gVisor を有効化する Pod 設定を行います:

    • runtimeClassName: gvisor を設定
    • リソース制限を設定(CPU/メモリ)
    • セキュリティコンテキストを追加(読み取り専用ファイルシステム)
  4. 4

    ステップ4: サンドボックス隔離の検証

    セキュリティ境界をテストします:

    • ホストのファイルシステムへのアクセスを試す(拒否されるべき)
    • リソース集約型コードを実行する(制限されるべき)
    • ネットワーク隔離が有効か確認する

FAQ

Docker コンテナと gVisor の違いは何ですか?
Docker コンテナはホストとカーネルを共有するため、攻撃者がカーネルの脆弱性を突くと脱出できてしまいます。gVisor はユーザー空間に「偽のカーネル」(Sentry)を実装し、すべてのシステムコールを遮断して安全な操作だけを許可するため、より強力な隔離を提供します。
gVisor ではなく Firecracker を使うべきなのはどんなときですか?
セキュリティ要件が極めて高いときに Firecracker を選びます:

• ハードウェアレベルの隔離が必要(金融、医療データなど)
• 厳格なコンプライアンス要件を満たす必要がある
• まったく信頼できないサードパーティのコードを扱う

gVisor は性能オーバーヘッドが小さく(10〜20%)、ほとんどの本番シナリオに適しています。
E2B と AWS Bedrock AgentCore はどう選べばよいですか?
E2B は迅速な検証やオープンソースで自分で制御したいケースに向いています:
• 小規模アプリはまず E2B Cloud を使う
• データのローカライズが必要なら E2B on AWS

Bedrock AgentCore は AWS エコシステムを深く使うユーザーに向いています:
• 既に AWS サービスを使っていれば統合が容易
• ブラウザ自動化が必要なら Browser Tool を選ぶ
サンドボックスはコード実行性能に影響しますか?
ある程度の影響はあります:Docker はほぼ損失なし、gVisor は約10〜20%、Firecracker は約15〜30%のオーバーヘッドです。ただし AI Agent のコード実行シナリオ(データ分析、スクリプト処理)では、このオーバーヘッドは通常許容範囲です。
ローカル開発で素早くサンドボックスを構築するには?
最もシンプルな方法は、gVisor 付きのコンテナを Docker で動かすことです。GKE を使っているなら、Pod 設定に `runtimeClassName: gvisor` を1行加えるだけです。純粋なローカル開発であれば Docker の隔離でも十分で、重要なのはリソース制限とユーザー権限の設定です。

5分で読めます · 公開日: 2026年3月23日 · 更新日: 2026年6月1日

関連記事

コメント

GitHubアカウントでログインしてコメントできます