Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

アウトバウンドトラフィックを処理する

最終更新 Markdown で表示Agent セットアップ

アウトバウンドハンドラーを使うと、信頼できるコードでサンドボックスからの HTTP トラフィックを傍受し、変更できます。

次の用途に使います。

  • 特定の送信先オリジンを許可または拒否する
  • 認可ヘッダーやトークンを安全に注入する
  • トラフィックを透過的に付け替える
  • アウトバウンドトラフィックに独自ポリシーを追加する(特定の HTTP リクエストの拒否など)
  • KV、R2、Durable Objects などの Workers バインディングに接続する

アウトバウンドトラフィックをブロックする

enableInternet = false で、デフォルトのパブリックインターネットアクセスをブロックします。

import { Sandbox } from "@cloudflare/sandbox";

export class MySandbox extends Sandbox {
	enableInternet = false;
}
import { Sandbox } from "@cloudflare/sandbox";

export class MySandbox extends Sandbox {
	enableInternet = false;
}

enableInternetfalse のとき、このページで後述する allowedHosts またはアウトバウンドハンドラーで明示的に許可したトラフィックだけがサンドボックスから出られます。利用できるポートは 80443、DNS だけです。DNS クエリは Cloudflare の DNS サーバーを使います。

ホスト単位でトラフィックをブロックまたは許可する

Sandbox クラスの allowedHostsdeniedHosts プロパティで、アウトバウンドトラフィックをフィルタできます。

allowedHosts を設定すると、デフォルト拒否の許可リストになります。リストにないホストまたは IP は拒否され、一致する送信先だけが outbound または outboundByHost ハンドラーに到達できます。

allowedHostsdeniedHosts は、単純な glob パターンも使えます。* は任意の文字シーケンスに一致します。

デフォルトでは、Sandbox はインターネットアクセスを許可します。特定のホストまたは IP を拒否するには deniedHosts を設定します。

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };

export class MySandbox extends Sandbox {
	deniedHosts = ["some-nefarious-website.com", "141.101.64.0/18"];
}
import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };

export class MySandbox extends Sandbox {
	deniedHosts = ["some-nefarious-website.com", "141.101.64.0/18"];
}

デフォルトでインターネットアクセスを無効にし、特定のホストと IP だけを許可することもできます。

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };

export class MySandbox extends Sandbox {
	// default internet access to off unless overridden by 'allowedHosts' or outbound proxy
	enableInternet = false;

	// overrides enableInternet = false
	allowedHosts = ["allowed.com"];
}
import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };

export class MySandbox extends Sandbox {
	// default internet access to off unless overridden by 'allowedHosts' or outbound proxy
	enableInternet = false;

	// overrides enableInternet = false
	allowedHosts = ["allowed.com"];
}

アウトバウンドハンドラーを定義する

アウトバウンドハンドラーは、サンドボックスと同じマシンで動く、プログラム可能な egress プロキシです。すべての Workers バインディングにアクセスできます。

outbound で、すべてのアウトバウンド HTTP および HTTPS トラフィックを傍受します。

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };

export class MySandbox extends Sandbox {}

MySandbox.outbound = async (request, env, ctx) => {
	if (request.method !== "GET") {
		console.log(`Blocked ${request.method} to ${request.url}`);
		return new Response("Method Not Allowed", { status: 405 });
	}
	return fetch(request);
};
import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };

export class MySandbox extends Sandbox {}

MySandbox.outbound = async (
	request: Request,
	env: Env,
	ctx: OutboundHandlerContext,
) => {
	if (request.method !== "GET") {
		console.log(`Blocked ${request.method} to ${request.url}`);
		return new Response("Method Not Allowed", { status: 405 });
	}
	return fetch(request);
};

特定のドメイン名または IP アドレスをハンドラー関数に割り当てるには outboundByHost を使います。

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };

export class MySandbox extends Sandbox {}

MySandbox.outboundByHost = {
	"my.worker": async (request, env, ctx) => {
		// Run arbitrary Workers logic from this hostname
		return await someWorkersFunction(request.body);
	},
};
import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };

