Blog

Ali naj vsak najemnik dobi svoj VM?

Izberite med vsebniki na najemnika, navideznimi strežniki in hibridnimi postavitvami z okvirom za odločanje na podlagi tveganja ter koraki za utrjevanje, zaradi katerih je vsaka možnost upravičena.

Povzetek

Večnajemniško gostovanje vas sili, da se odločite, kako daleč lahko najemniki sežejo drug do drugega. Vsebniki uporabljajo imenske prostore Linuxa (Linux namespaces) in cgroups za izolacijo procesov in virov, vendar si delijo jedro gostitelja. Navidezni strežniki dodajo mejo na ravni strojne opreme, vendar za ceno hitrosti in operativne obremenitve. Hibridni pristop – vsebniki znotraj navideznih strežnikov – vam lahko da oboje, vendar podvoji površino, ki jo morate posodabljati. Ta članek vas popelje skozi odločanje na podlagi tveganja, primerjavo drugega ob drugem in korake utrjevanja Dockerja, ki so pomembni tudi znotraj navideznega strežnika. Do konca boste vedeli, kateri model izolacije ustreza vašim najemnikom in kaj morate konfigurirati pred zagonom.

Vaša večnajemniška aplikacija je skoraj pripravljena. Imate datoteko Docker Compose, ki za vsako stranko postavi sklad, in to hitro. Nato prijatelj, ki upravlja gostiteljsko podjetje, vpraša: „Ali daješ vsakemu najemniku svoj navidezni strežnik?" Zmrznete. Na to vprašanje niste bili pripravljeni. Ta članek vam daje način, kako nanj odgovoriti danes, brez varnostne ekipe. To počnete sami, zato mora biti odločitev dovolj preprosta, da jo lahko zagovarjate ob 2. uri zjutraj.

Nehajte iskati 'najboljši' model. Začnite tako, da zapišete, kaj se zgodi, če koda najemnika prevzame vaš gostitelj. Določite radij udarca (blast radius), preden izberete katero koli orodje. Ta vaja vam bo povedala več kot kateri koli benchmark.

Jedro je sostanovalec, ki ga ne morete izseliti

Vsebniki so učinkoviti, ker si delijo jedro gostitelja. To deljenje je celoten trik in celotno tveganje. Imenski prostori Linuxa (Linux namespaces) dajo vsakemu vsebniku lasten pogled na procese, omrežje in datotečni sistem. Nadzorne skupine (cgroups) vam omogočajo, da omejite CPU, pomnilnik in diskovni vnos/izhod, tako da en najemnik ne more izstradati drugih. Toda nobena od teh ne ustvari strojne stene.

Predstavljajte si vsebnik kot proces z res dobrim ponarejenim osebnim dokumentom. Verjame, da je na svojem računalniku. Vendar je jedro ena kopija Linuxa, ki teče na vašem gostitelju. Če najemnik izkoristi ranljivost jedra, imenski prostori postanejo zgolj metapodatki in nič več. Napadalec, ki lahko kliče funkcije jedra, lahko doseže druge imenske prostore na istem jedru. To je tisti pobeg iz vsebnika (container escape), o katerem nenehno slišite.

Recimo, da gostite majhno orodje B2B z enim vsebnikom na stranko. Stranka namesti sumljiv vtičnik z napako oddaljenega izvajanja kode. S privzetimi nastavitvami Dockerja ta proces teče kot root v vsebniku. Root v vsebniku je še vedno UID 0 in jedro tega UID ne razlikuje od root-a gostitelja, razen če izrecno preslikate uporabnike. Napadalec lahko poskusi pobegniti, deljeno jedro pa je njegov cilj.

Napaka ni nujno dramatična. En sam najemnik, ki pušča pomnilnik, lahko potisne gostitelj v swap, kar upočasni vse druge najemnike. Brez omejitev cgroups je ena sama zanka, ki se ne obnaša pravilno, napad na razpoložljivost. Z njimi pa je to blokiran proces in opozorilo.

