Tinklaraštis

Pasitikėjimo klaidingumas: kaip mūsų kelių nuomininkų Docker sąranka nutekino duomenis (ir kaip mes tai ištaisėme)

Sužinokite, kaip vienos komandos naivi Docker sąranka lėmė tarpnuomininko duomenų nutekėjimą ir kokia sluoksniuota izoliacijos strategija tai ištaisė.

Santrauka

„Docker“ konteineriai pagal numatytuosius nustatymus nėra izoliuoti – jie dalijasi pagrindine sistema, o be apgalvotos konfigūracijos nuomininkai gali trukdyti vienas kitam. Šis straipsnis aprašo realų scenarijų, kai kelių nuomininkų prieglobos paslaugų teikėjas atrado, kad klientų konteineriai gali pasiekti vienas kito duomenų bazes dėl bendro tinklo ir silpnų saugumo numatytųjų nustatymų. Mes parodome nuoseklius pakeitimus, kurie ištaisė pažeidimą: kiekvieno nuomininko vartotojo apibrėžti tinklai, ne root vartotojai, atsisakyti gebėjimai, tik skaityti failų sistemos ir seccomp profiliai. Dažna prielaida, kad konteineriai savaime suteikia stiprią izoliaciją; mes tai ginčijame paaiškindami, kodėl VM vis dar siūlo tvirtesnę ribą ir kada verta apsvarstyti hibridinį metodą. Išvada pabrėžia, kad izoliacija yra sluoksniuotas procesas, o ne vienas žymimasis langelis.

Incidentas: kai konteineriai per daug kalbasi

Jūs nustatėte „Docker“ viename pagrindiniame kompiuteryje, kad paleistumėte kelias klientų svetaines. Kiekvienas klientas turi savo konteinerį – tvarkingą, izoliuotą aplinką, tiesa? Taip manėme ir mes. Kol įprastinis saugumo auditas atskleidė, kad Kliento A konteineris skaito Kliento B konteinerio „MySQL“ lizdą tame pačiame pagrindiniame kompiuteryje. Jie dalijosi numatytuoju bridge tinklu. Dar blogiau, konteineriai veikė kaip root, todėl užpuolikas, įsilaužęs į vieną, galėjo manipuliuoti pagrindinio kompiuterio „Docker“ lizdu ar kito konteinerio failų sistema. Pažeidimas nebuvo sudėtingas išnaudojimas – tai buvo pagrindinė neteisinga konfigūracija. Duomenys nutekėjo. Pasitikėjimas išgaravo.

Nesėkmės scenarijus nėra retas. Daugelis komandų mano, kad „Docker“ vardų erdvės ir cgrupės automatiškai atskiria nuomininkus, tačiau jie neįvertina, kiek pabėgimo liukų lieka atvirais pagal numatytuosius nustatymus. Numatytieji „bridge“ tinklai nesiūlo tinklo izoliacijos tarp konteinerių. Veikimas kaip root suteikia konteineriui daugiau galių nei reikia. O be aiškių išteklių ribų vienas triukšmingas kaimynas gali atimti CPU ar atmintį iš kitų.

1 veiksmas: nustokite dalintis vienu tinklu

Pirmas mūsų pataisymas buvo suteikti kiekvienam nuomininkui savo vartotojo apibrėžtą „Docker“ tinklą. Tai neleidžia konteineriams pasiekti vienas kito, nebent aiškiai juos prijungsite. Mes sukūrėme scenarijų, kuris kiekvienam nuomininkui sukuria skirtą tinklą ir prie jo prijungia jų programos konteinerį. Duomenų bazės konteineris gyvena tame pačiame nuomininko tinkle, bet mes taip pat pridėjome vidinį tinklą tik nuomininkų komunikacijai. Daugiau jokio tarpnuomininko žvalgymosi.

Mes taip pat izoliavome duomenų bazes, paleisdami jas atskiruose konteineriuose tame pačiame nuomininko tinkle, naudodami atskirus duomenų tomus. Tai užtikrino, kad net jei užpuolikas įsilaužtų į programos konteinerį, jis negalėtų nuskaityti kito nuomininko duomenų bazės srauto.

Norėdami išsamiau susipažinti su tinklo izoliacijos strategijomis, žiūrėkite Praktinis „Docker“ izoliacijos saugumo kontrolinis sąrašas kelių nuomininkų prieglobai.

2 veiksmas: atsisakykite nereikalingų privilegijų

