Tinklaraštis

Kuriems klientams iš tikrųjų reikia nuosavos VM? Pakopinis Docker izoliavimo planas

VM kiekvienam klientui yra perteklius. Štai kaip nuspręsti, kiek izoliacijos reikia kiekvienam nuomininkui—ir automatizuoti sprendimą.

Santrauka

Agentūros dažnai panikuoja, kai klientas paklausia, kiek jų duomenys tikrai izoliuoti nuo kitų nuomininkų. Docker vardų erdvės (namespaces) ir cgroups suteikia realią izoliaciją, bet tai nėra tas pats, kas aparatinės įrangos riba. Užuot kiekvienam klientui paleidus VM—ar dar blogiau, traktavus kiekvieną klientą vienodai—sukurkite nedidelį izoliavimo pakopų rinkinį ir priskirkite kiekvieną klientą pagal duomenų jautrumą, pasitikėjimą ir atitiktį reikalavimams. Uždaras konteineris (ne root, atimtos galimybės, seccomp, tik skaitymo šaknis) padengia daugumą svetainių; reguliuojamos ar priešiškos darbo krūvio grupės gauna VM arba konteinerį VM hibridiniu būdu. Šis įrašas pateikia pakartojamą sprendimų eigą, palyginimo lentelę ir sąžiningą požiūrį į tai, kada didesnė izoliacija yra perteklinė.

Ar esate tame pardavimo skambučio taške, kai naujas klientas sako „mes sveikatos priežiūros įmonė, parodykite, kad mūsų duomenys izoliuoti nuo jūsų kitų klientų“ ir jūs verčiau kalbėtumėte apie bet ką kitą?

Tai agentūros problema: ne vienas tobulas diegimas, o tas pats patikimas diegimas, kartojamas per keliolika klientų su skirtingais biudžetais, rizikos profiliais ir atitikties reikalavimais. Štai sąžininga versija. Docker izoliacija yra reali, bet specifinė. Vardų erdvės suteikia kiekvienam konteineriui savo procesų, tinklo ir failų sistemos vaizdą; cgroups apriboja CPU, atmintį ir disko I/O, kad nuomininkai negalėtų vienas kito alinti. Ko tai nenupirks, tai aparatinės įrangos sienos tarp konteinerio ir pagrindinės OS branduolio. Jei užpuolikas pabėga iš konteinerio, jis yra vienintelio jūsų turimo branduolio viduje. Likusi šio straipsnio dalis paverčia tą nepatogų faktą pakartojamu sprendimu: klasifikuokite kiekvieną klientą pagal duomenų jautrumą ir pasitikėjimą, pritaikykite bazinį stiprinimo profilį ir griebkitės VM tik tada, kai pažeidimo kaina yra didesnė nei VM kaina.

Palaukite, ar konteineriai jau nėra izoliuoti?

Docker veikia Linux vardų erdvėse ir cgroups, ir tie žodžiai atlieka realų darbą. Vardų erdvės atskiria procesų ID, tinklo krūvas, prijungimo taškus ir vartotojus, kad vieno konteinerio procesas negalėtų matyti kito proceso lentelės. Cgroups nustato ribas: duokite konteineriui 0,5 CPU, 512 MB atminties ir fiksuotą blokų I/O svorį, ir tai tiksliai gausite. Vieno nuomininko nekontroliuojama kilpa yra prislopinama, o ne numuša kaimyną. Jei nesukonfigūravote ribų, praleidote pagrindinį dalyką, kuriam cgroups skirtos.

Paimkite paprastą PHP programą konteineryje A. Jis mato savo failų sistemą, savo tinklo sąsają, savo PID 1. Konteineris B turi tą patį, bet kitokį vaizdą. Tai vardų erdvės. Dabar nueikite ir praleiskite atminties limitą: konteineris A gali užpildyti pagrindinio kompiuterio RAM ir priversti B konteinerį šliaužti. Būtent tam ir skirtos cgroups. Tačiau du konteineriai gali būti izoliuoti vienas nuo kito vardų erdvėmis ir vis tiek dalytis pagrindinės OS branduoliu, o tai yra ta dalis, apie kurią pasakojama kiekviena konteinerio pabėgimo istorija. Išnaudojimas, pasiekiantis branduolį, gali pasiekti kiekvieną nuomininką tame pagrindiniame kompiuteryje.