Ali to pomeni, da so vsebniki nevarni? Ne. Pomeni, da morate jedro obravnavati kot skupno območje zaupanja. Preden se odločite, napišite en odstavek izjave o tveganju: „Če je vsebnik najemnika ogrožen, lahko napadalec dostopa do: [seznam]. Poslovni stroški bi bili: [znesek ali vpliv].“ Če vas ta odstavek prestraši, niste paranoidni. Ste pošteni.

Za podrobnejši vpogled v spekter izolacije, od deljenih vsebnikov do popolnoma ločenih skladov, si oglejte naš vodnik o načrtovanju večnajemniške Docker arhitekture.

Trije načini razdelitve (izberite enega pred uvedbo)

Resnično obstajajo tri arhitekture za izolacijo pri več najemnikih. Vsaka 'najboljša praksa' je kombinacija teh.

PristopIzolacijska pregradaNajbolje, koNajtežji zadržek
Vsebniki na najemnikaImenski prostori jedra + cgroupsVeliko majhnih najemnikov, nizko tveganje na najemnika, potrebna gostotaEn izkoristek jedra lahko poruši vse najemnike na tem gostitelju
En navidezni strežnik na najemnikaHipervizor/virtualizacija strojne opremeRegulirani podatki, sovražni najemniki, visoka vrednost na najemnikaTežji, počasnejše dodeljevanje, posodabljate OS za vsakega najemnika
Vsebniki znotraj navideznih strežnikovPregrada VM okoli vsebniških delovnih obremenitevGostota plus trda lupina med skupinamiStroški in operativna obremenitev se skoraj podvojijo

Vsebniki na najemnika. To je privzeta izbira za večino ustanoviteljev SaaS. Vsak najemnik dobi svoj vsebnik ali majhen sklad Compose. Dodeljevanje je takojšnje, slike so majhne, CI/CD je preprost. Omejitve virov preprečujejo hrupnim sosedom, da bi požrli strežnik. Kompromis je deljeno jedro. Če lahko delovne obremenitve ohranite neprivilegirane in redno posodabljate gostitelj, je to pogosto prava prva poteza.

Ne dajajte dveh najemnikov v isti vsebnik. To je deljeno jedro plus deljen izvajalni čas plus deljen datotečni sistem. Če en najemnik naloži datoteko, ki ustvari proces, je drugi najemnik že v isti procesni tabeli. Vsebnik je vaša enota izolacije; poskrbite, da je en najemnik na vsebnik.

Kaj pa podatkovna baza? Če se vsak najemnik poveže na eno instanco MongoDB ali PostgreSQL z istimi poverilnicami, ste že dodali ogromen skupni del. Vsakemu najemniku dajte ločene poverilnice in po možnosti ločeno podatkovno bazo ali shemo. Vsebniki izolirajo aplikacijo; podatkovna baza je pogosto prvo puščanje, ki ga napadalec preizkusi.

En navidezni strežnik na najemnika. Vsakemu najemniku dajte poln navidezni strežnik. Hipervizor doda mejo na ravni strojne opreme, kar je točno to, kar mora izkoristek jedra prečkati, da doseže gostitelja. To je pomembno v reguliranih okoljih ali kadar najemniki niso zaupanja vredni. Cena je gostota in čas. Zdaj upravljate floto operacijskih sistemov, ne le vsebnikov. Vsak navidezni strežnik potrebuje posodobitve, varnostne agente in nadzor. Za samostojnega ustanovitelja je to resnično delo.

Vzorci, ki delujejo na tej ravni: uporabite infrastrukturo kot kodo (infrastructure-as-code) za ustvarjanje navideznega strežnika iz iste osnovne slike, vključite posodobitve v nove slike namesto da popravljate žive sisteme, in ukinite delovne obremenitve, ki jih ne prepoznate. Upravljalna vrata navideznega strežnika imejte zaprta za internet.