Pagal numatytuosius nustatymus „Docker“ konteineriai veikia su ribotu „Linux“ galimybių rinkiniu, tačiau jie vis tiek turi daugiau, nei dauguma programų reikalauja. Mūsų konteineriai veikė kaip root, o tai leido procesams viduje atlikti veiksmus, pvz., prijungti failų sistemas ar keisti branduolio parametrus. Mes perėjome prie programos paleidimo kaip ne root vartotojo konteineryje (naudojant USER direktyvą „Dockerfile“) ir atsisakėme visų galimybių, išskyrus tas, kurios būtinai reikalingos. Įprastai žiniatinklio programai tai gali būti tik NET_BIND_SERVICE (prievadams, mažesniems nei 1024, prijungti) ir CHOWN (rašymui į katalogus). Taip pat pridėjome --security-opt no-new-privileges, kad užkirstume kelią privilegijų eskalavimui.

Vien šis žingsnis pašalino daugelį įprastų konteinerių pabėgimo vektorių. Užpuolikas, įsilaužęs į žiniatinklio serverį, negali įdiegti paketų, modifikuoti sistemos dvejetainių failų ar pasiekti pagrindinio kompiuterio „Docker“ lizdo, nes procesui trūksta CAP_SYS_ADMIN arba CAP_DAC_OVERRIDE galimybių.

3 veiksmas: užrakinkite failų sistemą

Rašomos failų sistemos yra dažnas atakos paviršius. Mes padarėme šakninę failų sistemą tik skaitymui (--read-only) visiems konteineriams, o tada prijungėme laikinas failų sistemas (tmpfs) katalogams, kuriems reikia rašymo prieigos, pvz., /tmp ir programos talpyklos katalogui. Tai neleidžia užpuolikui modifikuoti programos kodo ar išlaikyti kenkėjiškų dvejetainių failų.

Be to, mes naudojome „Docker“ --mount parinktį, kad prijungtume jautrius katalogus, pvz., „Docker“ lizdą, tik kai tai būtina – ir niekada gamybos konteineriuose. Principas: jei konteineriui nereikia rašyti į kelią, padarykite jį tik skaitymui.

4 veiksmas: pritaikykite seccomp ir AppArmor profilius

Numatytieji seccomp profiliai jau blokuoja daug pavojingų sisteminių iškvietimų, bet mes juos dar labiau pritaikėme, įtraukdami į baltąjį sąrašą tik tuos sistemos iškvietimus, kurių mūsų programai tikrai reikia. Tai kompromisas, nes reikalauja profiliuoti programą. Paprastesnis būdas yra naudoti numatytąjį „Docker“ seccomp profilį ir pridėti --security-opt seccomp=path/to/profile.json, jei reikia griežtesnių taisyklių. Panašiai, AppArmor profiliai gali apriboti konteinerio procesus iki konkrečių failų kelių ir galimybių. Mes įjungėme AppArmor ir naudojome pasirinktinį profilį, kuris apribojo prieigą tik prie programos duomenų katalogų.

Išsamų šių stiprinimo žingsnių vadovą rasite „Docker“ konteinerių stiprinimas kelių nuomininkų prieglobai: žingsnis po žingsnio izoliacijos vadovas.

Priešinga nuomonė: kartais jums reikia VM

Kad ir koks stiprintas, konteineriai dalijasi pagrindinės sistemos branduoliu. Branduolio pažeidžiamumas gali sugriauti visą izoliaciją vienu metu. Todėl daugelis saugumą suvokiančių platformų paleidžia konteinerius lengvų VM viduje – kiekvienas nuomininkas gauna savo branduolį. Tai prideda papildomų sąnaudų, bet suteikia aparatinės įrangos lygio ribą, kurios vieni konteineriai negali pasiekti. Jei jūsų nuomininkai tvarko kredito kortelių duomenis ar sveikatos įrašus, hibridinis metodas (konteineriai VM viduje) gali būti teisingas sprendimas. Nelaikykite konteinerių izoliacijos pakankama jūsų grėsmės modeliui; įvertinkite duomenų jautrumą ir reguliavimo reikalavimus.

Norėdami išsamiau palyginti izoliacijos lygius, skaitykite Kelių nuomininkų „Docker“ architektūros kūrimas: tinkamo izoliacijos lygio pasirinkimas.

Išvada: izoliacija yra krūva, o ne jungiklis

Pataisymas nebuvo vienas pakeitimas – tai buvo sluoksniavimas: tinklo izoliacija, ribotos privilegijos, tik skaitymui failų sistemos ir sisteminių iškvietimų filtravimas. Net ir tada mes pripažinome, kad tobula izoliacija neįmanoma su bendra branduolio konteineriais. Savo aukščiausio saugumo nuomininkus perkėlėme į dedikuotus pagrindinius kompiuterius. Pamoka: nepasitikėkite jokiais numatytaisiais nustatymais. Auditiruokite savo „Docker“ sąranką taip, lyg pažeidimas jau būtų įvykęs. Laikas užrakinti yra prieš nuotėkį, o ne po jo.

Sources (5)