Blog

Koji klijenti zapravo trebaju vlastitu VM? Plan izolacije u razinama za Docker

VM za svakog klijenta je pretjerano. Evo kako odlučiti koliko izolacije svaki najmoprimac treba – i automatizirati odluku.

Sažetak

Agencije često paničare kad klijent pita koliko su njihovi podaci doista izolirani od drugih najmoprimaca. Dockerovi namespaces i cgroups pružaju stvarnu izolaciju, ali to nije isto što i hardverska granica. Umjesto da svakog klijenta stavite na VM – ili još gore, da se prema svima ponašate isto – izgradite mali skup razina izolacije i svakog klijenta uskladite s jednom od njih prema osjetljivosti podataka, povjerenju i usklađenosti. Container s čvrstim ograničenjima (non-root, uklonjene capabilities, seccomp, read-only root) pokriva većinu web-mjesta; regulirani ili neprijateljski workloadovi dobivaju VM ili hibridnu kombinaciju container-unutar-VM-a. Ovaj post daje ponovljiv slijed odlučivanja, tablicu usporedbe i iskren pogled na to kada je veća izolacija pretjerana.

Jeste li ikad na prodajnom pozivu kad novi klijent kaže „u zdravstvu smo, pokažite mi da su naši podaci izolirani od vaših ostalih klijenata”, a vi radije biste pričali o bilo čemu drugom?

To je problem agencija: ne radi se o jednom savršenom postavljanju, već o istom pouzdanom postavljanju koje se ponavlja na desetak klijenata s različitim proračunima, profilima rizika i zahtjevima usklađenosti. Evo iskrene verzije. Docker izolacija je stvarna, ali specifična. Namespaces daju svakom containeru vlastiti pogled na procese, mrežu i datotečni sustav; cgroups ograničavaju CPU, memoriju i disk I/O tako da najmoprimci ne mogu izgladnjivati jedni druge. Ono što to ne kupuje jest hardverski zid između containera i kernela domaćina. Ako napadač pobjegne iz containera, unutra je u jedinom kernelu koji imate. Ostatak ovog članka pretvara tu neugodnu činjenicu u ponovljivu odluku: razvrstajte svakog klijenta prema osjetljivosti podataka i povjerenju, primijenite osnovni profil otvrdnjavanja i posegnite za VM-om samo kad je cijena proboja veća od cijene VM-a.

Čekaj, zar containeri već nisu izolirani?

Docker radi na Linux namespaces i cgroups, a te riječi rade stvaran posao. Namespaces razdvajaju ID-jeve procesa, mrežne stogove, točke montiranja i korisnike tako da proces u jednom containeru ne može vidjeti tablicu procesa drugog. Cgroups postavljaju ograničenja: dajte containeru 0,5 CPU-a, 512 MB memorije i fiksnu težinu blok I/O-a, i to će točno i dobiti. Problematična petlja u jednom najmoprimcu biva ograničena umjesto da sruši susjeda. Ako niste konfigurirali ograničenja, preskočili ste najosnovniju stvar za koju cgroups služe.

Uzmite jednostavnu PHP aplikaciju u containeru A. Ona vidi vlastiti datotečni sustav, vlastito mrežno sučelje, vlastiti PID 1. Container B ima isto, ali drugačiji pogled. To su namespaces. Sada se udaljite i preskočite ograničenje memorije: container A može ispuniti RAM domaćina i učiniti da container B jedva radi. To je ono što cgroups treba spriječiti. Ali dva containera mogu biti izolirana jedan od drugog namespace-ima i još uvijek dijeliti kernel domaćina, što je dio svake priče o bijegu iz containera. Exploit koji dosegne kernel može doseći potencijalno svakog najmoprimca na tom domaćinu.

„Docker je izoliran” je napola istinita rečenica. Točna verzija glasi: „Docker izolira pomoću namespaces i cgroups, a ranjivost kernela je radijus eksplozije.” Prije nego što povjerite najmoprimcu da pokreće nepouzdani kod, zadržite se na toj misli minutu. Odgovor nije „nikad ne koristite containere” – to je laka panika. Odgovor je sustav razina.

Zašto neki klijenti trebaju više od namespaces?

Iskren odgovor je da izolacija nije prekidač, već spektar. Na jednom kraju imate potpuno dijeljeni container u kojem su svi zapravo u jednoj aplikaciji. Na drugom kraju imate zasebnu VM po najmoprimcu s vlastitim kernelom. Većina agencijskog posla živi u neugodnoj sredini, a sredina nije binarni izbor između „Docker je ok” i „pokrenite VM za sve”.

