Блог

Zabluda poverenja: Kako je naša multi-tenant Docker postavka procurila podatke (i kako smo to popravili)

Saznajte kako je naivna Docker postavka jednog tima dovela do curenja podataka između tenanta i slojevita strategija izolacije koja ga je sprečila.

Sažetak

Docker kontejneri nisu izolovani podrazumevano—dele kernel hosta, i bez namerne konfiguracije, tenanti mogu ometati jedni druge. Ovaj članak prolazi kroz stvarni scenario gde je pružalac multi-tenant hostinga otkrio da klijentski kontejneri mogu pristupiti bazama podataka jedni drugih zbog deljenog umrežavanja i slabih sigurnosnih podrazumevanih postavki. Prikazujemo korak-po-korak promene koje su popravile proboj: mreže definisane od strane korisnika po tenantima, ne-root korisnici, odbačene mogućnosti, samo za čitanje fajl sistemi i seccomp profili. Uobičajena pretpostavka je da kontejneri inherentno pružaju jaku izolaciju; mi to izazivamo objašnjavajući zašto VM i dalje nude čvršću granicu i kada razmotriti hibridni pristup. Zaključak naglašava da je izolacija slojevita vežba, a ne jedan checkbox.

Incident: Kada kontejneri previše pričaju

Podesili ste Docker na jednom hostu da pokrećete više klijentskih veb sajtova. Svaki klijent ima svoj kontejner—uredno, izolovano okruženje, zar ne? To smo i mi mislili. Dok rutinska sigurnosna revizija nije otkrila da kontejner klijenta A čita MySQL socket kontejnera klijenta B na istom hostu. Delili su podrazumevanu bridge mrežu. Još gore, kontejneri su pokretani kao root, tako da je napadač koji je kompromitovao jedan mogao da petlja sa Docker socketom hosta ili fajl sistemom drugog kontejnera. Proboj nije bio sofisticirani exploit; bila je to osnovna pogrešna konfiguracija. Podaci su procurili. Poverenje je nestalo.

Scenarij neuspeha nije neuobičajen. Mnogi timovi pretpostavljaju da Docker imenski prostori i cgroups automatski odvajaju tenante, ali potcenjuju koliko izlaznih otvora ostaje otvoreno podrazumevano. Podrazumevane bridge mreže ne nude mrežnu izolaciju između kontejnera. Pokretanje kao root daje kontejneru više snage nego što je potrebno. A bez eksplicitnih ograničenja resursa, jedan bučni sused može uskratiti CPU ili memoriju drugima.

Korak 1: Prestanite deliti jednu mrežu

Naš prvi popravak je bio da svakom tenantu damo sopstvenu Docker mrežu definisanu od strane korisnika. Ovo sprečava kontejnera da dopru jedan do drugog osim ako ih eksplicitno ne povežete. Kreirali smo skriptu koja za svakog tenanta pokreće namensku mrežu i prikačuje njihov aplikacioni kontejner na nju. Kontejner baze podataka živi u istoj mreži tenanta, ali smo dodali i internu mrežu samo za komunikaciju unutar tenanta. Nema više mešanja između tenanta.

Takođe smo izolovali baze podataka pokretanjem u odvojenim kontejnerima na istoj mreži tenanta, koristeći odvojene volumene podataka. Ovo je osiguralo da čak i ako napadač prodre u aplikacioni kontejner, ne može da šmrče saobraćaj baze podataka drugog tenanta.

Za dublje poniranje u strategije mrežne izolacije, pogledajte Praktični Docker izolacioni sigurnosni kontrolni spisak za multi-tenant hosting.

Korak 2: Odustanite od nepotrebnih privilegija

Podrazumevano, Docker kontejneri se pokreću sa ograničenim skupom Linux mogućnosti, ali i dalje imaju više nego što je većini aplikacija potrebno. Naši kontejneri su pokretani kao root, što je omogućavalo procesima unutar da izvode radnje kao što su montiranje fajl sistema ili menjanje kernelskih parametara. Prešli smo na pokretanje aplikacije kao ne-root korisnik unutar kontejnera (koristeći USER direktivu u Dockerfile-u) i odbacili sve mogućnosti osim onih koje su apsolutno potrebne. Za tipičnu veb aplikaciju, to mogu biti samo NET_BIND_SERVICE (za vezivanje portova ispod 1024) i CHOWN (za pisanje u direktorijume). Takođe smo dodali --security-opt no-new-privileges da sprečimo eskalaciju privilegija.