export class MySandbox extends Sandbox {}

MySandbox.outboundByHost = {
	"my.worker": async (
		request: Request,
		env: Env,
		ctx: OutboundHandlerContext,
	) => {
		// Run arbitrary Workers logic from this hostname
		return await someWorkersFunction(request.body);
	},
};

サンドボックスから http://my.worker への呼び出しはハンドラーを起動します。ハンドラーは Workers ランタイム内、サンドボックスの外で実行されます。

deniedHostsallowedHosts は、どのアウトバウンドハンドラーよりも先に評価されます。allowedHosts を使う場合は、outbound または outboundByHost を動かすホスト名をそこに含めてください。outboundByHost ハンドラーは、包括的な outbound ハンドラーより優先されます。

認証情報を安全に注入する

アウトバウンドハンドラーは Workers ランタイム(サンドボックスの外)で動くため、サンドボックス自身が見ないシークレットを保持できます。サンドボックスは平文の HTTP リクエストを送り、ハンドラーが認証情報を付けて上流サービスへ転送します。

export class MySandbox extends Sandbox {}

MySandbox.outboundByHost = {
	"github.com": (request, env, ctx) => {
		const requestWithAuth = new Request(request);
		requestWithAuth.headers.set("x-auth-token", env.SECRET);
		return fetch(requestWithAuth);
	},
};
export class MySandbox extends Sandbox {}

MySandbox.outboundByHost = {
	"github.com": (request: Request, env: Env, ctx: OutboundHandlerContext) => {
		const requestWithAuth = new Request(request);
		requestWithAuth.headers.set("x-auth-token", env.SECRET);
		return fetch(requestWithAuth);
	},
};

サンドボックス内のコードを完全には信頼できないエージェントワークロードで特に有用です。このパターンでは次のとおりです。

  • トークンはサンドボックスに露出しません。 シークレットは Worker の環境にあり、サンドボックスへは渡りません。
  • サンドボックス内でのトークンローテーションは不要です。 Worker の環境でシークレットをローテーションすれば、以降のリクエストはすぐに新しい値を使います。
  • ホスト単位およびインスタンス単位のルール。 outboundByHostctx.containerId を組み合わせて、認証情報や権限を特定のサンドボックスインスタンスに限定できます。

ここでは、ctx.containerId で KV からインスタンスごとのキーを取得します。

export class MySandbox extends Sandbox {}

MySandbox.outboundByHost = {
	"my-internal-vcs.dev": async (request, env, ctx) => {
		const authKey = await env.KEYS.get(ctx.containerId);

		const requestWithAuth = new Request(request);
		requestWithAuth.headers.set("x-auth-token", authKey);
		return fetch(requestWithAuth);
	},
};
export class MySandbox extends Sandbox {}

MySandbox.outboundByHost = {
	"my-internal-vcs.dev": async (
		request: Request,
		env: Env,
		ctx: OutboundHandlerContext,
	) => {
		const authKey = await env.KEYS.get(ctx.containerId);

		const requestWithAuth = new Request(request);
		requestWithAuth.headers.set("x-auth-token", authKey);
		return fetch(requestWithAuth);
	},
};

HTTPS トラフィック

サンドボックスはデフォルトで HTTPS トラフィックを傍受します。Sandbox クラスでは interceptHttpstrue です。

HTTPS 傍受が有効なとき、サンドボックス起動後に一時的な CA ファイルが /etc/cloudflare/certs/cloudflare-containers-ca.crt に作成されます。

Sandbox ランタイムは、ディストリビューションに関係なく、この CA を自動的に信頼するよう最善を尽くします。起動時に、主要な Linux 系列の一般的なシステム CA バンドル場所を確認し、一般的な CA 環境変数を設定します。Node.js、curl、Python の requests、Git などが証明書を自動的に信頼します。

非 HTTP トラフィック