„Docker yra izoliuotas“ yra pusiau teisingas sakinys. Tiksli versija yra „Docker izoliuoja naudodamas vardų erdves ir cgroups, o branduolio pažeidžiamumas yra smūgio spindulys.“ Prieš patikėdami nuomininkui vykdyti nepatikimą kodą, pagalvokite apie tai minutę. Atsakymas nėra „niekada nenaudoti konteinerių“—tai lengva panika. Atsakymas yra pakopų sistema.

Tai kodėl kai kuriems klientams reikia daugiau nei vardų erdvių?

Sąžiningas atsakymas yra tas, kad izoliacija nėra jungiklis, tai spektras. Viename gale turite visiškai bendrinamą konteinerį, kuriame visi efektyviai yra vienoje programoje. Kitame gale turite atskirą VM kiekvienam nuomininkui su savo branduoliu. Dauguma agentūrų darbų yra nepatogioje viduryje, o vidurys nėra dvejetainis pasirinkimas tarp „Docker yra gerai“ ir „paleiskite VM visiems“.

Kas stumia klientą į dešinę, yra ne jų dydis. Tai keturi klausimai:

  • Ar jie saugo reguliuojamus duomenis? Sveikatos įrašus, mokėjimo kortelių duomenis, bet ką, ką reguliatorius vadintų jautriu.
  • Ar jų nuomininko pažeidimas turi realų kelią į kitą nuomininką? Jei jie gali vykdyti savavališką kodą, taip.
  • Ar pasitikite kodu ir jį diegiančiais žmonėmis? Klientas, kuris samdo pigiausią laisvai samdomą darbuotoją, nėra toks pat pasitikėjimo lygis kaip klientas, kurio kūrėjų komandą pažįstate.
  • Ar jų sutartyje rašoma „skirta“, „izoliuota“ ar „privatu“? Jei taip, jūs jau pažadėjote pakopą; dabar belieka pasirinkti tinkamą.

Jei dar negalite atsakyti į šiuos klausimus, įtraukite klientą į bazinę pakopą ir užrašykite prielaidas. Tai ne saugumo auditas; tai proto patikra, kurią kartojate kiekvieno įtraukimo metu.

Kaip nuspręsti dėl kiekvieno kliento be saugumo audito kiekvieną kartą?

Padarykite nedidelę lentelę ir jos laikykitės. Jums nereikia matricos su keturiasdešimt langelių. Keturios pakopos padengs beveik kiekvieną agentūros matomą klientą.

Kliento padėtisKas iš tikrųjų juos skiriaNaudoti, kai
1 pakopa: bendrinama programa / konteinerisTik programos logikaVidaus paslaugos, mažos rizikos duomenys, projektai, kuriuose visi aiškiai yra vienoje prisijungimo sistemoje
2 pakopa: tas pats pagrindinis kompiuteris, atskiri konteineriaiVardų erdvės ir cgroupsDauguma rinkodaros svetainių, kontaktų formos, nėra jautrių duomenų
3 pakopa: užrakintas konteineris2 pakopa + ne root, atimtos galimybės, seccomp, tik skaitymo šaknis, tinklo segmentavimasEl. prekyba, asmens duomenys (PII), nestandartinis kodas, kuriuo ne visai pasitikite
4 pakopa: VM kiekvienam nuomininkuiHipervizorius ir atskiras branduolysSveikatos priežiūra, finansai, atitikties dokumentai, nepatikimas kodas, triukšmingi kaimynai

Štai kaip tai atrodo praktiškai. Kepyklos klientas su kontaktų forma ir „Instagram“ nuoroda patenka į 2 pakopą: vienas konteineris bendrame pagrindiniame kompiuteryje, numatytasis Docker tinklas, išteklių ribos, darbas atliktas. Internetinė parduotuvė, kuri saugo klientų vardus, adresus ir mokėjimo peradresavimus, patenka į 3 pakopą: tas pats bendras pagrindinis kompiuteris, bet konteineris veikia kaip ne root vartotojas, neturi papildomų branduolio galimybių, naudoja seccomp profilį ir atidengia tik 443 prievadą. Medicininės registracijos portalas, saugantis apsaugotą sveikatos informaciją, patenka į 4 pakopą: VM kiekvienam nuomininkui, nes pažeidimo kaina yra ne „išvalysime“, o „negaliame klientui parodyti, kad į juos žiūrime rimtai“.

