なぜサンドボックス認証が難しいのか

LLMベースのエージェント(OpenCode、Claude Codeなど)が普及するにつれ、外部API呼び出しを安全に処理する方法が重要になっています。特にサンドボックス内で実行されるコードは信頼できないため、APIトークンを直接注入する従来の方法はリスクが伴います。トークンが漏洩すると、攻撃者に悪用される可能性があります。

この記事では、Cloudflare Sandboxのoutbound Workers機能を利用して、エージェントが外部サービスを呼び出す際に**ゼロトラスト(Zero Trust)**の原則を適用する方法をステップバイステップで解説します。

従来の認証方式の課題

方式メリットデメリット
APIトークン直接注入実装が簡単トークン漏洩リスク、有効期限管理が煩雑
OIDCワークロードアイデンティティ短期トークンでセキュリティ向上サービス統合が困難、独自トークン交換サーバーが必要
カスタムプロキシ完全な柔軟性プロキシ構築・運用が複雑、パフォーマンス問題

理想的な認証メカニズムは、ゼロトラスト、シンプルさ、柔軟性、パフォーマンス、透過性をすべて満たす必要があります。outbound Workersがどのようにこれらの条件を満たすか見ていきましょう。

Cloudflare Sandbox outbound Workers zero trust credential injection diagram Programming Illustration

実践: outbound Workersでゼロトラスト認証を実装する

1. 基本: リクエストのログ記録とブロック

最もシンプルな例として、すべてのアウトバウンドHTTPリクエストをインターセプトし、GETのみ許可してそれ以外をブロックします。

class MySandboxedApp extends Sandbox {
  static outbound = (req, env, ctx) => {
    // GET以外のリクエストはすべてブロックしログを記録
    if (req.method !== 'GET') {
      console.log(`コンテナが ${req.method} リクエストを送信: ${req.url}`);
      return new Response('許可されていません', { status: 405 });
    }
    // GETリクエストはそのまま転送
    return fetch(req);
  };
}

このプロキシはサンドボックスVMと同じマシン上で実行されるため、レイテンシはごくわずかです。Workersダッシュボードですべてのログを確認でき、可観測性も確保できます。

2. ゼロトラスト認証情報の注入

最も強力なユースケースは、シークレットトークンをサンドボックスに一切露出させずに外部サービスへ安全に渡すことです。

class OpenCodeInABox extends Sandbox {
  static outboundByHost = {
    "my-internal-vcs.dev": (request, env, ctx) => {
      // リクエストヘッダーにシークレットトークンを追加
      // サンドボックス内のコードはこのトークンを絶対に見られません!
      const headersWithAuth = new Headers(request.headers);
      headersWithAuth.set("x-auth-token", env.SECRET);
      return fetch(request, { headers: headersWithAuth });
    }
  };
}

ここで重要なのは、env.SECRETがサンドボックスではなくoutbound Workerの環境変数としてのみ存在する点です。また、ctx.containerIdを利用してサンドボックスインスタンスごとに異なるトークンを注入することも可能です。

static outboundByHost = {
  "my-internal-vcs.dev": async (request, env, ctx) => {
    // KVは保存時・転送時に暗号化されています
    const authKey = await env.KEYS.get(ctx.containerId);
    const requestWithAuth = new Request(request);
    requestWithAuth.headers.set("x-auth-token", authKey);
    return fetch(requestWithAuth);
  }
}

3. 動的ネットワーク制御

初期はnpmパッケージをダウンロードするためにGitHub、npmjs.orgへのアクセスを許可し、インストール完了後は即座にブロックするシナリオです。

class MySandboxedApp extends Sandbox {
  static outboundHandlers = {
    async allowHosts(req, env, { params }) {
      const url = new URL(request.url);
      if (params.allowedHostnames.includes(url.hostname)) {
        return await fetch(newRequest);
      } else {
        return new Response(null, { status: 403 });
      }
    },
    async noHttp(req) {
      return new Response(null, { status: 403 });
    }
  };
}

async function setUpSandboxes(req, env) {
  const sandbox = await env.SANDBOX.getByName(userId);
  // 初期: GitHub, npmのみ許可
  await sandbox.setOutboundHandler("allowHosts", {
    allowedHostnames: ["github.com", "npmjs.org"]
  });
  await sandbox.gitClone(userRepoURL);
  await sandbox.exec("npm install");
  // インストール完了後、すべてのHTTPをブロック
  await sandbox.setOutboundHandler("noHttp");
}