アウトバウンドハンドラーが傍受するのは HTTP と HTTPS だけです。80443 以外のポートのトラフィックは、outboundoutboundByHost には回りません。

enableInternet = false を設定すると、そのトラフィックは拒否されます。例外は DNS クエリだけですが、送信先は Cloudflare の DNS サーバーに限られます。任意の DNS 送信先を使ったデータ持ち出しを防ぎます。

実行時にポリシーを変更する

outboundHandlers で名前付きハンドラーを定義し、setOutboundByHost() で実行時に特定ホストへ割り当てます。setOutboundHandler() でハンドラーをグローバルに適用することもできます。

実行時ポリシーは setOutboundByHosts()setAllowedHosts()setDeniedHosts()allowHost()denyHost()removeAllowedHost()removeDeniedHost() でも管理できます。

信頼できる Worker が認証情報を保持し、信頼できないサンドボックスには渡さない構成にできます。

import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };

export class MySandbox extends Sandbox {}

MySandbox.outboundHandlers = {
	authenticatedGithub: async (request, env, ctx) => {
		const githubToken = env.GITHUB_TOKEN;
		return authenticateGitHttpsRequest(request, githubToken, ctx.containerId);
	},
};
import { Sandbox, ContainerProxy } from "@cloudflare/sandbox";
export { ContainerProxy };

export class MySandbox extends Sandbox {}

MySandbox.outboundHandlers = {
	authenticatedGithub: async (
		request: Request,
		env: Env,
		ctx: OutboundHandlerContext,
	) => {
		const githubToken = env.GITHUB_TOKEN;
		return authenticateGitHttpsRequest(request, githubToken, ctx.containerId);
	},
};

Worker からプログラムでホストにハンドラーを適用します。

import { Sandbox, ContainerProxy, getSandbox } from "@cloudflare/sandbox";
export { ContainerProxy };

export default {
	async fetch(request, env) {
		const sandbox = getSandbox(env.Sandbox, "agent-session");

		// Give the sandbox access to github.com during setup
		await sandbox.setOutboundByHost("github.com", "authenticatedGithub");
		await sandbox.exec("node setup.js");

		// Remove access once setup is complete
		await sandbox.removeOutboundByHost("github.com");
	},
};
import { Sandbox, ContainerProxy, getSandbox } from "@cloudflare/sandbox";
export { ContainerProxy };

export default {
	async fetch(request: Request, env: Env) {
		const sandbox = getSandbox(env.Sandbox, "agent-session");

		// Give the sandbox access to github.com during setup
		await sandbox.setOutboundByHost("github.com", "authenticatedGithub");
		await sandbox.exec("node setup.js");

		// Remove access once setup is complete
		await sandbox.removeOutboundByHost("github.com");
	},
};

ハンドラーの優先順位

リクエストは次の順で評価されます。

  1. 最初に deniedHosts を確認します。一致するホストまたは IP は直ちに拒否されます。
  2. 次に allowedHosts を確認します。設定されている場合、リストにないホストまたは IP は拒否されます。一致するホストはアウトバウンドハンドラーへ進むか、ハンドラーがなければパブリックインターネットへ出ます。
  3. setOutboundByHost() で設定したインスタンス単位のルールは、クラス単位の outboundByHost ルールより先に確認されます。
  4. ホスト単位のハンドラーは包括的なハンドラーより常に優先されるため、outboundByHostoutbound より先に動きます。
  5. setOutboundHandler() で設定したインスタンス単位のハンドラーは、クラス単位の outbound ハンドラーより先に確認されます。
  6. ハンドラーが一致しない場合でも、allowedHosts に一致した、または enableInternet = true のときは、リクエストはパブリックインターネットへ出られます。それ以外は拒否されます。

ローカル開発

wrangler dev はアウトバウンド傍受に対応しています。サンドボックスのネットワーク名前空間内でサイドカープロセスが起動します。一致するトラフィックをローカルの Workerd インスタンスへ回す TPROXY ルールを適用し、本番と同じ動きにします。

関連リソース

役に立ちましたか?