Blog
Past zaupanja: Kako je naša večnajemniška nastavitev Docker povzročila uhajanje podatkov (in kako smo to odpravili)
Naučite se, kako je naivna nastavitev Dockerja ene ekipe privedla do uhajanja podatkov med najemniki in kako je plastovita strategija izolacije to preprečila.
Povzetek
Zabojniki Docker privzeto niso izolirani – delijo jedro gostitelja in brez premišljene konfiguracije lahko najemniki vplivajo drug na drugega. Ta članek opisuje resničen scenarij, kjer je ponudnik večnajemniškega gostovanja odkril, da so zabojniki strank lahko dostopali do podatkovnih baz drugih strank zaradi skupnega omrežja in šibkih varnostnih privzetkov. Pokažemo postopne spremembe, ki so odpravile kršitev: uporabniško določena omrežja na najemnika, uporabniki brez korenskih pravic, odstranjene zmožnosti, bralno-pisalni datotečni sistemi in profili seccomp. Pogosta predpostavka je, da zabojniki samodejno zagotavljajo močno izolacijo; to izzovemo s pojasnilom, zakaj navidezni stroji še vedno nudijo trdnejšo mejo in kdaj razmisliti o hibridnem pristopu. Sklep poudarja, da je izolacija plastovita vaja, ne enoten potrditveni okvir.
Incident: Ko zabojniki preveč govorijo
Na enem samem gostitelju ste nastavili Docker za poganjanje več spletnih mest strank. Vsaka stranka ima svoj zabojnik – urejeno, izolirano okolje, kajne? Tako smo mislili tudi mi. Dokler rutinska varnostna revizija ni razkrila, da je zabojnik stranke A bral MySQL priključek zabojnika stranke B na istem gostitelju. Uporabljala sta privzeto omrežje bridge. Še huje, zabojniki so delovali kot korenski uporabnik, zato je napadalec, ki je ogrozil enega, lahko posegal v Docker priključek gostitelja ali datotečni sistem drugega zabojnika. Kršitev ni bila sofisticiran napad; šlo je za osnovno napačno konfiguracijo. Podatki so uhajali. Zaupanje je izginilo.
Scenarij napake ni redek. Mnoge ekipe predpostavljajo, da Dockerjeva imenska okolja in cgroups samodejno ločijo najemnike, vendar podcenjujejo, koliko izhodov v sili ostaja odprtih privzeto. Privzeta omrežja bridge ne nudijo omrežne izolacije med zabojniki. Delovanje kot korenski uporabnik daje zabojniku več moči, kot je potrebno. In brez izrecnih omejitev virov lahko en hrupni sosed drugim odvzame CPU ali pomnilnik.
1. korak: Nehajte deliti eno samo omrežje
Naša prva rešitev je bila dati vsakemu najemniku lastno uporabniško določeno omrežje Docker. To preprečuje, da bi zabojniki dosegli drug drugega, razen če jih izrecno povežete. Ustvarili smo skript, ki za vsakega najemnika vzpostavi namensko omrežje in nanj pripne njihov aplikacijski zabojnik. Podatkovna baza živi v istem omrežju najemnika, dodali pa smo tudi notranje omrežje samo za komunikacijo znotraj najemnika. Brez več vmešavanja med najemniki.
Podatkovne baze smo tudi izolirali tako, da jih poganjamo v ločenih zabojnikih na istem omrežju najemnika z uporabo ločenih podatkovnih nosilcev. To je zagotovilo, da tudi če napadalec vdre v aplikacijski zabojnik, ne more prestrezati prometa podatkovne baze drugega najemnika.
Za poglobljen pogled v strategije omrežne izolacije si oglejte Praktični varnostni kontrolni seznam Docker izolacije za večnajemniško gostovanje.
2. korak: Odstranite nepotrebna pooblastila
Privzeto zabojniki Docker delujejo z omejenim naborom zmožnosti Linuxa, vendar imajo še vedno več, kot večina aplikacij potrebuje. Naši zabojniki so delovali kot korenski uporabnik, kar je procesom v notranjosti omogočalo dejanja, kot je priklop datotečnih sistemov ali spreminjanje parametrov jedra. Preklopili smo na poganjanje aplikacije kot ne-korenski uporabnik znotraj zabojnika (z uporabo direktive USER v Dockerfile) in odstranili vse zmožnosti razen tistih, ki so nujno potrebne. Za tipično spletno aplikacijo so to morda le NET_BIND_SERVICE (za vezavo na vrata pod 1024) in CHOWN (za pisanje v imenike). Dodali smo tudi --security-opt no-new-privileges za preprečevanje dviga pooblastil.
Že ta korak je odpravil številne pogoste vektorje pobega iz zabojnika. Napadalec, ki ogrozi spletni strežnik, ne more namestiti paketov, spreminjati sistemskih binarnih datotek ali dostopati do Docker priključka gostitelja, ker procesu manjkajo zmožnosti CAP_SYS_ADMIN ali CAP_DAC_OVERRIDE.
3. korak: Zaklenite datotečni sistem
Zapisljivi datotečni sistemi so pogosta napadalna površina. Korenski datotečni sistem smo naredili samo za branje (--read-only) za vse zabojnike, nato pa priklopili začasne datotečne sisteme (tmpfs) za imenike, ki potrebujejo pisalni dostop, kot sta /tmp in predpomnilniški imenik aplikacije. To preprečuje napadalcu spreminjanje aplikacijske kode ali ohranjanje zlonamerne binarne datoteke.
Poleg tega smo uporabili Dockerjevo možnost --mount za priklop občutljivih imenikov, kot je Docker priključek, le kadar je nujno potrebno – in nikoli na produkcijskih zabojnikih. Načelo: če zabojnik ne potrebuje pisanja na pot, naj bo samo za branje.
4. korak: Uporabite profila seccomp in AppArmor
Privzeti profili seccomp že blokirajo mnoge nevarne sistemske klice, vendar smo jih dodatno prilagodili, da dovolimo le tiste sistemske klice, ki jih naša aplikacija dejansko potrebuje. To je kompromis, saj zahteva profiliranje aplikacije. Preprostejši pristop je uporaba privzetega profila seccomp Dockerja in nato dodajanje --security-opt seccomp=pot/do/profila.json, če potrebujete strožja pravila. Podobno lahko profili AppArmor omejijo procese zabojnika na določene datotečne poti in zmožnosti. Omogočili smo AppArmor in uporabili po meri profil, ki je omejil dostop le na podatkovne imenike aplikacije.
Za celovit vodnik po teh korakih utrjevanja si oglejte Utrjevanje Docker zabojnikov za večnajemniško gostovanje: Vodnik po korakih za izolacijo.
Nasprotni pogled: Včasih potrebujete navidezne stroje
Ne glede na utrjevanje zabojniki delijo jedro gostitelja. Ranljivost jedra lahko naenkrat prekine vso izolacijo. Zato mnoge varnostno ozaveščene platforme poganjajo zabojnike znotraj lahkih navideznih strojev – vsak najemnik dobi svoje jedro. To dodaja režijo, vendar zagotavlja mejo na ravni strojne opreme, ki je zabojniki sami ne morejo. Če vaši najemniki obdelujejo podatke kreditnih kartic ali zdravstvene evidence, je hibridni pristop (zabojniki znotraj VM) morda prava izbira. Ne predpostavljajte, da je izolacija zabojnikov zadostna za vaš model groženj; ocenite občutljivost podatkov in regulativne zahteve.
Za poglobljeno primerjavo ravni izolacije preberite Načrtovanje večnajemniške Docker arhitekture: Izbira prave ravni izolacije.
Sklep: Izolacija je sklad, ne stikalo
Popravek ni bila ena sama sprememba – bilo je plastenje: omrežna izolacija, omejena pooblastila, bralno-pisalni datotečni sistemi in filtriranje sistemskih klicev. Tudi takrat smo sprejeli, da je popolna izolacija z zabojniki, ki delijo jedro, nemogoča. Za naše najbolj varnostno občutljive najemnike smo jih premaknili na namenske gostitelje. Naučili smo se: ne zaupajte privzetim nastavitvam. Revidirajte svojo Docker nastavitev, kot da je do kršitve že prišlo. Čas za zaklepanje je pred uhajanjem, ne po njem.


