INTEGRITY Dokumentace

Zpracování odchozího provozu

Odchozí handlery umožňují pomocí důvěryhodného kódu zachytávat a upravovat HTTP provoz z kontejneru.

Použijte je k:

Blokujte odchozí provoz

Použijte enableInternet = false pro výchozí blokování přístupu z veřejného internetu:

import { Container } from "@cloudflare/containers";

export class MyContainer extends Container {
	enableInternet = false;
}

Když enableInternet je false, pouze provoz, který na této stránce dále explicitně povolíte prostřednictvím allowedHosts nebo obslužné rutiny odchozího provozu mohou kontejner opustit. Pouze porty 80, 443, a DNS jsou dostupné, přičemž DNS dotazy používají DNS servery Cloudflare.

Blokujte nebo povolujte provoz podle hostitele

Odchozí provoz můžete filtrovat pomocí allowedHosts a deniedHosts vlastnosti třídy Container.

Když allowedHosts je nastaven, stane se allowlistem s výchozím zamítnutím. Každý host nebo IP adresa mimo seznam je zamítnuta a spojit se lze jen s outbound nebo outboundByHost handlery.

allowedHosts a deniedHosts podporují také jednoduché glob vzory, kde * odpovídá libovolné posloupnosti znaků.

Ve výchozím nastavení Container povoluje přístup k internetu a můžete nastavit deniedHosts k zakázání konkrétních hostitelů nebo IP adres:

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

Přístup k internetu můžete také ve výchozím nastavení zakázat a povolit jen konkrétní hostitele a IP adresy:

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

Definujte obslužné rutiny pro odchozí provoz

Odchozí handlery jsou programovatelné proxy servery pro odchozí provoz, které běží na stejném počítači jako kontejner. Mají přístup ke všem vazbám Workers.

Použijte outbound k zachycení veškerého provozu HTTP a 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);
};

Použijte outboundByHost k namapování konkrétních názvů domén nebo IP adres na proxy funkce:

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);
	},
};

Volání na http://my.worker z kontejneru vyvolávají handler, který běží uvnitř Workers runtime, mimo sandbox kontejneru.

deniedHosts a allowedHosts se vyhodnocují před jakýmkoli outbound handlerem. Pokud používáte allowedHosts, uveďte tam hostname buď pro outbound nebo outboundByHost ke spuštění. outboundByHost handlery mají přednost před catch-all outbound handlery.

Bezpečně vkládejte přihlašovací údaje

Protože odchozí handlery běží v runtime Workers, mimo sandbox kontejneru, mohou obsahovat tajné údaje, ke kterým se samotný kontejner nikdy nedostane. Kontejner odešle běžný HTTP požadavek a handler k němu před předáním nadřazené službě připojí přihlašovací údaje.

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);
	},
};

To je užitečné zejména pro agentní úlohy, kde nemůžete kódu spuštěnému uvnitř kontejneru plně důvěřovat. Při tomto přístupu:

Zde ctx.containerId vyhledá klíč pro danou instanci v 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);
	},
};

Provoz HTTPS

Ve výchozím nastavení odchozí handlery provoz HTTPS nezachytávají. Pokud to chcete povolit, musíte nastavit interceptHttps atribut.

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);
};

To se hodí pro služby podobné sandboxu, které přesměrovávají nedůvěryhodný provoz z instance kontejneru na Workers kvůli filtrování a úpravám.

Když je aktivní zachytávání HTTPS, vytvoří se dočasný soubor CA na /etc/cloudflare/certs/cloudflare-containers-ca.crt jakmile se váš kontejner spustí. CA se vloží pouze v případě, že současně nastavíte interceptHttps = true a definujte outbound nebo outboundByHost handler.

Důvěřovat certifikátu CA

Aby fungovalo zachytávání HTTPS, musíte důvěřovat souboru CA. CA je dočasná a existuje pouze za běhu, proto se ji nesnažte zapéct do obrazu během docker build. Místo toho jej zkopírujte do úložiště důvěryhodných certifikátů vaší distribuce a aktualizujte toto úložiště z kontejneru entrypoint před spuštěním vaší aplikace.

