Blog
Má mať každý nájomník vlastný VM?
Vyberte si medzi kontajnermi pre jednotlivých nájomníkov, VM a hybridnými nastaveniami pomocou rozhodovacieho rámca založeného na rizikách a krokov na posilnenie zabezpečenia, ktoré každú možnosť obhájajú.
Zhrnutie
Hosting pre viacero nájomníkov vás núti rozhodnúť sa, ako ďaleko môžu nájomníci zasahovať do seba navzájom. Kontajnery používajú Linuxové namespaces a cgroups na izoláciu procesov a zdrojov, ale zdieľajú jadro hostiteľa. Virtuálne stroje pridávajú hardvérovú hranicu, za cenu rýchlosti a prevádzkovej záťaže. Hybridný prístup – kontajnery vo vnútri VM – vám môže dať oboje, ale zdvojnásobuje povrch, ktorý musíte opravovať. Tento článok vás prevedie rozhodovaním založeným na rizikách, porovnaním bok po boku a krokmi na posilnenie Dockeru, ktoré sú dôležité aj vo vnútri VM. Na konci budete vedieť, ktorý izolačný model vyhovuje vašim nájomníkom a čo nakonfigurovať pred spustením.
Vaša multi-tenant aplikácia je takmer pripravená. Máte Docker Compose súbor, ktorý spustí stack pre každého zákazníka, a je rýchly. Potom sa priateľ, ktorý prevádzkuje hostingovú spoločnosť, opýta: „Dávate každému nájomníkovi vlastný VM?“ Znehybnete. Na túto otázku ste neboli pripravení. Tento článok vám dnes dá spôsob, ako na ňu odpovedať, bez bezpečnostného tímu. Robíte to sami, takže rozhodnutie musí byť dostatočne jednoduché na obhajobu o druhej v noci.
Prestaňte hľadať „najlepší“ model. Začnite tým, že si zapíšete, čo sa stane, ak kód nájomníka prevezme kontrolu nad vaším hostiteľom. Definujte polomer výbuchu (blast radius) predtým, než si vyberiete akýkoľvek nástroj. Toto cvičenie vám povie viac než akýkoľvek benchmark.
Jadro je spolubývajúci, ktorého nemôžete vysťahovať
Kontajnery sú efektívne, pretože zdieľajú jadro hostiteľa. Toto zdieľanie je celý trik a celé riziko. Linuxové namespaces dávajú každému kontajneru vlastný pohľad na procesy, sieť a súborový systém. Control groups (cgroups) vám umožňujú obmedziť CPU, pamäť a diskové I/O, aby jeden nájomník nemohol vyhladovať ostatných. Ale ani jedno nevytvára hardvérovú stenu.
Predstavte si kontajner ako proces s naozaj dobrým falošným preukazom. Verí, že je na vlastnom stroji. Jadro je však jedna kópia Linuxu bežiaca na vašom hostiteľovi. Ak nájomník zneužije zraniteľnosť jadra, namespaces sa stanú len metadátami. Útočník, ktorý môže volať funkcie jadra, sa môže dostať k iným namespaceom na rovnakom jadre. To je únik z kontajnera, o ktorom stále počúvate.
Povedzme, že hostujete malý B2B nástroj s jedným kontajnerom na klienta. Klient si nainštaluje podozrivý plugin s chybou vzdialeného spustenia kódu. Pri predvolených nastaveniach Dockeru tento proces beží ako root vo vnútri kontajnera. Root v kontajneri je stále UID 0 a jadro nerozlišuje toto UID od roota hostiteľa, pokiaľ explicitne nemapujete používateľov. Útočník sa môže pokúsiť dostať von a zdieľané jadro je jeho cieľom.
Zlyhanie nemusí byť dramatické. Jeden nájomník, ktorému uniká pamäť, môže hostiteľa dostať do swapu, čím spomalí všetkých ostatných nájomníkov. Bez limitov cgroup je jeden zle sa správajúci cyklus útokom na dostupnosť. S nimi je to zablokovaný proces a upozornenie.
Znamená to, že kontajnery sú nebezpečné? Nie. Znamená to, že jadro musíte považovať za zdieľanú zónu dôvery. Pred výberom si napíšte jednostranné vyhlásenie o riziku: „Ak je kontajner nájomníka kompromitovaný, útočník má prístup k: [list]. Obchodné náklady by boli: [amount or impact].“ Ak vás tento odsek vystraší, nie ste paranoidní. Ste úprimní.
Ak sa chcete hlbšie pozrieť na spektrum izolácie, od zdieľaných kontajnerov až po úplne oddelené stacky, pozrite si nášho sprievodcu navrhovaním multi-tenant Docker architektúry.
Tri spôsoby, ako to rozdeliť (vyberte si jeden pred nasadením)
Na izoláciu pre viacerých nájomníkov existujú naozaj tri architektúry. Každá „najlepšia praktika“ je kombináciou týchto.
| Prístup | Izolačná bariéra | Najlepšie, keď | Najťažšia výhrada |
|---|---|---|---|
| Kontajnery pre jednotlivých nájomníkov | Kernelové namespaces + cgroups | Veľa malých nájomníkov, nízke riziko na nájomníka, potreba hustoty | Jeden exploit jadra môže rozbiť každého nájomníka na tomto hostiteľovi |
| Jeden VM na nájomníka | Hypervízor / hardvérová virtualizácia | Regulované dáta, nepriateľskí nájomníci, vysoká hodnota na nájomníka | Ťažšie, pomalšie na vytvorenie, opravujete OS pre každého nájomníka |
| Kontajnery vo vnútri VM | Hranica VM okolo kontajnerových pracovných záťaží | Hustota plus tvrdá škrupina medzi skupinami | Náklady a prevádzková réžia takmer dvojnásobné |
Kontajnery pre jednotlivých nájomníkov. Toto je predvolená voľba pre väčšinu zakladateľov SaaS. Každý nájomník dostane vlastný kontajner alebo malý Compose stack. Vytvorenie je okamžité, obrazy sú malé, CI/CD je jednoduchý. Limity zdrojov zabránia hlučným susedom zožrať server. Kompromisom je zdieľané jadro. Ak dokážete udržať pracovné záťaže bez privilegií a pravidelne opravovať hostiteľa, je to často správny prvý krok.
Nedávajte dvoch nájomníkov do toho istého kontajnera. To je zdieľané jadro plus zdieľaný runtime plus zdieľaný súborový systém. Ak jeden nájomník nahraje súbor, ktorý vytvorí proces, druhý nájomník je už v rovnakej tabuľke procesov. Kontajner je vaša jednotka izolácie; urobte z neho jedného nájomníka na kontajner.
A čo databáza? Ak sa každý nájomník pripája k jednej inštancii MongoDB alebo PostgreSQL s rovnakými prihlasovacími údajmi, už ste pridali obrovský zdieľaný komponent. Dajte každému nájomníkovi samostatné prihlasovacie údaje a ideálne samostatnú databázu alebo schému. Kontajnery izolujú aplikáciu; databáza je často prvý únik, ktorý útočník otestuje.
Jeden VM na nájomníka. Dajte každému nájomníkovi plný virtuálny stroj. Hypervízor pridáva hardvérovú hranicu, čo je presne to, čo musí exploit jadra prekonať, aby sa dostal k hostiteľovi. To je dôležité v regulovanom prostredí alebo keď nájomníci nie sú dôveryhodní. Cenou je hustota a čas. Teraz spravujete flotilu operačných systémov, nielen kontajnerov. Každý VM potrebuje aktualizácie, bezpečnostných agentov a monitorovanie. Pre sólového zakladateľa je to skutočná práca.
Vzory, ktoré fungujú na tejto úrovni: použite infraštruktúru ako kód na vytvorenie VM z rovnakého základného obrazu, zapracujte aktualizácie do nových obrazov namiesto opravy živých systémov a ukončite pracovné záťaže, ktoré nespoznávate. Udržujte správcovský port VM zatvorený pred internetom.
Kontajnery vo vnútri VM. Tento hybrid sa v kurzoch pre začiatočníkov málokedy spomína. Okolo každého nájomníka (alebo malej skupiny nájomníkov) umiestnite malý VM a potom v ňom spúšťate kontajnery. VM je kontajner na polomer výbuchu; kontajnery sú len nasaditeľné jednotky. To vám dáva tvrdú hranicu virtualizácie a reprodukovateľnosť obrazov. Stojí to viac, pretože platíte za réžiu virtualizácie a flexibilitu kontajnerov, ale môže to byť najrozumnejší dlhodobý model, keď nemôžete úplne dôverovať nájomníkom.
Jeden bežný mikropríklad: nájomník prevádzkuje Node API a background worker. Namiesto jedného veľkého kontajnera s oboma procesmi použite jeden VM a potom dva kontajnery s rôznymi limitmi zdrojov, zdieľanou sieťou a bez priameho vystavenia internetu pre workera. VM poskytuje tvrdú hranicu; kontajnery poskytujú štruktúru.
Ktorý by ste si mali vybrať? Tabuľka je váš užší výber. Ďalšie časti rozhodnutie konkretizujú.
Ak si vyberiete kontajnery, urobte týchto šesť vecí, alebo sa do toho nepúšťajte
Kontajnery pre jednotlivých nájomníkov sú v poriadku, ak každý kontajner považujete za potenciálneho útočníka. To začína konfiguráciou, nie želaným myslením.
0. Obmedzte zdroje skôr, než niekomu začnete dôverovať. Cgroups sú mechanizmom spravodlivosti a obranou dostupnosti. Nastavte --memory a --cpus pre každý kontajner. Nájomník, ktorému uniká pamäť, by mal naraziť na vlastný limit, nie na limit vášho servera. Toto nie je bezpečnostná hranica, ale hlučný sused je útok bez jediného riadku kódu. Praktický štart: --memory 512m --cpus 0.5. Pre worker proces začnite nižšie a škálujte.
1. Spúšťajte ako ne-root používateľ. Nikdy nedovoľte procesu v kontajneri používať UID 0, pokiaľ to absolútne nepotrebujete. Nastavte používateľa v Dockerfile a odovzdajte --user ako extra ochranu. Exploit bežiaci ako neprivilegovaný používateľ má oveľa menej ciest k jadru. Vo vašom Dockerfile vytvorte používateľa: RUN useradd -u 10001 app a USER app. Nepreskakujte to, aby ste ušetrili čas.
2. Odstráňte všetky capabilities, ktoré nepotrebujete. Linuxové capabilities rozdeľujú moc roota na malé časti. Väčšina webových aplikácií nepotrebuje takmer žiadne. Začnite s --cap-drop=ALL a pridajte späť len to, o čom viete, že to potrebujete. Kontajner bez CAP_SYS_ADMIN sa oveľa ťažšie používa na namespace triky. Ak sa vaša aplikácia pokúša viazať privilegovaný port, spustite ju na vysokom porte a pred ňu dajte proxy namiesto udeľovania NET_BIND_SERVICE.
3. Nastavte súborový systém ako len na čítanie. Vaša aplikácia by nemala zapisovať do vlastnej vrstvy kontajnera. Pripojte tmpfs pre stav. Útočník, ktorý nemôže zapisovať na disk, má oveľa ťažšie zabezpečiť perzistenciu. Kompromitovaná PHP aplikácia, ktorá sa pokúša zapísať webshell, zlyhá, keď je root súborový systém len na čítanie. Pre zapisovateľný adresár, ktorý aplikácia naozaj potrebuje, môžete pripojiť pomenovaný volume.
4. Použite seccomp a AppArmor alebo SELinux. Tieto posielajú rizikové syscally na hromadu odpadu. Docker obsahuje predvolený seccomp profil; použite ho. Pridajte AppArmor profil ako ďalšiu vrstvu. Nemusíte ovládať každý syscall. Musíte odoprieť to, čo bežný web worker nikdy nevyžaduje. Nikdy nespúšťajte s --privileged. Tento príznak deaktivuje takmer všetku obranu, ktorú ste práve nastavili.
5. Segmentujte sieť. Nedávajte každému kontajneru cestu ku každému inému kontajneru. Predvolene deny, potom otvorte len porty, ktoré potrebujete. Kompromitovaný databázový kontajner by nemal byť schopný skenovať váš admin panel. Ak sú nájomníci v oddelených sieťach, narušenie jednej siete sa nemôže šíriť laterálne.
Praktický štart:
docker run --user 10001 --cap-drop=ALL --security-opt no-new-privileges --read-only --tmpfs /tmp:rw,size=64M --security-opt seccomp=default.json --memory 512m --cpus 0.5 myimage
Rovnaké príznaky vložte do Compose súboru a aplikujte ich na každého nájomníka. Toto nie je úplné, ale je to oveľa silnejšie predvolené nastavenie, než aké vám docker run dá hneď po vybalení.
Pre hlbší prechod použite nášho podrobného sprievodcu posilňovaním Docker kontajnerov v multi-tenant hostingu.
Docker Enhanced Container Isolation je výnimka, o ktorej by ste mali vedieť
Ak bežíte v spravovanom Docker prostredí, hľadajte Docker Enhanced Container Isolation (ECI). Pod kapotou používa izoláciu používateľských namespaceov a bezpečný runtime kontajnerov. Root v kontajneri sa mapuje na neprivilegovaného používateľa na hostiteľovi, takže ani kontajner bežiaci ako root nezíska práva roota hostiteľa. Tiež predvolene blokuje nebezpečné capabilities a syscally. Toto nie je niečo, čo môžete znovu vytvoriť niekoľkými príznakmi na vanilkovom Dockeri. Ak vaša platforma to podporuje, zapnite to. Neodstraňuje to potrebu ne-root používateľov a limitov zdrojov, ale mení to rizikovú matematiku.
Časť tohto môžete priblížiť pomocou remapovania používateľských namespaceov (userns-remap) v Docker daemone. To nie je také úplné ako bezpečný runtime, ale je to lepšie ako nič. Ak to použijete, overte, či mapovanie UID funguje, predtým než tomu začnete dôverovať.
Mýtus o VM: Prechod na virtuálne stroje nie je posilňovanie
Tu je kontrariánska časť, a to je časť, ktorú väčšina ľudí preskočí. Ak prejdete na jeden VM na nájomníka a potom doň nasadíte svoje bežné kontajnery, neodstránili ste svoj problém s bezpečnosťou kontajnerov. Pridali ste širokú klietku. Únik z kontajnera stále funguje; útočník jednoducho pristane vo VM namiesto hostiteľa. To je skutočné zlepšenie, ale stále potrebujete šesť krokov.
Ďalšou pascou je predpokladať, že samotný VM je bezpečný. Predvolený obraz so slabým SSH heslom, neopravenými základnými balíkmi alebo otvoreným správcovským portom je darček. Hranica hypervízora záleží len vtedy, ak je hosť posilnený a aktualizovaný. Inak je váš „bezpečný VM“ rýchlejšou cestou ku kompromitácii, pretože sa cítite bezpečne a prestanete kontrolovať.
Čo vám VM dáva, je zredukovateľný polomer výbuchu. Katastrofa jedného nájomníka zostane v jednom VM. Čo vás to stojí, je váš čas. Stanete sa správcom toľkých operačných systémov, koľko máte nájomníkov. Ak ste sólový zakladateľ, ktorý dodáva produkt, opýtajte sa, či máte hodiny na opravu a monitorovanie flotily. Ak áno, VM na nájomníka môže byť správna voľba. Ak nie, kontajnery so silným posilnením môžu byť úprimnejšie.
Tiež si pamätajte, že váš hypervízor hostiteľ je kritický cieľ. Kompromitovaný hypervízor môže vidieť všetkých hostí. Opravujte hostiteľa, nielen hostí. VM vás neospravedlňuje z opravovania hostiteľa; zvyšuje stávky pre jeho vynechanie.
Upozornenie k hybridu: nepredpokladajte, že kontajnery vo vnútri VM vám zadarmo dajú „dve vrstvy bezpečnosti“. VM pridáva hranicu; kontajner stále potrebuje ne-root, capabilities a seccomp. Inak je prvá vrstva len taká silná, aký je najslabší kontajner.
Štyri otázky, ktoré vyriešia debatu za desať minút
Neoptimalizujte v abstraktnej rovine. Položte si tieto štyri otázky v poradí. Zapíšte si odpovede.
1. K čomu má môj nájomník prístup? Ak sa nájomník môže dostať len k svojej vlastnej webovej aplikácii a databáze, kontajnery pre jednotlivých nájomníkov s prísnymi sieťovými pravidlami sú obhájiteľné. Ak sú dáta nájomníka regulované alebo finančne citlivé, presuňte sa smerom k VM.
2. Koľko by ma stála kompromitácia jedného nájomníka? Spočítajte stratených zákazníkov, právne riziká a dôveru. Ak je číslo väčšie ako náklady na prevádzku VM, minite peniaze. Ak nie, kontajnery sú racionálna voľba.
3. Koľko mám nájomníkov a koľko platia? Veľa malých predplatiteľov: záleží na hustote kontajnerov. Niekoľko veľkých účtov: dajte každému VM a fakturujte podľa toho. Nájomníci, ktorí vám platia menej ako káva, by nemali každý vyžadovať OS na správu.
4. Dokážem veci opravovať podľa plánu? Kontajnery zdieľajú jedno jadro hostiteľa, takže oprava hostiteľa chráni všetkých. VM znásobujú vaše ciele na opravy. Ak viete, že aktualizácie vynecháte, vyberte si architektúru s menej pohyblivými časťami a tvrdšími predvolenými nastaveniami.
Vaše odpovede sa zoskupia. Dve alebo viac odpovedí zameraných na VM znamená, že by ste nemali predvolene používať kontajnery pre jednotlivých nájomníkov. Tri alebo viac odpovedí zameraných na kontajnery znamená, že VM sú predčasné. Jeden kontraintuitívny výsledok: nízkopríjmový nájomník s prístupom k citlivým dátam stále potrebuje VM, pretože regulačné náklady nemajú nič spoločné s tým, koľko platí.
Nasaďte minimum, ktorému môžete dôverovať, a potom si zaslúžte viac izolácie
Vaša prvá architektúra nemusí byť vaša konečná. Začnite s najtesnejším nastavením, ktoré dokážete skutočne udržiavať, a potom pridávajte izoláciu, keď si to vaša základňa nájomníkov vyžiada. Pre väčšinu sólových prevádzkovateľov to znamená kontajnery pre jednotlivých nájomníkov s ne-root, obmedzenými capabilities, súborovými systémami len na čítanie, seccomp a segmentáciou siete. Pre regulovaných alebo vysoko hodnotných nájomníkov prejdite rovno na jeden VM na nájomníka, s kontajnermi len ako baliacou vrstvou vo vnútri.
Čokoľvek si vyberiete, zapíšte si rozhodnutie a vracajte sa k nemu štvrťročne. Keď dostanete prvú otázku „mali by sme presunúť tohto nájomníka na VM?“, budete mať odpoveď a budete mať kontrolný zoznam, ktorý ju podporí. To je to, čo izolácia v skutočnosti znamená: kompromis, ktorý spravujete, nie technológia, ktorú si kúpite.
Pred spustením si prejdite náš praktický kontrolný zoznam bezpečnosti izolácie Dockeru – premení tieto rozhodnutia na zoznam, ktorý môžete overiť, kým zákazníkovi ukážete stránku.

