◉CLAUDE LABEN
●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り45日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました●2.1.301 — vim の % モーション、VS Code パネルでの LaTeX 数式表示、使用量上限待ちのリトライ監視の上限が入りました(10/15)●2.1.299 — 200K トークン超で約54分放置した会話はアイドル圧縮。MCP の許可ルールは名指ししたサーバーだけに一致します●SONNET 4.5 — Claude API での提供終了は 11/30、残り45日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●FAST MODE — Opus 5.5 の Fast mode がリサーチプレビューを終え、ベータヘッダーが不要になりました(10/15)●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました
記事一覧/API & SDK
⬡ API & SDK/2026-04-12上級

Claude Managed Agents のサンドボックス設計 ― 本番環境で安全に自律エージェントを動かす技術

Claude Managed Agentsのサンドボックスを3層構造で解剖し、本番環境で自律エージェントを安全に動かすセキュリティパターンを解説します。リソース制限の実践的な設定値、SSEストリーミングによるリアルタイム監視、暴走時のフェイルセーフ設計、デプロイ前チェックリストまで実装コード付きです。

managed-agents6sandboxsecurity10production87api39

自律型AIエージェントを本番サービスに組み込むとき、最初にぶつかる壁は「どこまで自由にさせるか」の線引きです。

2026年4月、AnthropicがパブリックベータとしてリリースしたClaude Managed Agentsは、この問題に対する明確な回答を持っています。コンテナベースのサンドボックス、サーバーサイドイベント(SSE)ストリーミング、そしてビルトインツールの組み合わせによって、エージェントの自律性とセキュリティを両立させる設計です。

しかし公式ドキュメントだけでは、本番運用で直面する「コンテナのリソース制限をどう設定するか」「ネットワークアクセスの許可範囲はどこまでが適切か」といった実務的な判断が難しいです。ここでは実際にManaged Agentsを本番環境に導入した経験をもとに、サンドボックスのセキュリティ設計パターンを具体的なコードとともに解説します。

サンドボックスアーキテクチャの3層構造

Managed Agentsのサンドボックスは、単なるDockerコンテナではありません。以下の3つのレイヤーで多層防御を実現しています。

import anthropic
 
client = anthropic.Anthropic()
 
# エージェントの作成時にサンドボックス設定を指定
agent = client.agents.create(
    model="claude-sonnet-4-6",
    instructions="データ分析タスクを実行するエージェント",
    tools=[
        {"type": "code_execution"},
        {"type": "file_read"},
        {"type": "file_write"},
    ],
    # サンドボックス設定
    sandbox={
        "type": "managed",
        "memory_mb": 512,
        "timeout_seconds": 300,
        "network_access": "restricted",
        "allowed_domains": [
            "api.example.com",
            "storage.googleapis.com"
        ]
    }
)

第1層:コンテナ分離は、各エージェントセッションが独立したLinuxコンテナで実行される仕組みです。ファイルシステムは完全に隔離され、あるセッションで作成したファイルが別セッションから見えることはありません。

第2層:リソース制限では、メモリ・CPU・実行時間に上限を設ける。上のコード例では512MBのメモリと300秒のタイムアウトを指定しているが、この値の決め方にコツがあります。

第3層:ネットワークポリシーが最も重要です。network_access を "restricted" にすると、allowed_domains に明示したドメイン以外への外向き通信がすべてブロックされます。本番環境では "full" を使うべきケースはほぼありません。

リソース制限の実践的な設定値

公式ドキュメントでは memory_mb のデフォルトが1024MBと書かれているが、実際に本番で運用してみると、タスクの種類によって最適値は大きく異なります。

# タスク別のリソース設定テンプレート
 
SANDBOX_PROFILES = {
    # テキスト処理系(要約・分類・変換)
    "text_processing": {
        "memory_mb": 256,
        "timeout_seconds": 120,
        "network_access": "none",
    },
    # データ分析系(CSV/JSON解析、グラフ生成)
    "data_analysis": {
        "memory_mb": 1024,
        "timeout_seconds": 600,
        "network_access": "restricted",
        "allowed_domains": ["storage.googleapis.com"],
    },
    # コード生成・実行系
    "code_execution": {
        "memory_mb": 2048,
        "timeout_seconds": 900,
        "network_access": "restricted",
        "allowed_domains": ["pypi.org", "registry.npmjs.org"],
    },
    # 外部API連携系
    "api_integration": {
        "memory_mb": 512,
        "timeout_seconds": 300,
        "network_access": "restricted",
        # allowed_domains はタスクごとに動的に設定
    },
}
 