Vsebniki znotraj navideznih strežnikov. Ta hibrid se le redko obravnava v vadnicah za začetnike. Okoli vsakega najemnika (ali majhne skupine najemnikov) postavite majhen navidezni strežnik, nato v tem navideznem strežniku zaženete vsebnike. Navidezni strežnik je vsebnik radija udarca; vsebniki so le enote za uvajanje. To vam daje trdo mejo virtualizacije in ponovljivost slik. Stane več, ker plačate stroške virtualizacije in prilagodljivost vsebnikov, vendar je lahko najbolj zdrav dolgoročni model, ko ne morete popolnoma zaupati najemnikom.

Pogost mikro primer: najemnik izvaja Node API in ozadnega delavca. Namesto enega velikega vsebnika z obema procesoma uporabite en navidezni strežnik, nato dva vsebnika z različnimi omejitvami virov, skupnim omrežjem in brez neposredne izpostavljenosti internetu za delavca. Navidezni strežnik zagotavlja trdo mejo; vsebniki zagotavljajo strukturo.

Katero bi morali izbrati? Tabela je vaš ožji izbor. Naslednji razdelki odločitev konkretizirajo.

Če izberete vsebnike, naredite teh šest stvari ali pa se s tem ne ukvarjajte

Vsebniki na najemnika so v redu, če vsak vsebnik obravnavate kot potencialnega napadalca. To se začne s konfiguracijo, ne z željnim razmišljanjem.

0. Omejite vire, preden komurkoli zaupate. Cgroups so mehanizem poštenosti in obramba razpoložljivosti. Nastavite --memory in --cpus za vsak vsebnik. Najemnik, ki pušča pomnilnik, bi moral zadeti svojo lastno omejitev, ne omejitve vašega strežnika. To ni varnostna meja, vendar je hrupni sosed napad brez ene same vrstice kode. Praktičen začetek: --memory 512m --cpus 0.5. Za proces delavca začnite nižje in povečujte.

1. Zaženite kot ne-root uporabnik. Nikoli ne dovolite, da proces v vsebniku uporablja UID 0, razen če to nujno potrebujete. Nastavite uporabnika v Dockerfile in podajte --user kot dodatno zaščito. Izkoristek, ki teče kot neprivilegiran uporabnik, ima veliko manj poti do jedra. V svojem Dockerfile ustvarite uporabnika: RUN useradd -u 10001 app in USER app. Tega ne preskočite, da bi prihranili čas.

2. Odstranite vse zmogljivosti (capabilities), ki jih ne potrebujete. Zmogljivosti Linuxa razdelijo moč root-a na majhne dele. Večina spletnih aplikacij ne potrebuje skoraj nobene. Začnite z --cap-drop=ALL in dodajte nazaj samo tisto, za kar veste, da jo potrebujete. Vsebnik brez CAP_SYS_ADMIN je veliko težje uporabiti za trike z imenskimi prostori. Če vaša aplikacija poskuša vezati privilegirana vrata, jo zaženite na visokih vratih in pred njo postavite proxy namesto da podelite NET_BIND_SERVICE.

3. Naredite datotečni sistem samo za branje. Vaša aplikacija ne bi smela pisati v svojo plast vsebnika. Priklopite tmpfs za stanje. Napadalec, ki ne more pisati na disk, ima veliko težje pri nameščanju trajnosti. Ogrožena PHP aplikacija, ki poskuša zapisati spletno lupino (webshell), bo spodletela, če je korenski datotečni sistem samo za branje. Za pisno mapo, ki jo aplikacija resnično potrebuje, lahko priklopite poimenovani nosilec.

4. Uporabite seccomp in AppArmor ali SELinux. Ti pošljejo tvegane sistemske klice na smetišče. Docker prinaša privzeti profil seccomp; uporabite ga. Dodajte profil AppArmor za dodatno plast. Ni vam treba obvladati vsakega sistemskega klica. Zavrniti morate tisto, kar običajni spletni delavec nikoli ne zahteva. Nikoli ne zaženite s --privileged. Ta zastavica onemogoči skoraj vse obrambe, ki ste jih pravkar nastavili.

