送信ハンドラーを使うと、信頼できるコードで Container からの HTTP トラフィックを傍受して変更できます。
次の用途に使えます。
- 特定のオリジン宛先を許可または拒否する
- 認可ヘッダーやトークンを安全に注入する
- トラフィックを透過的に再ルーティングする
- 送信トラフィックにカスタムポリシーを追加する(特定の HTTP リクエストを拒否するなど)
- KV、R2、Durable Objects などの Workers バインディングに接続する
enableInternet = false を使い、デフォルトでパブリックインターネットへのアクセスをブロックします。
import { Container } from "@cloudflare/containers";
export class MyContainer extends Container {
enableInternet = false;
}enableInternet が false のとき、このページの後半で allowedHosts または送信ハンドラーによって明示的に許可したトラフィックだけが Container から出られます。利用できるのはポート 80、443、および DNS だけで、DNS クエリは Cloudflare の DNS サーバーを使います。
Container クラスの allowedHosts と deniedHosts プロパティで、送信トラフィックをフィルターできます。
allowedHosts を設定すると、デフォルト拒否の許可リストになります。リストにないホストや IP は拒否され、一致する宛先だけが outbound または outboundByHost ハンドラーに到達できます。
allowedHosts と deniedHosts は、単純なグロブパターンもサポートします。* は任意の文字シーケンスに一致します。
デフォルトでは Container はインターネットアクセスを許可します。特定のホストや IP を拒否するには deniedHosts を設定します。
import { Container, ContainerProxy } from "@cloudflare/containers";
export { ContainerProxy };
export class MyContainer extends Container {
// Make sure the container trusts /etc/cloudflare/certs/cloudflare-containers-ca.crt
interceptHttps = true;
deniedHosts = ["some-nefarious-website.com", "141.101.64.0/18"];
}デフォルトでインターネットアクセスを無効にし、特定のホストと IP だけを許可することもできます。
import { Container, ContainerProxy } from "@cloudflare/containers";
export { ContainerProxy };
export class MyContainer extends Container {
// Make sure the container trusts /etc/cloudflare/certs/cloudflare-containers-ca.crt
interceptHttps = true;
// default internet access to off unless overridden by 'allowedHosts' or outbound proxy
enableInternet = false;
// overrides enableInternet = false
allowedHosts = ["allowed.com"];
}送信ハンドラーは、Container と同じマシンで動く、プログラム可能な送信プロキシです。すべての Workers バインディングにアクセスできます。
outbound を使い、すべての HTTP および HTTPS トラフィックを傍受します。
import { Container, ContainerProxy } from "@cloudflare/containers";
export { ContainerProxy };
export class MyContainer extends Container {
interceptHttps = true;
}
MyContainer.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);
};outboundByHost を使い、特定のドメイン名または IP アドレスをプロキシ関数へ対応付けます。
import { Container, ContainerProxy } from "@cloudflare/containers";
export { ContainerProxy };
export class MyContainer extends Container {
interceptHttps = true;
}
MyContainer.outboundByHost = {
"my.worker": async (request, env, ctx) => {
// Run arbitrary Workers logic from this hostname
return await someWorkersFunction(request.body);
},
};Container から http://my.worker への呼び出しはハンドラーを起動します。ハンドラーは Workers ランタイム内、Container サンドボックスの外で実行されます。
deniedHosts と allowedHosts は、どの送信ハンドラーよりも先に評価されます。allowedHosts を使う場合は、outbound または outboundByHost が動くように、そのホスト名をリストに含めてください。outboundByHost ハンドラーは、キャッチオールの outbound ハンドラーより優先されます。
送信ハンドラーは Workers ランタイム(Container サンドボックスの外)で動くため、Container 自身には見えないシークレットを保持できます。Container は平文の HTTP リクエストを送り、ハンドラーが認証情報を付けてから上流サービスへ転送します。
export class MyContainer extends Container {
// Make sure the container trusts /etc/cloudflare/certs/cloudflare-containers-ca.crt
interceptHttps = true;
}
MyContainer.outboundByHost = {
"github.com": (request, env, ctx) => {
const requestWithAuth = new Request(request);
requestWithAuth.headers.set("x-auth-token", env.SECRET);
return fetch(requestWithAuth);
},
};これは、Container 内で動くコードを完全には信頼できないエージェント型ワークロードで特に役立ちます。このパターンでは次のとおりです。
- トークンは Container に公開されません。 シークレットは Worker の環境にあり、サンドボックスへ渡されません。
- Container 内でトークンをローテーションする必要はありません。 Worker の環境でシークレットをローテーションすると、以降のリクエストはすぐに新しい値を使います。
- ホスト単位およびインスタンス単位のルール。
outboundByHostとctx.containerIdを組み合わせて、認証情報や権限を特定の Container インスタンスに限定できます。
ここでは、ctx.containerId で KV からインスタンス単位のキーを取得します。
export class MyContainer extends Container {
// Make sure the container trusts /etc/cloudflare/certs/cloudflare-containers-ca.crt
interceptHttps = true;
}
MyContainer.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);
},
};デフォルトでは、HTTPS トラフィックは送信ハンドラーで傍受されません。オプトインするには interceptHttps 属性を設定します。
export class MyContainer extends Container {
// Make sure the container trusts /etc/cloudflare/certs/cloudflare-containers-ca.crt
interceptHttps = true;
}
MyContainer.outbound = (req, env, ctx) => {
// All HTTP(S) requests will trigger this hook.
return fetch(req);
};これは、信頼できないトラフィックを Container インスタンスから Workers へリダイレクトし、フィルタリングと変更を行う Sandbox のようなサービスで役立ちます。
HTTPS 傍受が有効なとき、Container の起動時に一時的な CA ファイルが /etc/cloudflare/certs/cloudflare-containers-ca.crt に作成されます。CA が注入されるのは、interceptHttps = true を設定し、かつ outbound または outboundByHost ハンドラーを定義した場合だけです。
HTTPS 傍受を動かすには、CA ファイルを信頼する必要があります。CA はエフェメラルでランタイムにだけ存在するため、docker build 中にイメージへ焼き込まないでください。代わりに、ディストリビューションの信頼ストアへコピーし、アプリケーション起動前に Container の entrypoint から信頼ストアを更新します。
ベースイメージに信頼ストア用のツールが含まれていない場合は、先にイメージへディストリビューションの ca-certificates パッケージをインストールします。
import { Container, ContainerProxy } from "@cloudflare/containers";
export { ContainerProxy };
export class MyContainer extends Container {
interceptHttps = true;
entrypoint = [
"sh",
"-lc",
[
"cp /etc/cloudflare/certs/cloudflare-containers-ca.crt /usr/local/share/ca-certificates/cloudflare-containers-ca.crt",
"update-ca-certificates",
"exec node server.js",
].join(" && "),
];
}import { Container, ContainerProxy } from "@cloudflare/containers";
export { ContainerProxy };
export class MyContainer extends Container {
interceptHttps = true;
entrypoint = [
"sh",
"-lc",
[
"cp /etc/cloudflare/certs/cloudflare-containers-ca.crt /usr/local/share/ca-certificates/cloudflare-containers-ca.crt",
"update-ca-certificates",
"exec node server.js",
].join(" && "),
];
}import { Container, ContainerProxy } from "@cloudflare/containers";
export { ContainerProxy };
export class MyContainer extends Container {
interceptHttps = true;
entrypoint = [
"sh",
"-lc",
[
"cp /etc/cloudflare/certs/cloudflare-containers-ca.crt /etc/pki/ca-trust/source/anchors/cloudflare-containers-ca.crt",
"update-ca-trust",
"exec node server.js",
].join(" && "),
];
}import { Container, ContainerProxy } from "@cloudflare/containers";
export { ContainerProxy };
export class MyContainer extends Container {
interceptHttps = true;
entrypoint = [
"sh",
"-lc",
[
"cp /etc/cloudflare/certs/cloudflare-containers-ca.crt /etc/ca-certificates/trust-source/anchors/cloudflare-containers-ca.crt",
"trust extract-compat",
"exec node server.js",
].join(" && "),
];
}node server.js は、アプリケーションを起動するコマンドに置き換えてください。
ほとんどのランタイムは、システムのルートストア経由で CA を自動的に信頼します。ランタイムが独自の CA バンドルを使う場合は、NODE_EXTRA_CA_CERTS や REQUESTS_CA_BUNDLE などで /etc/cloudflare/certs/cloudflare-containers-ca.crt を直接指定します。
送信ハンドラーが傍受するのは HTTP と HTTPS トラフィックだけです。ポート 80 と 443 以外のトラフィックは、outbound や outboundByHost を通りません。
enableInternet = false を設定すると、そのトラフィックは拒否されます。例外は DNS クエリだけですが、宛先は Cloudflare の DNS サーバーに限られます。任意の DNS 宛先を使ったデータ持ち出しを防ぐためです。
outboundHandlers で名前付きハンドラーを定義し、setOutboundByHost() で実行時に特定のホストへ割り当てます。setOutboundHandler() でハンドラーをグローバルに適用することもできます。
実行時ポリシーは、setOutboundByHosts()、setAllowedHosts()、setDeniedHosts()、allowHost()、denyHost()、removeAllowedHost()、removeDeniedHost() でも管理できます。
これにより、信頼できる Worker が認証情報を保持し、信頼できない Container には公開しません。
export class MyContainer extends Container {
// Make sure the container trusts /etc/cloudflare/certs/cloudflare-containers-ca.crt
interceptHttps = true;
}
MyContainer.outboundHandlers = {
authenticatedGithub: async (request, env, ctx) => {
const githubToken = env.GITHUB_TOKEN;
return authenticateGitHttpsRequest(request, githubToken, ctx.containerId);
},
};Worker からプログラムでホストにハンドラーを適用します。
async setUpContainer(req, env) {
const container = await env.MY_CONTAINER.getByName("my-instance");
// Give the container access to github.com on a specific host during setup
await container.setOutboundByHost("github.com", "authenticatedGithub");
// do something with github.com on your container...
}
async removeAccessToGithub(req, env) {
const container = await env.MY_CONTAINER.getByName("my-instance");
// Remove access to Github
await container.removeOutboundByHost("github.com");
}リクエストは次の順で評価されます。
- 最初に
deniedHostsを確認します。一致するホストまたは IP は直ちに拒否されます。 - 次に
allowedHostsを確認します。設定されている場合、リストにないホストまたは IP は拒否されます。一致するホストは送信ハンドラーへ進むか、ハンドラーがなければパブリックインターネットへ送信されます。 setOutboundByHost()で設定したインスタンス単位のルールは、クラス単位のoutboundByHostルールより先に確認されます。- ホスト単位のハンドラーは常にキャッチオールハンドラーより優先されるため、
outboundByHostはoutboundより先に実行されます。 setOutboundHandler()で設定したインスタンス単位のハンドラーは、クラス単位のoutboundハンドラーより先に確認されます。- どのハンドラーにも一致しない場合でも、
allowedHostsに一致したかenableInternet = trueなら、リクエストはパブリックインターネットへ送信できます。それ以外は拒否されます。
ctx.container で送信傍受を直接設定するには、特定のホスト名グロブ、IP、または CIDR 範囲に interceptOutboundHttp を使うか、すべてのトラフィックに interceptAllOutboundHttp を使います。どちらも WorkerEntrypoint を受け取ります。
import { WorkerEntrypoint } from "cloudflare:workers";
export class MyOutboundWorker extends WorkerEntrypoint {
fetch(request) {
// Inspect, modify, or deny the request before passing it on
return fetch(request);
}
}
// Inside your Container DurableObject
this.ctx.container.start({ enableInternet: false });
const worker = this.ctx.exports.MyOutboundWorker({ props: {} });
await this.ctx.container.interceptAllOutboundHttp(worker);これらのメソッドは、Container の起動前でも起動後でも、接続が開いている最中でも呼び出せます。進行中の TCP 接続は新しいハンドラーを自動的に取り込みます。接続は切断されません。
// Intercept a specific CIDR range
await this.ctx.container.interceptOutboundHttp("203.0.113.0/24", worker);
// Intercept by hostname
this.ctx.container.interceptOutboundHttp("foo.com", worker);
// Update the handler while the container is running
const updated = this.ctx.exports.MyOutboundWorker({
props: { phase: "post-install" },
});
await this.ctx.container.interceptOutboundHttp("203.0.113.0/24", updated);HTTPS では、interceptOutboundHttps は interceptOutboundHttp と同じように動作します。
// Intercept a specific hostname
this.ctx.container.interceptOutboundHttps("foo.com", worker);
// Intercept all traffic
this.ctx.container.interceptOutboundHttps("*", worker);Container クラスは、上記の関数を使うときにこれらのメソッドを自動的に呼び出します。クラスがカバーしないケースでは、直接呼び出すこともできます。
wrangler dev は送信傍受をサポートします。Container のネットワーク名前空間内でサイドカープロセスが起動します。一致するトラフィックをローカルの Workerd インスタンスへルーティングする TPROXY ルールを適用し、本番の動作を再現します。
- Workers バインディングに接続する — Container から KV、R2、Durable Objects、その他のバインディングへアクセスします
- 送信トラフィックを制御する(Sandboxes) — 送信ハンドラー向けの Sandbox SDK API です
- 環境変数とシークレット — シークレットと環境変数を設定します
- Durable Object インターフェイス —
ctx.containerの API リファレンス全体です