Što klijenta gura udesno nije njegova veličina. To su četiri pitanja:

  • Čuvaju li regulirane podatke? Zdravstvene kartone, podatke o platnim karticama, bilo što što bi regulator nazvao osjetljivim.
  • Ima li proboj na njihovom najmoprimcu realističan put do drugog najmoprimca? Ako mogu izvršavati proizvoljni kod, da.
  • Povjeravate li se kodu i ljudima koji ga postavljaju? Klijent koji unajmi najjeftinijeg freelancera nije ista razina povjerenja kao klijent čiji dev tim poznajete.
  • Kaže li njihov ugovor „dedicated”, „izolirano” ili „privatno”? Ako kaže, već ste obećali razinu; jedini posao sada je odabrati pravu.

Ako još ne možete odgovoriti na ta pitanja, stavite klijenta u osnovnu razinu i zapišite pretpostavke. To nije sigurnosna revizija; to je provjera zdravog razuma koju ponavljate pri svakom uključivanju.

Kako odlučiti po klijentu bez provođenja sigurnosne revizije svaki put?

Napravite malu tablicu i držite je se. Ne trebate matricu s četrdeset ćelija. Četiri razine pokrit će gotovo svakog klijenta koje agencija vidi.

Pozicija klijentaŠto ih zapravo razdvajaKoristi se kada
Razina 1: Dijeljena aplikacija/containerIsključivo logika aplikacijeInterne usluge, podaci niskog rizika, projekti gdje su svi izričito u jednom sustavu prijave
Razina 2: Isti domaćin, zasebni containeriNamespaces i cgroupsVećina marketinških web-mjesta, kontaktni obrasci, nema osjetljivih podataka
Razina 3: Container s čvrstim ograničenjimaRazina 2 + non-root, uklonjene capabilities, seccomp, read-only root, mrežna segmentacijaE-trgovina, PII, prilagođeni kod kojem ne vjerujete u potpunosti
Razina 4: VM po najmoprimcuHipervizor i zaseban kernelZdravstvo, financije, dokumenti o usklađenosti, nepouzdani kod, bučni susjedi

Evo kako to izgleda u praksi. Klijent pekara s kontakt obrascima i Instagram vezom ide na Razinu 2: jedan container na dijeljenom domaćinu, zadano Docker mrežno povezivanje, ograničenja resursa, posao obavljen. Online trgovina koja pohranjuje imena kupaca, adrese i preusmjeravanja plaćanja ide na Razinu 3: isti dijeljeni domaćin, ali container radi kao non-root korisnik, nema dodatnih kernel capabilities, koristi seccomp profil i izlaže samo port 443. Medicinski portal za unos koji pohranjuje zaštićene zdravstvene informacije ide na Razinu 4: VM po najmoprimcu, jer cijena proboja nije „očistit ćemo to” nego „ne možemo klijentu pokazati da smo ga ozbiljno shvatili”.

Cijeli trik je u tome da ne preispitujete arhitekturu za svakog klijenta. Birate redak iz tablice o kojoj ste se već dogovorili. Tako agencija od pet ljudi može voditi stotinu web-mjesta bez stotinu zasebnih sigurnosnih opsesija. To također znači da sljedeći klijent neće dobiti odgovor koji ovisi o tome koji je član tima podignuo slušalicu. Za dublju arhitektonsku raspravu o tim odlukama, ovaj vodič o dizajniranju razina izolacije za više najmoprimaca detaljnije pokriva te kompromise.

Kako zapravo izgleda container s čvrstim ograničenjima?

Prestanimo govoriti „čvrsto ograničen” i budimo konkretni. Ovo znači Razina 3 za tipičnog WordPress ili PHP klijenta.

Prvo, promijenite korisnika. Većina službenih slika i dalje po zadanim postavkama radi kao root; u svom Dockerfileu stvorite non-root korisnika i pokrenite aplikaciju kao taj korisnik. To odmah uklanja najčešći način na koji kompromitacija containera postaje kompromitacija domaćina. Drugo, uklonite capabilities koje ne trebate. Pokrenite s --cap-drop ALL i vratite samo jednu, obično NET_BIND_SERVICE kako bi aplikacija mogla slušati na portu 80. Već to je veća promjena nego što većina ljudi očekuje. Treće, učinite root datotečni sustav samo za čitanje s --read-only i montirajte zapisive direktorije (uploads, direktorij baze podataka) kao volumene ili tmpfs. Četvrto, primijenite seccomp profil i, ako vaš domaćin to podržava, AppArmor ili SELinux. Na kraju, stavite container na namjensku Docker mrežu i izložite samo portove koji stvarno moraju biti dostupni.

Prođimo kroz WordPress primjer. Osnovna slika vjerojatno radi kao root, pa dodajete korak useradd i direktivu USER. Pokrenete container s ograničenjem memorije i CPU-a, tako da nalet prometa od dodataka ne šteti susjedu. Montirate /var/www/html/wp-content/uploads kao zapisivi volumen. Postavite --read-only. Priključite ga na mrežu koja nema zastavicu --privileged nigdje u blizini. Rezultat je container koji je nekad bio „WordPress web-mjesto”, a sada je „WordPress web-mjesto koje je čvršće ograničeno od većine virtualnih privatnih poslužitelja”.