5. Segmentirajte omrežje. Ne dajte vsakemu vsebniku poti do vsakega drugega vsebnika. Privzeto zavrnite, nato odprite le vrata, ki jih potrebujete. Ogrožen vsebnik podatkovne baze ne bi smel moči skenirati vaše skrbniške plošče. Če so najemniki v ločenih omrežjih, se vdor v enem omrežju ne more širiti bočno.

Praktičen začetek:

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

Iste zastavice vnesite v datoteko Compose in jih uporabite za vsakega najemnika. To ni popolno, vendar je veliko močnejša privzeta nastavitev, kot vam jo docker run ponudi takoj po namestitvi.

Za podrobnejši vodnik uporabite naš vodnik po korakih za utrjevanje Docker vsebnikov v večnajemniškem gostovanju.

Dockerjeva izboljšana izolacija vsebnikov je izjema, ki bi jo morali poznati

Če delujete v upravljanem okolju Docker, poiščite Dockerjevo izboljšano izolacijo vsebnikov (Enhanced Container Isolation, ECI). V ozadju uporablja izolacijo uporabniških imenskih prostorov in varen izvajalni čas vsebnikov. Root v vsebniku se preslika v neprivilegiranega uporabnika na gostitelju, tako da tudi vsebnik, ki teče kot root, ne dobi korenskih privilegijev gostitelja. Prav tako privzeto blokira nevarne zmogljivosti in sistemske klice. Tega ni mogoče poustvariti z nekaj zastavicami na navadnem Dockerju. Če vaša platforma to podpira, to vklopite. To ne odpravi potrebe po ne-root uporabnikih in omejitvah virov, vendar spremeni matematiko tveganja.

Del tega lahko približate s ponovnim preslikavanjem uporabniških imenskih prostorov (userns-remap) v Dockerjevem demonu. To ni tako popolno kot varen izvajalni čas, vendar je bolje kot nič. Če ga uporabljate, preverite, ali preslikava UID deluje, preden mu zaupate.

Zmota o navideznih strežnikih: Selitev na navidezne strežnike ni utrjevanje

Tu je nasprotni del, in to je del, ki ga večina ljudi preskoči. Če se preselite na en navidezni strežnik na najemnika in nato v njem namestite svoje običajne vsebnike, niste odpravili varnostne težave vsebnikov. Dodali ste široko kletko. Pobeg iz vsebnika še vedno deluje; napadalec pristane v navideznem strežniku namesto na gostitelju. To je resnično izboljšanje, vendar še vedno potrebujete šest korakov.

Druga past je domneva, da je navidezni strežnik sam po sebi varen. Privzeta slika s šibkim geslom SSH, nepopravljenimi osnovnimi paketi ali odprtim upravljalnim vratom je darilo. Meja hipervizorja je pomembna le, če je gost utrjen in posodobljen. V nasprotnem primeru je vaš 'varni navidezni strežnik' hitrejša pot do ogroženosti, ker se počutite varne in nehate preverjati.

Kar vam navidezni strežnik prinese, je zmanjšljiv radij udarca. Nesreča enega najemnika ostane v enem navideznem strežniku. Kar vas stane, je vaš čas. Postanete sistemski skrbnik za toliko operacijskih sistemov, kolikor imate najemnikov. Če ste samostojni ustanovitelj, ki izdeluje izdelek, se vprašajte, ali imate ure za posodabljanje in nadzor flote. Če da, je navidezni strežnik na najemnika lahko prava odločitev. Če ne, so vsebniki z močnim utrjevanjem morda bolj pošteni.

