Tinklaraštis
Ar kiekvienam nuomininkui reikia atskiros VM?
Pasirinkite tarp konteinerių kiekvienam nuomininkui, VM ir hibridinių sąrankų, naudodamiesi rizika pagrįstu sprendimų modeliu ir stiprinimo žingsniais, kad kiekvienas variantas būtų gintinas.
Santrauka
Daugianuominė priegloba verčia pasirinkti, kaip toli nuomininkai gali pasiekti vienas kitą. Konteineriuose procesai ir ištekliai izoliuojami naudojant Linux namespaces ir cgroups, tačiau jie dalijasi pagrindinio kompiuterio branduoliu. Virtualios mašinos prideda aparatinės įrangos lygmens ribą, tačiau tai kainuoja greitį ir eksploatacinę naštą. Hibridinis metodas – konteineriai VM viduje – gali suteikti abu, bet padvigubina paviršių, kurį turite pataisyti. Šiame straipsnyje nagrinėjame rizika pagrįstą sprendimą, palyginimą greta ir Docker stiprinimo žingsnius, kurie svarbūs net ir VM viduje. Galiausiai žinosite, kuris izoliacijos modelis tinka jūsų nuomininkams ir ką sukonfigūruoti prieš paleidimą.
Jūsų daugianuomenė programa beveik paruošta. Turite Docker Compose failą, kuris kiekvienam klientui paleidžia atskirą rinkinį, ir tai greita. Tada draugas, valdantis prieglobos įmonę, klausia: „Ar kiekvienam nuomininkui suteikiate atskirą VM?“ Jūs sustingstate. Jūs neplanavote šio klausimo. Šis straipsnis suteikia jums būdą į jį atsakyti šiandien, be saugumo komandos. Tai darote vieni, todėl sprendimas turi būti pakankamai paprastas, kad galėtumėte jį apginti 2 valandą nakties.
Nustokite ieškoti „geriausio“ modelio. Pradėkite užsirašydami, kas atsitiks, jei nuomininko kodas perims jūsų pagrindinį kompiuterį. Apibrėžkite sprogimo spindulį prieš pasirinkdami bet kokį įrankį. Šis pratimas jums pasakys daugiau nei bet koks etaloninis testas.
Branduolys – kambariokas, kurio negalite iškelti
Konteinerių efektyvumas pagrįstas tuo, kad jie dalijasi pagrindinio kompiuterio branduoliu. Tas dalijimasis yra visas triukas ir visa rizika. Linux namespaces suteikia kiekvienam konteineriui savo procesų, tinklo ir failų sistemos vaizdą. Control groups (cgroups) leidžia riboti CPU, atmintį ir disko I/O, kad vienas nuomininkas neišstumtų kitų. Tačiau nė vienas iš jų nesukuria aparatinės įrangos sienos.
Įsivaizduokite konteinerį kaip procesą su labai geru netikru asmens dokumentu. Jis tiki, kad yra savo pačio mašinoje. Tačiau branduolys yra viena Linux kopija, veikianti jūsų pagrindiniame kompiuteryje. Jei nuomininkas išnaudoja branduolio pažeidžiamumą, namespaces tampa tik metaduomenimis. Atakuojantis asmuo, galintis iškviesti branduolio funkcijas, gali pasiekti kitas namespaces tame pačiame branduolyje. Tai yra konteinerio pabėgimas, apie kurį nuolat girdite.
Tarkime, talpinate nedidelį B2B įrankį su vienu konteineriu kiekvienam klientui. Klientas įdiegia įtartiną papildinį su nuotolinio kodo vykdymo spraga. Naudojant numatytuosius Docker nustatymus, tas procesas konteineryje veikia kaip root. Root konteineryje vis tiek yra UID 0, o branduolys neskiria šio UID nuo pagrindinio kompiuterio root, jei aiškiai nesuprojektavote vartotojų. Atakuojantis asmuo gali bandyti pabėgti, o bendras branduolys yra jo taikinys.
Nesėkmė neturi būti dramatiška. Vieno nuomininko atminties nuotėkis gali nustumti pagrindinį kompiuterį į swap, sulėtindamas visus kitus nuomininkus. Be cgroup apribojimų, viena netinkamai veikianti kilpa yra prieinamumo ataka. Su jais - tai blokuojamas procesas ir aliarmas.
Ar tai reiškia, kad konteineriai nesaugūs? Ne. Tai reiškia, kad į branduolį turite žiūrėti kaip į bendrą pasitikėjimo zoną. Prieš rinkdamiesi surašykite vienos pastraipos rizikos pareiškimą: „Jei nuomininko konteineris yra pažeistas, atakuojantis asmuo gali pasiekti: [list]. Verslo nuostoliai būtų: [amount or impact].“ Jei ši pastraipa jus gąsdina, nesate paranojiškas. Esate sąžiningas.
Norėdami giliau pažvelgti į izoliacijos spektrą – nuo bendrų konteinerių iki visiškai atskirų rinkinių – žr. mūsų vadovą apie daugianuomenės Docker architektūros kūrimą.
Trys būdai tai padalyti (pasirinkite vieną prieš diegdami)
Iš tikrųjų yra trys daugianuomenės izoliacijos architektūros. Kiekviena „geriausia praktika“ yra šių derinys.
| Metodas | Izoliacijos barjeras | Kada geriausiai tinka | Sunkiausias įspėjimas |
|---|---|---|---|
| Konteineriai kiekvienam nuomininkui | Branduolio namespaces + cgroups | Daug mažų nuomininkų, maža rizika vienam nuomininkui, reikia tankio | Vienas branduolio išnaudojimas gali sugriauti visus to pagrindinio kompiuterio nuomininkus |
| Viena VM nuomininkui | Hipervizoriaus/aparatinės įrangos virtualizacija | Reguliuojami duomenys, priešiški nuomininkai, didelė vertė vienam nuomininkui | Sunkesnis, lėčiau provisioninamas, kiekvienam nuomininkui reikia taisyti OS |
| Konteineriai VM viduje | VM riba aplink konteinerizuotus darbo krūvius | Tankumas ir kietas apvalkalas tarp grupių | Išlaidos ir eksploatacinės sąnaudos beveik dvigubėja |
Konteineriai kiekvienam nuomininkui. Tai yra numatytasis pasirinkimas daugeliui SaaS įkūrėjų. Kiekvienas nuomininkas gauna savo konteinerį arba nedidelį Compose rinkinį. Provisioninimas yra akimirksniu, vaizdai maži, CI/CD paprastas. Išteklių apribojimai neleidžia triukšmingiems kaimynams suėsti serverio. Kompromisas – bendras branduolys. Jei galite išlaikyti darbo krūvius neprivilegijuotus ir reguliariai taisyti pagrindinį kompiuterį, tai dažnai yra teisingas pirmas žingsnis.
Nedėkite dviejų nuomininkų į tą patį konteinerį. Tai bendras branduolys, bendra vykdymo aplinka ir bendra failų sistema. Jei vienas nuomininkas įkelia failą, kuris sukuria procesą, kitas nuomininkas jau yra toje pačioje procesų lentelėje. Konteineris yra jūsų izoliacijos vienetas; laikykitės vieno nuomininko viename konteineryje.
O kaip duomenų bazė? Jei kiekvienas nuomininkas prisijungia prie vienos MongoDB ar PostgreSQL egzemplioriaus su tais pačiais prisijungimo duomenimis, jau pridėjote didelį bendrą komponentą. Suteikite kiekvienam nuomininkui atskirus prisijungimo duomenis, o idealu – atskirą duomenų bazę ar schemą. Konteineriai izoliuoja programą; duomenų bazė dažnai yra pirmasis nuotėkis, kurį atakuojantis asmuo išbandys.
Viena VM nuomininkui. Kiekvienam nuomininkui suteikite pilną virtualią mašiną. Hipervizorius prideda aparatinės įrangos lygmens ribą, kurią turi peržengti branduolio išnaudojimas, kad pasiektų pagrindinį kompiuterį. Tai svarbu reguliuojamoje aplinkoje arba kai nuomininkai nėra patikimi. Kaina – tankumas ir laikas. Dabar valdote operacinių sistemų parką, o ne tik konteinerius. Kiekvienai VM reikia atnaujinimų, saugos agentų ir stebėjimo. Vienam įkūrėjui tai tikras darbas.
Šiame lygmenyje veikiantys modeliai: naudokite infrastruktūrą kaip kodą, kad sukurtumėte VM iš to paties pagrindinio vaizdo, įdėkite atnaujinimus į naujus vaizdus, o ne taisykite veikiančias sistemas, ir nutraukite neatpažintus darbo krūvius. Laikykite VM valdymo prievadą uždarytą nuo interneto.
Konteineriai VM viduje. Šis hibridas retai aptariamas pradedančiųjų pamokose. Kiekvienam nuomininkui (ar nedidelei nuomininkų grupei) sukuriate mažą VM, o tada toje VM paleidžiate konteinerius. VM yra sprogimo spindulio konteineris; konteineriai – tik diegimo vienetai. Tai suteikia virtualizacijos kietą kraštą ir vaizdų atkuriamumą. Tai kainuoja daugiau, nes mokate už virtualizacijos pridėtinę naštą ir konteinerių lankstumą, tačiau tai gali būti protingiausias ilgalaikis modelis, kai negalite visiškai pasitikėti nuomininkais.
Dažnas mikro pavyzdys: nuomininkas vykdo Node API ir fono darbuotoją. Vietoj vieno didelio konteinerio su abiem procesais naudokite vieną VM, tada du konteinerius su skirtingais išteklių apribojimais, bendru tinklu ir be tiesioginio interneto prieigos darbuotojui. VM suteikia kietą kraštą; konteineriai – struktūrą.
Kurį turėtumėte pasirinkti? Lentelė yra jūsų trumpasis sąrašas. Tolesni skyriai paverčia sprendimą konkrečiu.
Jei renkatės konteinerius, atlikite šiuos šešis žingsnius arba nesivarginkite
Konteineriai kiekvienam nuomininkui yra tinkami, jei į kiekvieną konteinerį žiūrite kaip į potencialų atakuotoją. Tai prasideda nuo konfigūracijos, o ne noro tikėtis geriausio.
0. Apribokite išteklius prieš pasitikėdami kuo nors. Cgroups yra sąžiningumo mechanizmas ir prieinamumo gynyba. Nustatykite --memory ir --cpus kiekvienam konteineriui. Nuomininkas, iš kurio teka atmintis, turėtų atsitrenkti į savo limitą, o ne į jūsų serverį. Tai nėra saugumo riba, bet triukšmingas kaimynas yra ataka be nė vienos kodo eilutės. Praktiška pradžia: --memory 512m --cpus 0.5. Darbuotojo procesui pradėkite nuo mažesnių ir didinkite.
1. Vykdykite kaip ne root vartotojas. Niekada neleiskite konteinerio procesui naudoti UID 0, nebent to tikrai reikia. Nustatykite vartotoją Dockerfile ir pridėkite --user kaip papildomą apsaugą. Išnaudojimas, veikiantis kaip neprivilegijuotas vartotojas, turi daug mažiau kelių į branduolį. Savo Dockerfile sukurkite vartotoją: RUN useradd -u 10001 app ir USER app. Nepraleiskite šio žingsnio, kad sutaupytumėte laiko.
2. Pašalinkite visas nereikalingas galimybes (capabilities). Linux galimybės padalija root galią į mažas dalis. Daugumai žiniatinklio programų beveik jų nereikia. Pradėkite nuo --cap-drop=ALL ir pridėkite tik tai, ko tikrai reikia. Konteineris be CAP_SYS_ADMIN yra daug sunkiau panaudojamas namespace gudrybėms. Jei jūsų programa bando prisijungti prie privilegijuoto prievado, paleiskite ją aukštame prievade ir įdiekite tarpinį serverį, o ne suteikite NET_BIND_SERVICE.
3. Padarykite failų sistemą tik skaitoma. Jūsų programa neturėtų rašyti į savo konteinerio sluoksnį. Prijunkite tmpfs būsenai. Atakuojantis asmuo, negalintis rašyti į diską, turės daug sunkiau įdiegti atkaklumą. Pažeista PHP programa, bandanti įrašyti žiniatinklio apvalkalą, žlugs, kai pagrindinė failų sistema yra tik skaitoma. Galite prijungti pavadintą tomą katalogui, į kurį jūsų programai tikrai reikia rašyti.
4. Taikykite seccomp ir AppArmor arba SELinux. Jie nukreipia rizikingus sistemos iškvietimus į šiukšlių krūvą. Docker pateikia numatytąjį seccomp profilį; naudokite jį. Pridėkite AppArmor profilį kaip dar vieną sluoksnį. Jums nereikia išmanyti kiekvieno sistemos iškvietimo. Turite uždrausti tai, ko normalus žiniatinklio darbuotojas niekada nereikalauja. Niekada nenaudokite --privileged. Ši vėliavėlė išjungia beveik visą apsaugą, kurią ką tik nustatėte.
5. Segmentuokite tinklą. Nesuteikite kiekvienam konteineriui maršruto į kiekvieną kitą konteinerį. Pagal nutylėjimą uždrauskite, tada atidarykite tik tuos prievadus, kurių reikia. Pažeistas duomenų bazės konteineris neturėtų galėti nuskaityti jūsų administravimo skydelio. Jei nuomininkai yra atskiruose tinkluose, pažeidimas viename tinkle negali plisti šoniniu judėjimu.
Praktiška pradžia:
docker run --user 10001 --cap-drop=ALL --security-opt no-new-privileges --read-only --tmpfs /tmp:rw,size=64M --security-opt seccomp=default.json --memory 512m --cpus 0.5 myimage
Įdėkite tas pačias vėliavėles į Compose failą ir pritaikykite jas kiekvienam nuomininkui. Tai nėra išsamu, bet daug stipresnis numatytasis variantas nei tai, ką docker run suteikia iš karto.
Išsamesniam peržiūrėjimui naudokitės mūsų nuosekliu Docker konteinerių stiprinimo vadovu daugianuomenėje priegloboje.
Docker patobulinta konteinerių izoliacija – išimtis, kurią turėtumėte žinoti
Jei dirbate valdomoje Docker aplinkoje, ieškokite Docker patobulintos konteinerių izoliacijos (ECI). Jis naudoja vartotojo vardų erdvės izoliaciją ir saugų konteinerių vykdymo laiką. Root konteineryje susieta su neprivilegijuotu vartotoju pagrindiniame kompiuteryje, todėl net konteineris, veikiantis kaip root, negauna pagrindinio kompiuterio root teisių. Jis taip pat blokuoja pavojingas galimybes ir sistemos iškvietimus pagal nutylėjimą. To negalima atkurti keliomis vėliavėlėmis standartiniame Docker. Jei jūsų platforma tai palaiko, įjunkite. Tai nepašalina poreikio naudoti ne root vartotojus ir išteklių apribojimus, bet keičia rizikos skaičiavimą.
Dalį to galite atkartoti su vartotojo vardų erdvės permapinimu (userns-remap) Docker demono nustatymuose. Tai nėra taip išsamu kaip saugus vykdymo laikas, bet geriau nei nieko. Jei naudojate, patikrinkite, ar UID atvaizdavimas veikia, prieš tuo pasitikėdami.
VM klaidinga nuomonė: perėjimas prie virtualių mašinų nėra stiprinimas
Čia yra prieštaringa dalis, kurią dauguma žmonių praleidžia. Jei pereinate prie vienos VM nuomininkui ir tada joje diegiate savo įprastus konteinerius, nepašalinote konteinerių saugumo problemos. Pridėjote platų narvelį. Konteinerio pabėgimas vis tiek veikia; atakuojantis asmuo tiesiog atsiduria VM, o ne pagrindiniame kompiuteryje. Tai tikras pagerėjimas, bet vis tiek reikia tų šešių žingsnių.
Kitas spąstas – manyti, kad pati VM yra saugi. Numatytasis vaizdas su silpnu SSH slaptažodžiu, nepataisytais pagrindiniais paketais ar atviru valdymo prievadu yra dovana. Hipervizoriaus riba svarbi tik tada, jei svečio sistema yra sustiprinta ir atnaujinta. Priešingu atveju jūsų „saugi VM“ yra greitesnis kelias į kompromitaciją, nes jaučiatės saugūs ir nustojate tikrinti.
Ką VM jums suteikia – tai sumažinamas sprogimo spindulys. Vieno nuomininko nelaimė lieka vienoje VM. Ką tai kainuoja – jūsų laiką. Jūs tampate sistemų administratoriumi tiek operacinių sistemų, kiek turite nuomininkų. Jei esate vienas įkūrėjas, kuriantis produktą, paklauskite savęs, ar turite valandų pataisyti ir stebėti parką. Jei taip, VM kiekvienam nuomininkui gali būti teisingas sprendimas. Jei ne, konteineriai su stipriu stiprinimu gali būti sąžiningesni.
Taip pat atminkite, kad hipervizoriaus pagrindinis kompiuteris yra kritinis taikinys. Kompromitavus hipervizorių, galima matyti visus svečius. Taisykite pagrindinį kompiuterį, ne tik svečius. VM neatleidžia nuo pagrindinio kompiuterio taisymo; tai padidina įkainius, jei to praleidžiate.
Atsargumas dėl hibrido: nemanykite, kad konteineriai VM viduje automatiškai suteikia „du saugumo sluoksnius“ už dyką. VM prideda ribą; konteineriui vis tiek reikia ne root, galimybių apribojimų ir seccomp. Priešingu atveju pirmasis sluoksnis yra tik tiek stiprus, kiek silpniausias konteineris.
Keturi klausimai, kurie išsprendžia ginčą per dešimt minučių
Neoptimizuokite abstrakčiai. Užduokite sau šiuos keturis klausimus eilės tvarka. Užsirašykite atsakymus.
1. Prie ko mano nuomininkas turi prieigą? Jei nuomininkas gali pasiekti tik savo žiniatinklio programą ir duomenų bazę, konteineriai kiekvienam nuomininkui su griežtomis tinklo taisyklėmis yra gintini. Jei nuomininko duomenys yra reguliuojami arba finansiškai jautrūs, judėkite link VM.
2. Kiek kainuotų vieno nuomininko kompromitacija? Suskaičiuokite prarastus klientus, teisinę riziką ir pasitikėjimą. Jei skaičius didesnis nei VM eksploatacijos kaina, išleiskite pinigus. Jei ne, konteineriai yra racionalus pasirinkimas.
3. Kiek turiu nuomininkų ir kiek jie moka? Daug mažų prenumeratorių: konteinerių tankis svarbus. Sauja didelių sąskaitų: kiekvienam suteikite VM ir atitinkamai apmokestinkite. Nuomininkai, mokantys mažiau nei kava, neturėtų reikalauti atskiros OS administravimui.
4. Ar galiu pataisyti pagal grafiką? Konteineriai dalijasi vienu pagrindinio kompiuterio branduoliu, todėl taisant pagrindinį kompiuterį apsaugomi visi. VM padaugina jūsų taisymo taikinius. Jei žinote, kad praleisite atnaujinimus, rinkitės architektūrą su mažiau judančių dalių ir griežtesniais numatytaisiais nustatymais.
Jūsų atsakymai susiklosčius. Du ar daugiau atsakymų, orientuotų į VM, reiškia, kad neturėtumėte pagal nutylėjimą rinktis konteinerių kiekvienam nuomininkui. Trys ar daugiau atsakymų, orientuotų į konteinerius, reiškia, kad VM yra per ankstyvos. Vienas kontrargumentas: mažas pajamas nešantis nuomininkas, turintis prieigą prie jautrių duomenų, vis tiek reikalauja VM, nes reguliavimo sąnaudos neturi nieko bendra su jo mokama suma.
Išleiskite mažiausiai, kuo galite pasitikėti, tada užsidirbkite daugiau izoliacijos
Jūsų pirmoji architektūra neturi būti galutinė. Pradėkite nuo griežčiausios sąrankos, kurią iš tikrųjų galite prižiūrėti, tada pridėkite izoliaciją, kai jūsų nuomininkų bazė tai pateisins. Daugumai pavienių operatorių tai reiškia konteinerius kiekvienam nuomininkui su ne root, apribotomis galimybėmis, tik skaitoma failų sistema, seccomp ir tinklo segmentavimu. Reguliuojamiems arba didelės vertės nuomininkams iškart pereikite prie vienos VM vienam nuomininkui, konteinerius naudodami tik kaip pakavimo sluoksnį viduje.
Kad ir ką pasirinktumėte, užsirašykite sprendimą ir peržiūrėkite jį kas ketvirtį. Kai gausite pirmąjį klausimą „ar turėtume perkelti šį nuomininką į VM?“, turėsite atsakymą ir sąrašą, kuriuo galėsite pagrįsti. Tai iš tikrųjų reiškia izoliacija: kompromisas, kurį valdote, o ne technologija, kurią perkate.
Prieš paleidimą peržiūrėkite mūsų praktinį Docker izoliacijos saugumo kontrolinį sąrašą – jis paverčia šiuos sprendimus sąrašu, kurį galite patikrinti prieš parodydami puslapį klientui.