Ovaj korak je sam eliminisao mnoge uobičajene vektore bekstva iz kontejnera. Napadač koji kompromituje veb server ne može da instalira pakete, modifikuje sistemske binarne datoteke ili pristupi Docker socketu hosta jer procesu nedostaju mogućnosti CAP_SYS_ADMIN ili CAP_DAC_OVERRIDE.

Korak 3: Zaključajte fajl sistem

Zapisivi fajl sistemi su uobičajena napadačka površina. Učinili smo koreni fajl sistem samo za čitanje (--read-only) za sve kontejnere, a zatim montirali privremene fajl sisteme (tmpfs) za direktorijume kojima je potreban pristup za pisanje, kao što su /tmp i keš direktorijum aplikacije. Ovo sprečava napadača da modifikuje kod aplikacije ili trajno postavi zlonamerne binarne datoteke.

Dodatno, koristili smo Docker --mount opciju za bind-mount osetljivih direktorijuma poput Docker socketa samo kada je apsolutno neophodno—i nikada na produkcijskim kontejnerima. Princip: ako kontejner ne treba da piše na putanju, učinite je samo za čitanje.

Korak 4: Primenite Seccomp i AppArmor profile

Podrazumevani seccomp profili već blokiraju mnoge opasne sistemske pozive, ali smo ih dodatno prilagodili da dozvolimo samo one sistemske pozive koje naša aplikacija stvarno koristi. Ovo je kompromis jer zahteva profilisanje aplikacije. Jednostavniji pristup je koristiti Docker-ov podrazumevani seccomp profil, a zatim dodati --security-opt seccomp=path/to/profile.json ako su potrebna stroža pravila. Slično, AppArmor profili mogu ograničiti procese kontejnera na specifične putanje datoteka i mogućnosti. Omogućili smo AppArmor i koristili prilagođeni profil koji je ograničio pristup samo direktorijumima sa podacima aplikacije.

Za sveobuhvatan vodič o ovim koracima ojačavanja, pogledajte Ojačavanje Docker kontejnera za multi-tenant hosting: Vodič korak po korak za izolaciju.

Suprotstavljeni pogled: Ponekad su vam potrebne VM

Bez obzira koliko ojačani, kontejneri dele kernel hosta. Ranjivost kernela može odjednom slomiti svu izolaciju. Zbog toga mnoge sigurnosno svesne platforme pokreću kontejnere unutar laganih VM—svaki tenant dobija sopstveni kernel. Ovo dodaje režijske troškove, ali pruža granicu na nivou hardvera koju kontejneri sami ne mogu. Ako vaši tenanti rukuju podacima o kreditnim karticama ili zdravstvenim kartonima, hibridni pristup (kontejneri unutar VM) može biti pravi izbor. Ne pretpostavljajte da je izolacija kontejnera dovoljna za vaš model pretnje; procenite osetljivost podataka i regulatorne zahteve.

Za dublje poređenje nivoa izolacije, pročitajte Dizajniranje multi-tenant Docker arhitekture: Odabir pravog nivoa izolacije.

Zaključak: Izolacija je stek, a ne prekidač

Popravak nije bila jedna promena—bilo je slojevanje: mrežna izolacija, ograničene privilegije, samo za čitanje fajl sistemi i filtriranje sistemskih poziva. Čak i tada, prihvatili smo da je savršena izolacija nemoguća sa kontejnerima koji dele kernel. Za naše najsigurnosnije tenante, preselili smo ih na namenske hostove. Lekcija: ne verujte podrazumevanim postavkama. Revidirajte svoju Docker postavku kao da se proboj već dogodio. Vreme za zaključavanje je pre curenja, a ne posle.

Sources (5)