Blog

Kteří klienti skutečně potřebují vlastní VM? Vrstvený plán izolace Dockeru

VM pro každého klienta je přehnané. Zde je návod, jak se rozhodnout, kolik izolace každý tenant potřebuje – a automatizovat toto rozhodnutí.

Shrnutí

Agentury často zpanikaří, když se klient zeptá, jak skutečně izolovaná jsou jeho data od ostatních tenantů. Namespaces a cgroups Dockeru poskytují skutečnou izolaci, ale nejsou totéž co hardwarová hranice. Místo spouštění každého klienta na VM – nebo hůř, zacházet se všemi klienty stejně – vytvořte malou sadu izolačních vrstev a přiřaďte každého klienta k jedné z nich podle citlivosti dat, důvěry a shody s předpisy. Uzavřený kontejner (non-root, odstraněné capabilities, seccomp, read-only root) pokrývá většinu webů; regulované nebo nepřátelské úlohy dostanou VM nebo hybrid kontejneru ve VM. Tento příspěvek poskytuje opakovatelný rozhodovací postup, srovnávací tabulku a upřímný pohled na to, kdy je více izolace zbytečné.

Jste v bodě obchodního hovoru, kdy nový klient řekne: „Jsme zdravotnictví, ukažte mi, že jsou naše data izolovaná od vašich ostatních klientů,“ a vy byste raději mluvili o čemkoli jiném?

Toto je problém agentur: ne jedno dokonalé nasazení, ale stejné spolehlivé nasazení opakované u tuctu klientů s různými rozpočty, rizikovými profily a požadavky na shodu. Zde je upřímná verze. Izolace Dockeru je skutečná, ale specifická. Namespaces dávají každému kontejneru vlastní pohled na procesy, síť a souborový systém; cgroups omezují CPU, paměť a diskové I/O, takže se tenanti nemohou navzájem vyhladovět. To vám ale nekoupí hardwarovou zeď mezi kontejnerem a jádrem hostitele. Pokud útočník uteče z kontejneru, je uvnitř jediného jádra, které máte. Zbytek tohoto článku mění tento nepříjemný fakt na opakovatelné rozhodnutí: zařaďte každého klienta podle citlivosti dat a důvěry, použijte základní profil zabezpečení a sáhněte po VM pouze tehdy, když jsou náklady na únik dat vyšší než náklady na VM.

Počkat, nejsou kontejnery už izolované?

Docker běží na Linux namespaces a cgroups, a tato slova dělají skutečnou práci. Namespaces oddělují ID procesů, síťové zásobníky, přípojné body a uživatele, takže proces v jednom kontejneru nemůže vidět tabulku procesů jiného. Cgroups nastavují limity: dejte kontejneru 0,5 CPU, 512 MB paměti a pevnou váhu blokového I/O, a přesně to dostane. Utečená smyčka v jednom tenantovi je omezena místo toho, aby položila souseda. Pokud jste nenakonfigurovali limity, přeskočili jste to nejzákladnější, k čemu cgroups slouží.

Vezměte si jednoduchou PHP aplikaci v kontejneru A. Vidí vlastní souborový systém, vlastní síťové rozhraní, vlastní PID 1. Kontejner B má totéž, ale jiný pohled. To jsou namespaces. Teď odejděte a vynechte paměťový limit: kontejner A může zaplnit RAM hostitele a zpomalit kontejner B na minimum. Přesně tomu mají cgroups zabránit. Ale dva kontejnery mohou být od sebe izolované pomocí namespaces a přesto sdílet jádro hostitele, a právě o tom je každý příběh o úniku z kontejneru. Exploit, který se dostane k jádru, se může potenciálně dostat ke každému tenantovi na tomto hostiteli.

„Docker je izolovaný“ je polopravdivá věta. Přesná verze je: „Docker izoluje pomocí namespaces a cgroups, a zranitelnost jádra je poloměr výbuchu.“ Než svěříte tenantovi spouštění nedůvěryhodného kódu, chvíli si s tou myšlenkou pohrajte. Odpovědí není „nikdy nepoužívejte kontejnery“ – to je snadná panika. Odpovědí je systém vrstev.

Proč tedy někteří klienti potřebují více než namespaces?

Upřímná odpověď je, že izolace není přepínač, ale spektrum. Na jednom konci máte plně sdílený kontejner, kde jsou všichni efektivně v jedné aplikaci. Na druhém konci máte samostatný VM pro každého tenanta s vlastním jádrem. Většina agenturní práce žije v nepříjemném středu, a střed není binární volba mezi „Docker je v pořádku“ a „spustit VM pro všechny.“