Pokud váš základní obraz ještě neobsahuje nástroje pro trust store, nainstalujte ca-certificates balíček do vašeho image nejdříve.

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(" && "),
	];
}

Nahraďte node server.js s příkazem, který spouští vaši aplikaci.

Většina runtime prostředí pak automaticky důvěřuje CA prostřednictvím systémového úložiště kořenových certifikátů. Pokud vaše runtime prostředí používá vlastní sadu CA certifikátů, nasměrujte ji na /etc/cloudflare/certs/cloudflare-containers-ca.crt přímo, například pomocí NODE_EXTRA_CA_CERTS nebo REQUESTS_CA_BUNDLE.

Provoz jiný než HTTP

Outbound handlery zachytávají pouze provoz HTTP a HTTPS. Provoz na portech jiných než 80 a 443 se nikdy nesměruje přes outbound nebo outboundByHost.

Pokud nastavíte enableInternet = false, takový provoz je zamítnut. Jedinou výjimkou jsou dotazy DNS, které však směřují pouze na servery DNS Cloudflare. Tím se zabraňuje zneužití libovolných cílů DNS k exfiltraci dat.

Měňte zásady za běhu

Použijte outboundHandlers pro definování pojmenovaných handlerů a jejich následné přiřazení konkrétním hostitelům za běhu pomocí setOutboundByHost(). Handler můžete také použít globálně pomocí setOutboundHandler().

Zásady runtime můžete také spravovat pomocí setOutboundByHosts(), setAllowedHosts(), setDeniedHosts(), allowHost(), denyHost(), removeAllowedHost(), a removeDeniedHost().

Díky tomu může důvěryhodný Worker držet přihlašovací údaje, aniž by je vystavoval nedůvěryhodnému kontejneru:

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);
	},
};

Handlery aplikujte na hosty programově přímo z Workeru:

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

Priorita handlerů

Požadavky se vyhodnocují v tomto pořadí:

  1. deniedHosts se kontroluje jako první. Odpovídající hosty nebo IP adresy jsou okamžitě zamítnuty.
  2. allowedHosts se kontroluje jako další. Pokud je nastaven, každý host nebo IP adresa, které nejsou na seznamu, jsou zamítnuty. Odpovídající hosty pokračují k outbound handlerům, nebo pokud žádný handler není nastaven, do veřejného internetu.
  3. Pravidla na úrovni instance nastavená pomocí setOutboundByHost() se kontrolují před úrovní třídy outboundByHost pravidla.
  4. Obslužné rutiny pro jednotlivé hostitele mají vždy přednost před univerzálními obslužnými rutinami, takže outboundByHost se spustí před outbound.
  5. Obslužné rutiny na úrovni instance nastavené pomocí setOutboundHandler() se kontrolují před danou úrovní třídy outbound handler.
  6. Pokud neodpovídá žádný handler, požadavek může přesto opustit síť do veřejného internetu, pokud odpovídal allowedHosts nebo enableInternet = true. V opačném případě je operace zamítnuta.

Nízkoúrovňové API

Pro konfiguraci zachytávání odchozího provozu přímo na ctx.container, použijte interceptOutboundHttp pro konkrétní glob hostname, IP nebo rozsah CIDR, nebo interceptAllOutboundHttp pro veškerý provoz. Oba přijímají 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);

Tyto metody můžete volat před spuštěním kontejneru nebo po něm, a to i v době, kdy jsou spojení otevřená. Právě probíhající TCP spojení automaticky přejmou nový handler, žádná spojení se přitom nepřeruší.

// 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);

Pro HTTPS, interceptOutboundHttps funguje stejně jako interceptOutboundHttp.

// Intercept a specific hostname
this.ctx.container.interceptOutboundHttps("foo.com", worker);

// Intercept all traffic
this.ctx.container.interceptOutboundHttps("*", worker);

Container třída tyto metody volá automaticky, když použijete výše uvedené funkce. Můžete je také zavolat přímo pro případy, které tato třída nepokrývá.

Lokální vývoj

wrangler dev podporuje zachytávání odchozího provozu. Uvnitř síťového jmenného prostoru kontejneru se spustí sidecar proces, který aplikuje TPROXY pravidla pro směrování odpovídajícího provozu na lokální instanci Workerd, což odpovídá chování v produkci.