def create_agent_with_profile(profile_name: str, extra_domains: list[str] | None = None):
    """プロファイルに基づいてエージェントを生成する"""
    config = SANDBOX_PROFILES[profile_name].copy()
 
    if extra_domains and config.get("network_access") == "restricted":
        config.setdefault("allowed_domains", [])
        config["allowed_domains"].extend(extra_domains)
 
    return client.agents.create(
        model="claude-sonnet-4-6",
        instructions=f"Profile: {profile_name}",
        tools=[{"type": "code_execution"}],
        sandbox={"type": "managed", **config},
    )

ここで注目してほしいのは "text_processing" プロファイルの "network_access": "none" です。テキスト処理タスクでは外部通信が不要なケースがほとんどで、ネットワークを完全に遮断することでセキュリティリスクを最小化できます。「必要最小限の権限」という原則は、エージェント設計においても変わらありません。

SSEストリーミングによるリアルタイム監視

Managed Agentsの大きな特徴は、エージェントの実行状況をSSE(Server-Sent Events)でリアルタイムに取得できることです。これを活用すると、異常検知や自動停止の仕組みを構築できます。

import json
from collections import defaultdict
 
class AgentMonitor:
    """エージェントの実行を監視し、異常を検知する"""
 
    def __init__(self, max_tool_calls: int = 50, max_errors: int = 3):
        self.max_tool_calls = max_tool_calls
        self.max_errors = max_errors
        self.tool_call_count = 0
        self.error_count = 0
        self.accessed_files: list[str] = []
 
    def process_event(self, event) -> dict:
        """SSEイベントを処理し、異常があれば警告を返す"""
        result = {"action": "continue", "warnings": []}
 
        if event.type == "tool_use":
            self.tool_call_count += 1
 
            # ツール呼び出し回数の上限チェック
            if self.tool_call_count > self.max_tool_calls:
                result["action"] = "stop"
                result["warnings"].append(
                    f"ツール呼び出し上限超過: {self.tool_call_count}/{self.max_tool_calls}"
                )
                return result
 
            # ファイルアクセスの追跡
            if event.tool_name in ("file_read", "file_write"):
                path = event.tool_input.get("path", "")
                self.accessed_files.append(path)
 
                # 機微なパスへのアクセス検知
                sensitive_patterns = ["/etc/", "/proc/", "/sys/", ".env", "credentials"]
                for pattern in sensitive_patterns:
                    if pattern in path:
                        result["warnings"].append(
                            f"機微なパスへのアクセス検知: {path}"
                        )
 
        elif event.type == "error":
            self.error_count += 1
            if self.error_count >= self.max_errors:
                result["action"] = "stop"
                result["warnings"].append(
                    f"エラー上限到達: {self.error_count}/{self.max_errors}"
                )
 
        return result
 
async def run_monitored_agent(agent_id: str, task: str):
    """監視付きでエージェントを実行する"""
    monitor = AgentMonitor(max_tool_calls=30, max_errors=2)
 
    session = client.agents.sessions.create(agent_id=agent_id)
 
    with client.agents.sessions.turn_stream(
        session_id=session.id,
        messages=[{"role": "user", "content": task}],
    ) as stream:
        for event in stream:
            check = monitor.process_event(event)
 
            if check["warnings"]:
                for w in check["warnings"]:
                    print(f"⚠️ {w}")
                    # 本番ではここで Slack/PagerDuty に通知
 
            if check["action"] == "stop":
                print("🛑 エージェントを強制停止")
                client.agents.sessions.cancel(session_id=session.id)
                break
 
    return {
        "tool_calls": monitor.tool_call_count,
        "errors": monitor.error_count,
        "files_accessed": monitor.accessed_files,
    }

このコードの肝は process_event メソッドで、ツール呼び出しのたびに3つのチェックを走らせている点です。回数制限、ファイルパスの安全性チェック、エラー回数の累積。どれか1つでも閾値を超えたら即座にセッションをキャンセルします。

本番運用ではここにさらに、ツール実行時間の移動平均を監視して急激な遅延を検知するロジックや、特定のツールの連続呼び出し(無限ループの兆候)を検知するパターンを追加しています。

フェイルセーフ設計:エージェントが暴走したときの対処

どれだけ慎重にサンドボックスを設計しても、「想定外の振る舞い」は起こりうる。重要なのは、暴走したときのダメージを最小化する仕組みを事前に用意しておくことです。

import asyncio
from contextlib import asynccontextmanager
from dataclasses import dataclass, field
from datetime import datetime
 