Ne pozabite tudi, da je gostitelj hipervizorja kritična tarča. Ogrožen hipervizor lahko vidi vse goste. Posodabljajte gostitelj, ne le gostov. Navidezni strežnik vas ne odveže od posodabljanja gostitelja; poveča vložek, če to izpustite.

Opozorilo o hibridu: ne domnevajte, da vam vsebniki znotraj navideznega strežnika dajo 'dve plasti varnosti' zastonj. Navidezni strežnik doda mejo; vsebnik še vedno potrebuje ne-root, omejitev zmogljivosti in seccomp. V nasprotnem primeru je prva plast le tako močna kot najšibkejši vsebnik.

Štiri vprašanja, ki razrešijo debato v desetih minutah

Ne optimizirajte v abstraktnem. Zastavite si ta štiri vprašanja po vrstnem redu. Zapišite odgovore.

1. Do česa ima moj najemnik dostop? Če lahko najemnik doseže le svojo spletno aplikacijo in podatkovno bazo, so vsebniki na najemnika s strogimi omrežnimi pravili obrambni. Če so podatki najemnika regulirani ali finančno občutljivi, se pomaknite k navideznim strežnikom.

2. Koliko bi me stal ogroženost enega najemnika? Seštejte izgubljene stranke, pravno izpostavljenost in zaupanje. Če je število večje od stroškov upravljanja navideznih strežnikov, porabite denar. Če ne, so vsebniki racionalna izbira.

3. Koliko najemnikov imam in koliko plačujejo? Veliko majhnih naročnikov: pomembna je gostota vsebnikov. Peščica velikih računov: vsakemu dajte navidezni strežnik in temu primerno zaračunajte. Najemniki, ki vam plačajo manj kot kavo, ne bi smeli vsak zahtevati operacijskega sistema za upravljanje.

4. Ali lahko posodabljam stvari po urniku? Vsebniki si delijo eno jedro gostitelja, zato posodabljanje gostitelja ščiti vse. Navidezni strežniki pomnožijo število ciljev za posodabljanje. Če veste, da boste posodobitve preskakovali, izberite arhitekturo z manj gibljivimi deli in strožjimi privzetimi nastavitvami.

Vaši odgovori se bodo združili. Dva ali več odgovorov, osredotočenih na navidezne strežnike, pomeni, da ne bi smeli privzeto uporabljati vsebnikov na najemnika. Trije ali več odgovorov, osredotočenih na vsebnike, pomeni, da so navidezni strežniki preuranjeni. En kontraintuitiven rezultat: najemnik z nizkimi prihodki, ki ima dostop do občutljivih podatkov, še vedno potrebuje navidezni strežnik, ker regulativni stroški nimajo nobene zveze s tem, koliko plačuje.

Izdajte najmanj, čemur lahko zaupate, nato si prislužite več izolacije

Vaša prva arhitektura ni nujno vaša končna. Začnite z najtesnejšo nastavitvijo, ki jo dejansko lahko vzdržujete, nato dodajajte izolacijo, ko jo vaša baza najemnikov upravičuje. Za večino samostojnih operaterjev to pomeni vsebnike na najemnika z ne-root uporabnikom, omejenimi zmogljivostmi, datotečnimi sistemi samo za branje, seccomp in segmentacijo omrežja. Za regulirane ali visokovredne najemnike preskočite naravnost na en navidezni strežnik na najemnika, pri čemer so vsebniki le plast za pakiranje znotraj.

Karkoli izberete, zapišite odločitev in jo četrtletno ponovno preverite. Ko dobite prvo vprašanje 'ali bi tega najemnika preselili na navidezni strežnik?', boste imeli odgovor in kontrolni seznam, s katerim ga boste podprli. To dejansko pomeni izolacija: kompromis, ki ga upravljate, ne tehnologija, ki jo kupite.

Pred zagonom preverite naš praktični varnostni kontrolni seznam za izolacijo Docker – te odločitve spremeni v seznam, ki ga lahko preverite, preden stran prikažete stranki.

Sources (5)