INTEGRITY Документация

Обработка исходящего трафика

Исходящие обработчики позволяют перехватывать и изменять HTTP-трафик из песочницы с помощью доверенного кода.

Используйте их, чтобы:

Блокируйте исходящий трафик

Используйте 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;
}

Когда enableInternet это false, только трафик, который вы явно разрешите далее на этой странице через allowedHosts или исходящие обработчики могут покинуть sandbox. Только порты 80, 443, и DNS доступны, а DNS-запросы используют DNS-серверы Cloudflare.

Блокируйте или разрешайте трафик по хосту

Исходящий трафик можно фильтровать с помощью allowedHosts и deniedHosts свойства класса Sandbox.

Когда allowedHosts задан, он становится белым списком с запретом по умолчанию. Любой хост или IP, не входящий в список, блокируется, и только совпадающие адреса назначения могут получить доступ к outbound или outboundByHost обработчики.

allowedHosts и deniedHosts также поддерживают простые glob-шаблоны, где * соответствует любой последовательности символов.

По умолчанию Sandbox разрешает доступ в интернет, и вы можете задать deniedHosts чтобы запретить доступ к определённым хостам или IP-адресам:

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"];
}

Определите обработчики исходящих запросов

Исходящие обработчики представляют собой программируемые прокси для исходящего трафика, которые выполняются на той же машине, что и песочница. Они имеют доступ ко всем привязкам 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);
};

Используйте outboundByHost для сопоставления конкретных доменных имён или IP-адресов с функциями-обработчиками:

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, вне сандбокса.

deniedHosts и allowedHosts вычисляются раньше любого outbound-обработчика. Если вы используете allowedHosts, укажите там имя хоста для outbound или outboundByHost для запуска. outboundByHost обработчики имеют приоритет над catch-all 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);
	},
};

Это особенно полезно для агентных нагрузок, где нельзя полностью доверять коду, выполняемому в песочнице. При таком подходе:

Здесь 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-трафик: interceptHttps имеет значение true в классе Sandbox.

Когда перехват HTTPS активен, временный файл CA создаётся по пути /etc/cloudflare/certs/cloudflare-containers-ca.crt после запуска песочницы.

Среда выполнения Sandbox старается автоматически довериться этому CA независимо от дистрибутива. При запуске она проверяет стандартные расположения системного набора сертификатов CA для основных семейств Linux и настраивает стандартные переменные окружения CA, чтобы среды выполнения вроде Node.js, curl, Python requests, и Git автоматически доверяют этому сертификату.

Трафик не по HTTP

Исходящие обработчики перехватывают только HTTP- и HTTPS-трафик. Трафик на портах, отличных от 80 и 443 никогда не направляется через outbound или outboundByHost.

Если вы зададите enableInternet = false, такой трафик блокируется. Исключение составляют DNS-запросы, но они направляются только на DNS-серверы Cloudflare. Это исключает использование произвольных 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. Обработчики для конкретного хоста всегда имеют приоритет над catch-all обработчиками, поэтому outboundByHost выполняется перед outbound.
  5. Обработчики уровня инстанса, заданные с помощью setOutboundHandler() проверяются раньше, чем на уровне класса outbound обработчик.
  6. Если ни один обработчик не подошёл, запрос всё равно может выйти в публичный интернет, если он соответствовал allowedHosts или enableInternet = true. В противном случае запрос отклоняется.

Локальная разработка

wrangler dev поддерживает перехват исходящих соединений. Внутри сетевого пространства имен sandbox запускается sidecar-процесс. Он применяет TPROXY правила для маршрутизации подходящего трафика к локальному экземпляру Workerd, повторяя поведение продакшена.