← Dynamic Workers / dynamic-workers / usage
Контроль исходящего трафика
Когда вы выполняете непроверенный или сгенерированный ИИ код в dynamic Worker, необходимо контролировать, к чему он может получить доступ в сети. Возможно, вам потребуется:
- заблокировать весь исходящий доступ, чтобы dynamic Worker мог использовать только привязки который вы ему передаёте
- ограничивать исходящие запросы определённым набором разрешённых адресов назначения
- добавлять учётные данные в исходящие запросы, не раскрывая секреты самому dynamic Worker
- регистрировать или проверять каждый исходящий запрос в целях наблюдаемости
globalOutbound параметр в WorkerCode объект, возвращаемый get() или передан в load() управляет всем этим. Он перехватывает каждый fetch() и connect() вызов, который делает динамический Worker.
Блокировка всего исходящего доступа
Задайте globalOutbound к null для полной изоляции динамического Worker от сети:
return {
mainModule: "index.js",
modules: { "index.js": code },
globalOutbound: null,
};Это приводит к тому, что любой fetch() или connect() запрос от динамического Worker, чтобы вызвать исключение.
В этом режиме вы всё равно можете предоставить Dynamic Worker прямой доступ к определённым ресурсам и сервисам с помощью привязки. Это самый чистый и безопасный способ спроектировать изолированную среду выполнения: сначала заблокировать доступ в интернет, а затем осознанно предоставить конкретные возможности через привязки.
Тем не менее, если вам нужна совместимость с существующими библиотеками HTTP-клиентов, работающими непосредственно внутри песочницы Dynamic Worker, то блокирующий fetch() может оказаться невозможным, и вместо этого вы можете предпочесть перехватывать запросы.
Перехват исходящих запросов
Чтобы перехватывать исходящие запросы, определите WorkerEntrypoint класс в Worker-загрузчике, который выступает шлюзом. Каждый fetch() и connect() вызов, который делает динамический Worker, проходит через этот шлюз вместо прямого обращения к сети. Передайте шлюз динамическому Worker с помощью globalOutbound и ctx.exports:
import { WorkerEntrypoint } from "cloudflare:workers";
export class HttpGateway extends WorkerEntrypoint {
async fetch(request) {
// Every outbound fetch() from the dynamic Worker arrives here.
// Inspect, modify, block, or forward the request.
return fetch(request);
}
}
export default {
async fetch(request, env, ctx) {
const worker = env.LOADER.get("my-worker", async () => {
return {
compatibilityDate: "$today",
mainModule: "index.js",
modules: { "index.js": code },
// Pass the gateway as a service binding.
// The dynamic Worker's fetch() and connect() calls
// are routed through HttpGateway instead of going
// to the network directly.
globalOutbound: ctx.exports.HttpGateway(),
};
});
return worker.getEntrypoint().fetch(request);
},
};Отсюда вы можете добавить в шлюз любую логику, например ограничение адресатов, внедрение учётных данных или логирование запросов.
Внедрение учётных данных
Распространенный прием: добавлять учетные данные к исходящим запросам так, чтобы dynamic Worker никогда не видел секрет. Аналогично пользовательские привязки, вы можете использовать ctx.props для передачи контекста шлюзу в разрезе арендатора или запроса.
Динамический Worker вызывает fetch() как обычно. HttpGateway перехватывает запрос, добавляет токен из окружения Worker-загрузчика и пересылает его. Динамический Worker никогда не получает доступ к API_TOKEN.
import { WorkerEntrypoint } from "cloudflare:workers";
export class HttpGateway extends WorkerEntrypoint {
async fetch(request) {
let url = new URL(request.url);
const headers = new Headers(request.headers);
// For requests to api.example.com, inject credentials.
if (url.hostname === "api.example.com") {
headers.set("Authorization", `Bearer ${this.env.API_TOKEN}`);
headers.set("X-Tenant-Id", this.ctx.props.tenantId);
}
return fetch(request, { headers });
}
}
export default {
async fetch(request, env, ctx) {
const tenantId = getTenantFromRequest(request);
const worker = env.LOADER.get(`tenant:${tenantId}`, async () => {
return {
mainModule: "index.js",
modules: {
"index.js": `
export default {
async fetch() {
const resp = await fetch("https://api.example.com/data");
return new Response(await resp.text());
},
};
`,
},
globalOutbound: ctx.exports.HttpGateway({
props: { tenantId },
}),
};
});
return worker.getEntrypoint().fetch(request);
},
};