これにより、ネットワークが開放されている時間を最小限に抑え、攻撃対象領域を削減できます。

4. MITMプロキシによるHTTPSトラフィック制御

HTTPSリクエストも制御するにはTLS復号が必要です。Cloudflare Sandboxは各インスタンスごとに**一時認証局(CA)**を生成し、サンドボックス内部にインストールします。

export class MyContainer extends Container {
  interceptHttps = true;
}

MyContainer.outbound = (req, env, ctx) => {
  // すべてのHTTP(S)リクエストがこのフックを通過します
  return fetch(req);
};

この方式は完全に透過的に動作します。サンドボックス内のアプリケーションはプロキシの存在を認識しません。

5. 発展: WorkerEntrypointを活用した細粒度制御

IP範囲やホスト名パターン(globマッチング)でリクエストをインターセプトできます。

export class MyWorker extends WorkerEntrypoint {
  fetch() {
    return new Response(this.ctx.props.message);
  }
}

// コンテナ内部
this.ctx.container.start({ enableInternet: false });
const outboundWorker = this.ctx.exports.MyWorker({ props: { message: 'hello' } });
await this.ctx.container.interceptOutboundHttp('15.0.0.1:80', outboundWorker);
// 以降、15.0.0.1:80へのすべてのHTTPリクエストは "hello" を返します

// 動的に変更可能!既存の接続にも影響なし
const secondOutboundWorker = this.ctx.exports.MyWorker({ props: { message: 'switcheroo' } });
await this.ctx.container.interceptOutboundHttp('15.0.0.1:80', secondOutboundWorker);

// ホスト名、CIDR(IPv4/IPv6)もサポート
await this.ctx.container.interceptOutboundHttp('example.com', secondOutboundWorker);
await this.ctx.container.interceptOutboundHttp('*.example.com', secondOutboundWorker);
await this.ctx.container.interceptOutboundHttp('123.123.123.123/23', secondOutboundWorker);

すべてのプロキシはサンドボックスVMと同じマシン上でローカルに実行されるため、コンテナとWorker間の通信は「認証なし」でも安全です。

Developer configuring dynamic egress proxy rules in Sandbox dashboard IT Technology Image

注意点と制限

  1. パフォーマンスオーバーヘッド: MITMプロキシを使用するとTLSハンドシェイクが追加で発生します。レイテンシに非常に敏感なアプリケーションでは注意が必要です。
  2. 証明書の信頼問題: サンドボックス内部にインストールされた一時CAはそのサンドボックスでのみ有効です。標準コンテナではsudo update-ca-certificatesなどで手動設定が必要になる場合があります。
  3. 複雑なポリシー: outboundHandlersを複数定義すると管理の複雑さが増します。ポリシーをコードで管理するため、バージョン管理とテストが必須です。
  4. Cloudflareエコシステム依存: 現在この機能はCloudflare Workersエコシステム専用です。他のプラットフォームで同様の機能を実装するには、独自のプロキシサーバー(Envoy、Nginxなど)をVM内にデプロイする必要があるかもしれません。

次のステップ

  • Cloudflare Sandbox公式ドキュメントでさらに多くの例を確認してください。
  • OIDCとoutbound Workersを組み合わせたワークロードアイデンティティフェデレーションパターンを学習してみてください。
  • wrangler devを使用したローカル開発環境のセットアップ方法を習得すると、生産性が大幅に向上します。

Sandbox VM architecture with sidecar proxy and Workers runtime Software Concept Art

まとめ

outbound Workersは、サンドボックス環境においてゼロトラスト、動的制御、透過性をすべて満たす強力な認証・ネットワーク制御ソリューションです。わずか数行のJavaScriptでAPIトークンを安全に注入し、動的にネットワークポリシーを変更し、すべてのトラフィックを監視できます。

特にLLMエージェントがますます多くの権限を必要とする現在、このアプローチは必須です。「信頼できないコード」に「最小権限」のみを付与するという原則をコードレベルで実現できます。

合わせて読みたい記事

根拠資料: Cloudflare公式ブログ - Sandbox Auth

本コンテンツは、信頼性の高い情報源をもとにAIツールを活用して作成され、編集者によるレビューを経て公開されています。専門家によるアドバイスの代替となるものではありません。