Visa gudrybė ta, kad jūs nepergalvojate architektūros kiekvienam klientui. Jūs pasirenkate eilutę iš lentelės, dėl kurios jau susitarėte. Taip penkių žmonių agentūra gali valdyti šimtą svetainių be šimto atskirų saugumo manijų. Tai taip pat reiškia, kad kitas klientas negaus atsakymo, priklausančio nuo to, kuris komandos narys pakėlė ragelį. Dėl gilesnio architektūros debato, slypinčio už šių pasirinkimų, šis vadovas, kaip projektuoti kelių nuomininkų izoliavimo lygius, išsamiau aptaria kompromisus.

Kaip iš tikrųjų atrodo užrakintas konteineris?

Nustokime sakyti „užrakintas“ ir būkime konkretūs. Štai ką 3 pakopa reiškia tipiniam WordPress ar PHP klientui.

Pirma, pakeiskite vartotoją. Dauguma oficialių įvaizdžių vis dar pagal nutylėjimą veikia kaip root; savo Dockerfile sukurkite ne root vartotoją ir paleiskite programą kaip tą vartotoją. Tai iškart pašalina dažniausią būdą, kaip konteinerio pažeidimas tampa pagrindinio kompiuterio pažeidimu. Antra, atmeskite galimybes, kurių nereikia. Paleiskite su --cap-drop ALL ir grąžinkite tik vieną, paprastai NET_BIND_SERVICE, kad programa galėtų klausytis 80 prievade. Vien tai yra didesnis pakeitimas, nei dauguma tikisi. Trečia, padarykite šaknų failų sistemą tik skaitymui su --read-only, o rašomas katalogus (įkėlimus, duomenų bazės duomenų katalogą) prijunkite kaip tomus arba tmpfs. Ketvirta, pritaikykite seccomp profilį ir, jei jūsų pagrindinis kompiuteris palaiko, AppArmor arba SELinux. Galiausiai įdėkite konteinerį į atskirą Docker tinklą ir atidengkite tik tuos prievadus, kurie tikrai turi būti pasiekiami.

Peržiūrėkime WordPress pavyzdį. Bazinis įvaizdis tikriausiai veikia kaip root, todėl pridedate useradd žingsnį ir USER direktyvą. Paleidžiate konteinerį su atminties limitu ir CPU limitu, kad papildinio srauto šuolis nepakenktų kaimynui. Prijungiate /var/www/html/wp-content/uploads kaip rašomą tomą. Nustatote --read-only. Prisegate jį prie tinklo, kuriame nėra --privileged vėliavos. Rezultatas yra konteineris, kuris anksčiau buvo „WordPress svetainė“, o dabar yra „WordPress svetainė, kuri yra labiau užrakinta nei dauguma virtualių privačių serverių“.

Jei viso to rankinis darymas atrodo trapus, yra lengvesnis vidurio kelias: Docker patobulinta konteinerių izoliacija, kuri naudoja vartotojo vardų erdvių izoliaciją ir saugų konteinerių vykdymo laiką. Tai teisėtas sutrumpinimas, bet tai nėra laisvas bilietas praleisti ne root ar galimybių atmetimą. Nuomininkui vis tiek reikia protingo įvaizdžio. Skirtumas tas, kad į branduolį nukreiptas atakos paviršius sumažėja, nereikalaujant, kad per naktį taptumėte seccomp ekspertu. Jei norite tikslios vieno nuomininko sekos, nuoseklus izoliavimo stiprinimo vadovas paverčia šią sekciją kopijavimo-įklijavimo komandomis.

Kada nustoju sluoksniuoti ir tiesiog įteikiu jiems VM?

Čia yra prieštaringa dalis: didesnė izoliacija nėra automatiškai geriau. VM suteikia aparatinės įrangos lygio izoliaciją, atskirą branduolį ir daug mažesnį atakos paviršių, jei svečio branduolys krinta. Būtent to sveikatos priežiūros ir finansų klientai tikisi sakydami „norime būti izoliuoti“. Bet kiekviena VM prideda pataisymų, atsarginių kopijų ir skaičiavimo išlaidų bei padaugina darbą, reikalingą palaikyti flotilę atnaujintą. Jei VM kiekvienam klientui todėl, kad vienas klientas kadaise pasakė, jog Docker juos gąsdina, nusipirkote saugumo teatrą už tikrus pinigus.

