← Containers / containers / platform-details
Обработка исходящего трафика
Outbound handlers позволяют перехватывать и изменять HTTP-трафик от контейнера с помощью доверенного кода.
Используйте их, чтобы:
- Разрешайте или запрещайте доступ к определённым адресам назначения
- Безопасно внедряйте заголовки авторизации или токены
- Прозрачно перенаправлять трафик
- Добавьте собственную политику для исходящего трафика (например, запрет определённых HTTP-запросов)
- Подключитесь к привязкам Workers например KV, R2 и Durable Objects
Блокируйте исходящий трафик
Используйте enableInternet = false чтобы по умолчанию блокировать доступ к публичному интернету:
import { Container } from "@cloudflare/containers";
export class MyContainer extends Container {
enableInternet = false;
}Когда enableInternet это false, только трафик, который вы явно разрешите далее на этой странице через allowedHosts или исходящие обработчики могут покидать контейнер. Только порты 80, 443, и DNS доступны, а DNS-запросы используют DNS-серверы Cloudflare.
Блокируйте или разрешайте трафик по хосту
Исходящий трафик можно фильтровать с помощью allowedHosts и deniedHosts свойства класса Container.
Когда allowedHosts задан, он становится белым списком с запретом по умолчанию. Любой хост или IP, не входящий в список, блокируется, и только совпадающие адреса назначения могут получить доступ к outbound или outboundByHost обработчики.
allowedHosts и deniedHosts также поддерживают простые glob-шаблоны, где * соответствует любой последовательности символов.
По умолчанию Container разрешает доступ в интернет, и вы можете задать deniedHosts для
запрета конкретных хостов или 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;
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"];
}Определите обработчики исходящих запросов
Outbound handlers представляют собой программируемые egress-прокси, которые работают на той же машине, что и контейнер. У них есть доступ ко всем привязкам 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);
},
};Обращения к http://my.worker из контейнера вызывают обработчик, который выполняется внутри среды выполнения Workers, за пределами песочницы контейнера.
deniedHosts и allowedHosts вычисляются раньше любого outbound-обработчика. Если вы используете allowedHosts, укажите там имя хоста для outbound или outboundByHost для запуска. outboundByHost обработчики имеют приоритет над catch-all outbound обработчики.
Безопасно внедряйте учётные данные
Обработчики исходящих соединений выполняются в среде выполнения Workers, вне песочницы контейнера, поэтому они могут хранить секреты, которые сам контейнер никогда не увидит. Контейнер отправляет обычный 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);
},
};Это особенно полезно для агентных нагрузок, где нельзя полностью доверять коду, выполняющемуся внутри контейнера. При таком подходе:
- Токен не передаётся в контейнер. Секрет хранится в окружении Worker и никогда не передаётся в sandbox.
- Ротация токена внутри контейнера не выполняется. Обновите секрет в окружении своего Worker, и каждый следующий запрос сразу получит новое значение.
- Правила для отдельных хостов и экземпляров. Комбинируйте
outboundByHostсctx.containerIdчтобы ограничить область действия учётных данных или прав конкретным экземпляром контейнера.
Здесь 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-трафик
По умолчанию обработчики исходящих соединений не перехватывают 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);
};Это полезно для сервисов вроде песочниц, которые перенаправляют ненадёжный трафик от экземпляра контейнера в Workers для фильтрации и изменения.
Когда перехват HTTPS активен, временный файл CA будет создан по пути /etc/cloudflare/certs/cloudflare-containers-ca.crt после запуска контейнера. Сертификат CA внедряется только в том случае, если вы одновременно задали interceptHttps = true и определите outbound или outboundByHost обработчик.
Доверие сертификату CA
Чтобы перехват HTTPS работал, необходимо добавить файл CA в доверенные. CA является временным и существует только во время выполнения, поэтому не пытайтесь встраивать его в образ во время docker build. Вместо этого скопируйте его в хранилище доверенных сертификатов вашего дистрибутива и обновите это хранилище из контейнера entrypoint перед запуском приложения.
Если базовый образ ещё не включает инструменты для работы с trust-store, установите соответствующий пакет дистрибутива 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-сертификатов, укажите его на /etc/cloudflare/certs/cloudflare-containers-ca.crt напрямую, например с помощью NODE_EXTRA_CA_CERTS или REQUESTS_CA_BUNDLE.
Трафик не по HTTP
Исходящие обработчики перехватывают только HTTP- и HTTPS-трафик. Трафик на портах, отличных от 80 и 443 никогда не направляется через outbound или outboundByHost.
Если вы зададите enableInternet = false, такой трафик блокируется. Исключение составляют DNS-запросы, но они направляются только на DNS-серверы Cloudflare. Это исключает использование произвольных DNS-адресов для эксфильтрации данных.
Изменение политик во время выполнения
Используйте outboundHandlers чтобы определить именованные обработчики, а затем назначить их конкретным хостам во время выполнения с помощью setOutboundByHost(). Обработчик также можно применить глобально с помощью setOutboundHandler().
Вы также можете управлять политикой выполнения с помощью setOutboundByHosts(), setAllowedHosts(), setDeniedHosts(), allowHost(), denyHost(), removeAllowedHost(), а также removeDeniedHost().
Это позволяет доверенному Worker хранить учётные данные, не раскрывая их ненадёжному контейнеру:
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правил. - Обработчики для конкретного хоста всегда имеют приоритет над catch-all обработчиками, поэтому
outboundByHostвыполняется передoutbound. - Обработчики уровня инстанса, заданные с помощью
setOutboundHandler()проверяются раньше, чем на уровне классаoutboundобработчик. - Если ни один обработчик не подошёл, запрос всё равно может выйти в публичный интернет, если он соответствовал
allowedHostsилиenableInternet = true. В противном случае запрос отклоняется.
Низкоуровневый API
Чтобы настроить перехват исходящих запросов напрямую в ctx.container, используйте interceptOutboundHttp для конкретного glob-шаблона имени хоста, IP-адреса или диапазона CIDR,
либо 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);Эти методы можно вызывать до или после запуска контейнера и даже при открытых соединениях. Уже установленные 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 поддерживает перехват исходящего трафика. Внутри сетевого пространства имён контейнера запускается сайдкар-процесс, который применяет TPROXY правила для маршрутизации подходящего трафика к локальному экземпляру Workerd, повторяя поведение продакшена.
Дополнительные материалы
- Подключитесь к привязкам Workers : Доступ к KV, R2, Durable Objects и другим привязкам из контейнера
- Управление исходящим трафиком (Sandboxes) : Sandbox SDK API для исходящих обработчиков
- Переменные окружения и секреты : настройка секретов и переменных окружения
- интерфейс Durable Object : Полный
ctx.containerсправочник API