Co posune klienta doprava, není jeho velikost. Jsou to čtyři otázky:

  • Uchovávají regulovaná data? Zdravotní záznamy, údaje o platebních kartách, cokoli, co by regulátor označil za citlivé.
  • Má únik dat na jejich tenantovi reálnou cestu k jinému tenantovi? Pokud mohou spouštět libovolný kód, ano.
  • Důvěřujete kódu a lidem, kteří ho nasazují? Klient, který najme nejlevnějšího freelancera, není na stejné úrovni důvěry jako klient, jehož vývojový tým znáte.
  • Píše se v jejich smlouvě „vyhrazené“, „izolované“ nebo „soukromé“? Pokud ano, už jste slíbili určitou vrstvu; jediným úkolem je nyní vybrat tu správnou.

Pokud na tyto otázky zatím nedokážete odpovědět, zařaďte klienta do základní vrstvy a zapište si předpoklady. To není bezpečnostní audit; je to kontrola zdravého rozumu, kterou opakujete při každém onboardingu.

Jak se rozhodnu pro každého klienta, aniž bych pokaždé spouštěl bezpečnostní audit?

Vytvořte malou tabulku a držte se jí. Nepotřebujete matici se čtyřiceti buňkami. Čtyři vrstvy pokryjí téměř každého klienta, kterého agentura uvidí.

Pozice klientaCo je skutečně oddělujePoužijte, když
Vrstva 1: Sdílená aplikace/kontejnerPouze aplikační logikaInterní nástroje, nízce riziková data, projekty, kde jsou všichni explicitně v jednom přihlašovacím systému
Vrstva 2: Stejný hostitel, samostatné kontejneryNamespaces a cgroupsVětšina marketingových webů, kontaktní formuláře, žádná citlivá data
Vrstva 3: Uzavřený kontejnerVrstva 2 + non-root, odstraněné capabilities, seccomp, read-only root, segmentace sítěE-commerce, PII, vlastní kód, kterému zcela nedůvěřujete
Vrstva 4: VM pro každého tenantaHypervizor a samostatné jádroZdravotnictví, finance, compliance dokumenty, nedůvěryhodný kód, hluční sousedé

Takhle to vypadá v praxi. Pekařství s kontaktním formulářem a odkazem na Instagram patří do vrstvy 2: jeden kontejner na sdíleném hostiteli, výchozí Docker networking, limity zdrojů, hotovo. Internetový obchod, který ukládá jména zákazníků, adresy a přesměrování plateb, patří do vrstvy 3: stejný sdílený hostitel, ale kontejner běží jako non-root uživatel, nemá žádné další kernel capabilities, používá seccomp profil a vystavuje pouze port 443. Lékařský portál pro příjem pacientů, který ukládá chráněné zdravotní informace, patří do vrstvy 4: VM pro každého tenanta, protože náklady na únik dat nejsou „vypořádáme se s tím“, ale „nemůžeme klientovi ukázat, že jsme ho brali vážně.“

Celý trik spočívá v tom, že pro každého klienta znovu nepřemýšlíte o architektuře. Vyberete řádek z tabulky, na které jste se už shodli. Tak může pětičlenná agentura provozovat stovky webů bez stovek samostatných bezpečnostních posedlostí. Zároveň to znamená, že příští klient nedostane odpověď, která závisí na tom, který člen týmu zvedl telefon. Pro hlubší architektonickou debatu o těchto volbách se tento průvodce navrhováním úrovní izolace pro multi-tenant prostředí podrobněji věnuje kompromisům.

Jak vlastně vypadá uzavřený kontejner?

Přestaňme říkat „uzavřený“ a pojďme k konkrétnímu. Tohle znamená vrstva 3 pro typického klienta na WordPressu nebo PHP.

Nejprve změňte uživatele. Většina oficiálních obrazů stále standardně běží jako root; ve svém Dockerfile vytvořte non-root uživatele a spouštějte aplikaci jako tento uživatel. Tím okamžitě odstraníte nejběžnější způsob, jakým se kompromitace kontejneru stane kompromitací hostitele. Za druhé, odeberte capabilities, které nepotřebujete. Spusťte s --cap-drop ALL a vraťte pouze jednu, obvykle NET_BIND_SERVICE, aby aplikace mohla naslouchat na portu 80. Už jen to je větší změna, než většina lidí čeká. Za třetí, nastavte kořenový souborový systém na read-only pomocí --read-only a připojte zapisovatelné adresáře (uploady, datový adresář databáze) jako volume nebo tmpfs. Za čtvrté, použijte seccomp profil a pokud to váš hostitel podporuje, také AppArmor nebo SELinux. Nakonec umístěte kontejner do vyhrazené Docker sítě a vystavte pouze porty, které skutečně musí být dostupné.

Projděme si příklad s WordPressem. Základní obraz pravděpodobně běží jako root, takže přidáte krok useradd a direktivu USER. Spustíte kontejner s paměťovým limitem a CPU limitem, aby nával provozu z pluginů nepoškodil souseda. Připojíte /var/www/html/wp-content/uploads jako zapisovatelný volume. Nastavíte --read-only. Připojíte ho k síti, která nemá nikde poblíž příznak --privileged. Výsledkem je kontejner, který býval „web WordPress“ a nyní je „web WordPress, který je náhodou více zabezpečený než většina virtuálních privátních serverů.“