@dataclass
class SessionGuard:
    """セッションのライフサイクルを管理するガード"""
    session_id: str
    started_at: datetime = field(default_factory=datetime.now)
    max_duration_seconds: int = 600
    max_output_bytes: int = 10 * 1024 * 1024  # 10MB
    total_output_bytes: int = 0
 
    @property
    def elapsed_seconds(self) -> float:
        return (datetime.now() - self.started_at).total_seconds()
 
    @property
    def is_expired(self) -> bool:
        return self.elapsed_seconds > self.max_duration_seconds
 
    def track_output(self, data: str) -> bool:
        """出力データを追跡し、上限超過でFalseを返す"""
        self.total_output_bytes += len(data.encode("utf-8"))
        return self.total_output_bytes <= self.max_output_bytes
 
@asynccontextmanager
async def guarded_session(agent_id: str, **guard_kwargs):
    """ガード付きセッションのコンテキストマネージャ"""
    session = client.agents.sessions.create(agent_id=agent_id)
    guard = SessionGuard(session_id=session.id, **guard_kwargs)
 
    # タイムアウト監視タスクを並行起動
    async def _watchdog():
        while not guard.is_expired:
            await asyncio.sleep(5)
        print(f"⏰ セッション {session.id} がタイムアウト")
        try:
            client.agents.sessions.cancel(session_id=session.id)
        except Exception:
            pass  # すでに終了済みの場合
 
    watchdog_task = asyncio.create_task(_watchdog())
 
    try:
        yield session, guard
    finally:
        watchdog_task.cancel()
        try:
            client.agents.sessions.delete(session_id=session.id)
        except Exception:
            pass

SessionGuard は時間制限と出力量制限の2つを同時に管理します。特に出力量制限は見落としがちだが、エージェントが巨大なファイルを生成し続けるケースへの対策として不可欠です。

_watchdog コルーチンは5秒間隔でタイムアウトを監視し、制限時間を超えた瞬間にセッションを強制キャンセルします。Managed Agents APIの timeout_seconds とは別に、アプリケーション側でも独立したタイムアウトを設けておくことで、API側の制御が何らかの理由で効かなかった場合のセーフティネットになります。

本番デプロイ時のチェックリスト

ここまでのパターンを踏まえて、Managed Agentsを本番にデプロイする際に確認すべき項目をまとめる。

ネットワーク制御として、network_access がタスクに応じて "none" か "restricted" に設定されていること。allowed_domains が必要最小限であること。内部APIへのアクセスが必要な場合は、エージェント専用のAPIゲートウェイを経由させること。

リソース制限として、memory_mb と timeout_seconds が実際のワークロードに基づいて設定されていること。負荷テストで最大メモリ使用量を計測し、20%のマージンを加えた値を設定すること。

監視・アラートとして、SSEイベントをログに記録し、異常パターン(ツール呼び出しの急増、エラーの連続発生)を検知する仕組みがあること。セッションの平均実行時間と成功率をダッシュボードで可視化していること。

フェイルセーフとして、アプリケーション側のタイムアウトがAPI側とは独立して機能すること。エージェントの出力量に上限があること。緊急停止の手段(全セッション一括キャンセル)が運用手順に含まれていること。

これらはManaged Agentsに限らず、自律型AIエージェントを運用する際の普遍的な原則です。エージェントに「何ができるか」を考えるのと同じくらい、「何をさせないか」を考えることが、本番環境での信頼性を左右します。


この記事はプレミアムコンテンツの見本として全文を無料公開しています。Claude Lab のプレミアム記事では、このような実践的な実装パターンや本番運用のノウハウを、動作するコード付きで詳しく解説しています。すべてのプレミアム記事を読むには、メンバーシップへの登録をご検討ください。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

⬡ API & SDK2026-04-26
Claude API × WebSocket × Redis Pub/Sub でスケーラブルなリアルタイム AI チャットサーバーを構築する — Node.js 本番設計・マルチユーザー対応・コスト制御の実装
Claude API × WebSocket × Redis Pub/Sub でリアルタイム AI チャットサーバーを本番運用する設計と実装。SSE との判断基準、マルチインスタンス対応、停止遅延がユーザーごとの予算精度をどう崩すかまで、計測コードつきで扱います。
⬡ API & SDK2026-04-23
Claude API の tool_choice で無駄な推論を減らす — 4モードの使い分けとコスト最適化パターン
Claude API の tool_choice パラメータは、ツール呼び出しの挙動とコストの両方を左右します。auto / any / tool / none の4モードを実運用で使い分けるパターンを、動くコードとともに整理します。
⬡ API & SDK2026-03-27
Claude API プロダクション耐障害設計パターン — モデルルーティング・サーキットブレーカー・フォールバック戦略の実装ガイド
Claude APIを本番運用で支える耐障害設計の実装パターン。サーキットブレーカー、モデルルーティング、フォールバックチェーン、リトライ戦略、ディザスタリカバリをTypeScriptの実装コードと、運用で気づいた注意点を添えて整理しました。