VM yra teisingas atsakymas, kai rizika vienam nuomininkui yra didesnė nei VM eksploatacinės išlaidos vienam nuomininkui. Tai reiškia reguliuojamus duomenis, rašytinius atitikties reikalavimus, nepatikimą trečiosios šalies kodą arba klientą, kuriam reikia pašalinti triukšmingą kaimyną. Tai taip pat teisingas atsakymas, kai kliento sutartis tiesiogine prasme žada atskirą aplinką, nes „konteineris“ nėra tai, ką jie įsivaizduoja pasirašydami „skirta“.

Bet VM nepateisina aplaidaus konteinerio. Dažni spąstai yra įdėti klientą į VM ir tada praleisti stiprinimą, nes „VM juos apsaugo“. VM apsaugo pagrindinį kompiuterį nuo nuomininko, o ne nuomininką nuo jo paties blogo įvaizdžio. Jums vis tiek reikia ne root, atimtų galimybių ir seccomp toje VM viduje. Hibridinis metodas—konteineriai VM viduje—dažnai yra saldžiausia vieta: VM suteikia ribą atitikties pokalbiams, o konteineris suteikia diegimo darbo eigą, kurią jau žinote. Ilgesnė to debato versija yra Ar kiekvienas nuomininkas turėtų gauti savo VM?, bet trumpas atsakymas yra tas, kad VM yra sutarčiai, o ne baimei.

Kaip tai padaryti pakartojama visiems klientams?

Tai padarote pakartojama, paversdami pakopų sistemą šablonu, o ne atmintimi. Laikykite Compose failų katalogą, po vieną kiekvienai pakopai: tier2-baseline, tier3-locked, tier4-vm-hybrid. Kai pasirodo naujas klientas, nukopijuokite šabloną, pakeiskite aplinkos kintamuosius ir jau žinote izoliacijos formą, neparašę nė vienos naujos infrastruktūros eilutės.

Tada užrašykite sprendimą. Ne 400 puslapių saugumo ataskaitą, o trumpą pastraipą kliento saugykloje: kokius duomenis jie saugo, kokioje pakopoje yra, kodėl ir kas juos perkeltų į aukštesnę pakopą. Ta pastraipa verta daugiau nei šimtas užkardos taisyklių, nes tai dalykas, kurį galite parodyti kitam auditoriui ar kitam susirūpinusiam klientui. Tai taip pat neleidžia jums prisiminti, kodėl kepyklai skirta 2 pakopa, o el. prekybos parduotuvei—3 pakopa, po to, kai pirminis pardavimo skambutis išblėso.

Automatizuokite nuobodžius patikrinimus. Paprašykite, kad jūsų CI nuskaitytų kiekvieno kliento įvaizdį ir nepavyktų kūrimas, jei jis veikia kaip root, jei turi visas galimybes arba jei bando paskelbti prievadą, kuris nėra leidžiamas pakopoje. Nė vienas iš tų dalykų nėra egzotiškas; tai tiesiog užtikrinimas, kad šablonas netyčia nesugadintas geranoriško kūrėjo. Jei vis tiek kuriate supančią talpinimo darbo eigą, paruošto gamybai Docker talpinimo strategijų įrašas apima dalį, kuri ateina po konteinerių apibrėžimo.

Nieko iš to nėra žavingo. Joks tinklaraščio įrašas nepadarys „nuomininko izoliacijos“ skambančios taip įdomiai, kaip žalio lauko architektūros diagrama. Bet tai skirtumas tarp agentūros, kuri į klausimą „kiek mes izoliuoti?“ atsako sukryžiavus pirštus „visiškai“, ir tokios, kuri gali parodyti pakopą, konfigūraciją ir priežastį. Konteineriai nėra stebuklinga siena. VM nėra stebuklinga kulka. Pakopų sistema yra tik sprendimas, kurį užrašote ir naudojate pakartotinai—o agentūrai pakartojamumas yra visas žaidimas.

Sources (5)