Pokud se vám ruční vytváření všeho zdá křehké, existuje jednodušší střední cesta: Docker Enhanced Container Isolation, která používá izolaci uživatelských namespaces a bezpečný běhový prostředí kontejnerů. Je to legitimní zkratka, ale není to volný průkaz k vynechání non-root nebo odebírání capabilities. Tenant stále potřebuje rozumný obraz. Rozdíl je v tom, že útočná plocha směrem k jádru se zmenší, aniž byste se přes noc stali expertem na seccomp. Pokud chcete přesný postup pro jednoho tenanta, podrobný průvodce zabezpečením izolace převede tuto sekci na příkazy typu copy-paste.

Kdy přestanu vrstvit a prostě jim dám VM?

Zde je kontroverzní část: více izolace není automaticky lepší. VM vám poskytnou izolaci na úrovni hardwaru, samostatné jádro a mnohem menší útočnou plochu, pokud padne jádro hosta. To je přesně to, co klienti ze zdravotnictví a financí očekávají, když řeknou „chceme být izolovaní“. Ale každý VM přidává náklady na opravy, zálohování a výpočetní výkon a znásobuje práci s aktualizací celé flotily. Pokud dáte VM každému klientovi, protože vám jeden klient kdysi řekl, že se Dockeru bojí, koupili jste si bezpečnostní divadlo za skutečné peníze.

VM je správná odpověď, když je riziko na tenanta vyšší než provozní náklady na VM na tenanta. To znamená regulovaná data, písemné požadavky na shodu, nedůvěryhodný kód třetích stran nebo klient, který potřebuje odstranit hlučného souseda. Je to také správná odpověď, když smlouva klienta doslova slibuje vyhrazené prostředí, protože „kontejner“ není to, co si představují, když podepisují „vyhrazené“.

Ale VM neomlouvá lajdácký kontejner. Častou pastí je umístit klienta do VM a pak vynechat zabezpečení, protože „VM je chrání“. VM chrání hostitele před tenantem, ne tenanta před jeho vlastním špatným obrazem. Uvnitř toho VM stále chcete non-root, odstraněné capabilities a seccomp. Hybridní přístup – kontejnery uvnitř VM – je často ideální místo: VM poskytuje hranici pro rozhovory o shodě a kontejner vám dává pracovní postup nasazení, který už znáte. Delší verze této debaty je v článku Měl by každý tenant dostat vlastní VM?, ale krátká odpověď je, že VM je pro smlouvu, ne pro strach.

Jak to zajistím opakovatelné napříč všemi klienty?

Opakovatelnosti dosáhnete tím, že ze systému vrstev uděláte šablonu, ne vzpomínku. Mějte adresář se soubory Compose, jeden pro každou vrstvu: tier2-baseline, tier3-locked, tier4-vm-hybrid. Když se objeví nový klient, zkopírujte šablonu, změňte proměnné prostředí a už znáte tvar izolace dřív, než napíšete řádek nové infrastruktury.

Pak si rozhodnutí zapište. Ne 400stránkovou bezpečnostní zprávu, ale krátký odstavec v repozitáři klienta: jaká data ukládají, ve které vrstvě jsou, proč a co by je posunulo o vrstvu výš. Tento odstavec má větší hodnotu než sto firewallových pravidel, protože je to věc, kterou můžete ukázat příštímu auditorovi nebo dalšímu ustaranému klientovi. Také vám zabrání si pamatovat, proč pekařství dostalo vrstvu 2 a e-shop vrstvu 3, poté co původní obchodní hovor vyprchá.

Automatizujte nudné kontroly. Nechte svůj CI skenovat každý obraz klienta a selhat buildu, pokud běží jako root, pokud má všechny capabilities, nebo pokud se snaží publikovat jiný port, než který daná vrstva povoluje. Nic z toho není exotické; jen se ujistíte, že šablonu náhodou nerozbije dobře míněný vývojář. Pokud už stejně budujete okolní hostingový pracovní postup, článek o produkčně připravených Docker hostingových strategiích pokrývá část, která následuje po definování kontejnerů.

Na tom všem není nic okouzlujícího. Žádný blogový příspěvek nezpůsobí, že „izolace tenantů“ bude znít tak vzrušeně jako diagram zelené architektury. Ale to je rozdíl mezi agenturou, která na otázku „jak jsme izolovaní?“ odpoví se zkříženými prsty „naprosto“, a agenturou, která může ukázat vrstvu, konfiguraci a důvod. Kontejnery nejsou kouzelná zeď. VM nejsou všelék. Systém vrstev je jen rozhodnutí, které si zapíšete a znovu použijete – a pro agenturu je opakovatelnost celá hra.

Sources (5)