Ako vam se ručno sastavljanje svega toga čini krhkim, postoji lakši srednji put: Dockerova Enhanced Container Isolation, koja koristi izolaciju korisničkih namespace-ova i sigurno izvođenje containera. To je legitimni prečac, ali nije besplatna propusnica za preskakanje non-root ili uklanjanja capabilities. Najmoprimac i dalje treba razumnu sliku. Razlika je u tome što se površina napada okrenuta kernelu smanjuje bez da preko noći postanete stručnjak za seccomp. Ako želite točan slijed za jednog najmoprimca, vodič za otvrdnjavanje izolacije korak po korak pretvara ovaj odjeljak u copy-paste naredbe.

Kada prestajem s dodavanjem slojeva i jednostavno im dajem VM?

Ovdje je kontroverzni dio: veća izolacija nije automatski bolja. VM-ovi vam daju izolaciju na razini hardvera, zaseban kernel i mnogo manju površinu napada ako padne gostujući kernel. To je točno ono što klijenti iz zdravstva i financija očekuju kada kažu „želimo biti izolirani.” No svaka VM dodaje trošak zakrpa, sigurnosnih kopija i računalnih resursa te umnožava posao održavanja flote ažurnim. Ako svakog klijenta stavite na VM jer vam je jedan klijent jednom rekao da ga Docker plaši, kupili ste sigurnosno kazalište za pravi novac.

VM je pravi odgovor kada je rizik po najmoprimca veći od operativnog troška VM-a po najmoprimcu. To znači regulirani podaci, pisani zahtjevi usklađenosti, nepouzdani kod treće strane ili klijent kojem treba ukloniti bučnog susjeda. To je također pravi odgovor kada klijentov ugovor doslovno obećava namjensko okruženje, jer „container” nije ono što oni zamišljaju kada potpisuju „dedicated”.

Ali VM ne opravdava aljkav container. Česta zamka je staviti klijenta u VM, a zatim preskočiti otvrdnjavanje jer „VM ih štiti.” VM štiti domaćina od najmoprimca, ne najmoprimca od njegove vlastite loše slike. I dalje želite non-root, uklonjene capabilities i seccomp unutar tog VM-a. Hibridni pristup – containeri unutar VM-a – često je idealno rješenje: VM pruža granicu za razgovore o usklađenosti, a container vam daje radni tijek implementacije koji već poznajete. Dulja verzija te rasprave nalazi se u Treba li svaki najmoprimac dobiti vlastitu VM?, ali kratki odgovor je da je VM za ugovor, a ne za strah.

Kako ovo učiniti ponovljivim među svim klijentima?

To činite ponovljivim tako da sustav razina učinite predloškom, a ne sjećanjem. Držite direktorij Compose datoteka, jednu po razini: tier2-baseline, tier3-locked, tier4-vm-hybrid. Kad se pojavi novi klijent, kopirajte predložak, promijenite varijable okoline i već znate oblik izolacije prije nego što napišete i jedan redak nove infrastrukture.

Zatim zapišite odluku. Ne sigurnosno izvješće od 400 stranica, već kratki odlomak u klijentovom repozitoriju: koje podatke pohranjuju, na kojoj su razini, zašto i što bi ih pomaknulo na višu razinu. Taj odlomak vrijedi više od stotinu pravila vatrozida, jer je to ono što možete pokazati sljedećem revizoru ili sljedećem zabrinutom klijentu. Također vas sprječava da morate pamtiti zašto je pekara dobila Razinu 2, a e-trgovina Razinu 3 nakon što je izvorni prodajni poziv izblijedio.

Automatizirajte dosadne provjere. Neka vaš CI skenira svaku sliku klijenta i prekine gradnju ako se izvodi kao root, ako ima sve capabilities ili ako pokušava objaviti port koji nije među dopuštenima za tu razinu. Ništa od toga nije egzotično; to je samo osiguravanje da predložak nije slučajno slomio dobronamjerni developer. Ako već gradite okolni radni tijek hostinga, članak o produkcijski spremnim Docker hosting strategijama pokriva dio koji dolazi nakon što su containeri definirani.

Ništa od ovoga nije glamurozno. Nijedan blog post neće učiniti da „izolacija najmoprimaca” zvuči uzbudljivo poput dijagrama greenfield arhitekture. Ali to je razlika između agencije koja na pitanje „koliko smo izolirani?” odgovara držeći palčeve „potpuno” i one koja može pokazati razinu, konfiguraciju i razlog. Containeri nisu čarobni zid. VM-ovi nisu čarobni metak. Sustav razina samo je odluka koju zapišete i ponovno koristite – a za agenciju je ponovljivost cijela igra.

Sources (5)