Blog
Minden bérlő kapjon saját VM-et?
Válasszon a bérlőnkénti konténerek, VM-ek és hibrid megoldások között kockázatalapú döntési keretrendszerrel, valamint a megerősítési lépésekkel, amelyek mindegyik opciót védhetővé teszik.
Összefoglalás
A több-bérlős üzemeltetés arra kényszeríti, hogy eldöntse, milyen mélyen érhetnek el a bérlők egymásba. A konténerek Linux-névtereket és cgroupokat használnak a folyamatok és erőforrások elkülönítésére, de osztoznak a gazdagép kernelén. A virtuális gépek hardveres határt adnak, a sebesség és az üzemeltetési terhelés árán. A hibrid megközelítés – konténerek VM-ekben – mindkettőt megadhatja, de megduplázza a javítandó felületet. Ez a cikk végigvezeti egy kockázatalapú döntésen, egy oldalirányú összehasonlításon és a Docker-megerősítési lépéseken, amelyek VM-en belül is fontosak. A végére tudni fogja, melyik elkülönítési modell illik a bérlőihez, és mit kell beállítani indulás előtt.
A több-bérlős alkalmazása majdnem kész. Van egy Docker Compose fájlja, amely ügyfelenként egy stacket indít, és gyors. Aztán egy barátja, aki tárhelycéget vezet, megkérdezi: „Minden bérlőnek saját VM-et ad?” Lefagy. Nem tervezte ezt a kérdést. Ez a cikk egy módot ad arra, hogy még ma válaszoljon rá, biztonsági csapat nélkül. Ezt egyedül csinálja, így a döntésnek elég egyszerűnek kell lennie ahhoz, hogy hajnali 2-kor is meg tudja védeni.
Hagyjon fel a „legjobb” modell keresésével. Kezdje azzal, hogy leírja, mi történik, ha egy bérlő kódja átveszi az irányítást a gazdagép felett. Határozza meg a robbanási sugarat, mielőtt bármilyen eszközt kiválaszt. Ez a gyakorlat többet fog mondani, mint bármely benchmark.
A kernel az a lakótárs, akit nem lehet kilakoltatni
A konténerek azért hatékonyak, mert megosztják a gazdagép kernelét. Ez a megosztás az egész trükk és az egész kockázat. A Linux-névterek minden konténernek saját nézetet adnak a folyamatokról, a hálózatról és a fájlrendszerről. A control groupok (cgroupok) lehetővé teszik a CPU, memória és lemez I/O korlátozását, így egy bérlő nem éheztetheti ki a többieket. De egyik sem teremt hardverfalat.
Gondoljon egy konténerre úgy, mint egy folyamatra, amelyik nagyon jó hamis igazolvánnyal rendelkezik. Azt hiszi, hogy a saját gépén van. A kernel viszont egyetlen Linux-példány, amely a gazdagépen fut. Ha egy bérlő kernel-sérülékenységet aknáz ki, a névterek nem mások, mint metaadatok. Egy támadó, aki kernel-függvényeket tud hívni, elérheti a többi névteret ugyanazon a kernelen. Ez az a konténerszökés, amiről folyamatosan hallani.
Tegyük fel, hogy egy kis B2B eszközt üzemeltet, ügyfelenként egy konténerrel. Egy ügyfél telepít egy gyanús bővítményt, amelyben távoli kódfuttatási hiba van. Az alapértelmezett Docker-beállításokkal ez a folyamat rootként fut a konténerben. A root a konténerben továbbra is UID 0, és a kernel nem különbözteti meg ezt a UID-t a gazdagép rootjától, hacsak nem jeleníti meg explicit módon a felhasználókat. A támadó megpróbálhat kiszabadulni, és a megosztott kernel a célpont.
A meghibásodásnak nem kell drámainak lennie. Egyetlen bérlő memóriaszivárgása a gazdagépet swapre kényszerítheti, lelassítva az összes többi bérlőt. Cgroup-korlátok nélkül egy rosszul viselkedő hurok rendelkezésreállás-támadás. Velük viszont blokkolt folyamat és riasztás.
Ez azt jelenti, hogy a konténerek nem biztonságosak? Nem. Azt jelenti, hogy a kernelt megosztott bizalmi zónaként kell kezelni. Mielőtt választ, írjon egy bekezdésnyi kockázati nyilatkozatot: „Ha egy bérlő konténere sérül, a támadó hozzáférhet: [list]. Az üzleti költség: [amount or impact].” Ha ez a bekezdés megijeszti, nem paranoiás. Őszinte.
Az elkülönítési spektrum mélyebb megértéséhez, a megosztott konténerektől a teljesen különálló stackekig, tekintse meg útmutatónkat a több-bérlős Docker-architektúra tervezéséről.
Három módja a felosztásnak (Válasszon egyet a telepítés előtt)
Valójában három architektúra létezik a több-bérlős elkülönítéshez. Minden „legjobb gyakorlat” ezek kombinációja.
| Megközelítés | Elkülönítési határ | Legjobb, ha | Legnehezebb buktató |
|---|---|---|---|
| Bérlőnkénti konténerek | Kernel-névterek + cgroupok | Sok kicsi bérlő, bérlőnként alacsony kockázat, sűrűségre van szükség | Egy kernel-kihasználás minden bérlőt megbuktathat azon a gazdagépen |
| Egy VM bérlőnként | Hypervisor/hardver-virtualizáció | Szabályozott adatok, ellenséges bérlők, magas érték bérlőnként | Nehezebb, lassabb a kiosztás, bérlőnként egy operációs rendszert kell javítania |
| Konténerek VM-ekben | VM-határ a konténerizált munkaterhelések körül | Sűrűség plusz egy kemény héj a csoportok között | A költségek és az üzemeltetési terhek majdnem megduplázódnak |
Bérlőnkénti konténerek. Ez a legtöbb SaaS-alapító alapértelmezése. Minden bérlő saját konténert vagy kis Compose stacket kap. A kiosztás azonnali, a lemezképek kicsik, a CI/CD egyszerű. Az erőforrás-korlátok megakadályozzák, hogy a zajos szomszédok felfalják a szervert. A kompromisszum a megosztott kernel. Ha a munkaterheléseket nem-privilegizáltként tudja tartani, és rendszeresen javítja a gazdagépet, ez gyakran a helyes első lépés.
Ne tegyen két bérlőt ugyanabba a konténerbe. Az megosztott kernel, megosztott futási környezet és megosztott fájlrendszer. Ha egy bérlő feltölt egy fájlt, amely folyamatot hoz létre, a másik bérlő már ugyanabban a folyamattáblában van. A konténer az elkülönítés egysége; tartson egy bérlőt konténerenként.
Mi van az adatbázissal? Ha minden bérlő ugyanazokkal a hitelesítő adatokkal csatlakozik egy MongoDB vagy PostgreSQL példányhoz, máris hozzáadott egy hatalmas megosztott összetevőt. Adjon minden bérlőnek külön hitelesítő adatokat, és ideálisan külön adatbázist vagy séma. A konténerek elkülönítik az alkalmazást; az adatbázis gyakran az első szivárgás, amit a támadó tesztelni fog.
Egy VM bérlőnként. Adjon minden bérlőnek egy teljes virtuális gépet. A hypervisor hardveres határt ad, pontosan azt, amit egy kernel-kihasználásnak át kell lépnie, hogy elérje a gazdagépet. Ez fontos a szabályozott környezetekben vagy amikor a bérlők nem megbízhatóak. Az ár a sűrűség és az idő. Mostantól operációs rendszerek flottáját kezeli, nem csak konténereket. Minden VM-nek frissítésekre, biztonsági ügynökökre és monitorozásra van szüksége. Egy egyedül dolgozó alapítónak ez valódi munka.
Ezen a szinten bevált minták: használjon infrastruktúra-kódot (infrastructure-as-code) a VM létrehozásához ugyanabból az alaplemezképből, építse be a frissítéseket az új lemezképekbe a működő rendszerek javítása helyett, és állítsa le azokat a munkaterheléseket, amelyeket nem ismer fel. Tartsa a VM kezelési portját zárva az internet felé.
Konténerek VM-ekben. Ezt a hibridet ritkán tárgyalják a kezdő oktatóanyagok. Egy kis VM-et helyez minden bérlő (vagy kis bérlőcsoport) köré, majd konténereket futtat azon a VM-en belül. A VM egy robbanási sugár tartály; a konténerek csak telepíthető egységek. Ez megadja a virtualizáció kemény élét és a lemezképek reprodukálhatóságát. Többe kerül, mert fizet a virtualizációs többletért és a konténerflexibilitásért, de ez lehet a legészszerűbb hosszú távú modell, ha nem tudja teljesen megbízni a bérlőkben.
Egy gyakori mikro-példa: egy bérlő egy Node API-t és egy háttérfeldolgozót futtat. Egyetlen hatalmas konténer helyett, amely mindkét folyamatot tartalmazza, használjon egy VM-et, majd két konténert eltérő erőforrás-korlátokkal, megosztott hálózattal, és a feldolgozó ne legyen közvetlenül elérhető az internetről. A VM biztosítja a kemény élt; a konténerek biztosítják a struktúrát.
Melyiket válassza? A táblázat a rövidlistája. A következő részek kézzelfoghatóvá teszik a döntést.
Ha konténereket választ, tegye meg ezt a hat dolgot, vagy ne is foglalkozzon vele
A bérlőnkénti konténerek rendben vannak, ha minden konténert potenciális támadóként kezel. Ez a konfigurációval kezdődik, nem a szép reményekkel.
0. Korlátozza az erőforrásokat, mielőtt bárkiben megbízik. A cgroupok méltányossági mechanizmusok és rendelkezésre állási védelem. Állítson be --memory és --cpus értékeket konténerenként. A memóriát szivárogtató bérlőnek a saját korlátját kell elérnie, nem a szerverét. Ez nem biztonsági határ, de a zajos szomszéd támadás egyetlen sornyi kód nélkül. Gyakorlati kezdés: --memory 512m --cpus 0.5. Egy feldolgozó folyamathoz kezdje alacsonyabban, és skálázza föl.
1. Futtassa nem-root felhasználóként. Soha ne engedje, hogy a konténerfolyamat UID 0-t használjon, hacsak nem feltétlenül szükséges. Állítson be felhasználót a Dockerfile-ban, és adja meg a --user-t extra védelemként. Egy nem privilegizált felhasználóként futó kihasználásnak sokkal kevesebb útja van a kernelhez. A Dockerfile-ban hozzon létre egy felhasználót: RUN useradd -u 10001 app és USER app. Ne hagyja ki ezt az időmegtakarítás miatt.
2. Dobja el az összes olyan képességet, amelyre nincs szüksége. A Linux-képességek apró darabokra bontják a root hatalmát. A legtöbb webalkalmazásnak szinte egyikre sincs szüksége. Kezdje a --cap-drop=ALL-lal, és csak azt adja vissza, amiről tudja, hogy szüksége van rá. Egy CAP_SYS_ADMIN nélküli konténert sokkal nehezebb névtér trükkökhöz használni. Ha az alkalmazás privilegizált portot próbál meg kötni, futtassa magas porton, és tegyen elé proxy-t, ahelyett hogy NET_BIND_SERVICE-t adna.
3. Tegye a fájlrendszert csak olvashatóvá. Az alkalmazás ne írjon a saját konténerrétegébe. Csatoljon tmpfs-t az állapothoz. Egy támadó, aki nem tud lemezre írni, sokkal nehezebben tud állandóságot biztosítani. Egy feltört PHP-alkalmazás, amely webshell-t próbál írni, kudarcot vall, ha a gyökér fájlrendszer csak olvasható. Csatolhat névvel ellátott kötetet egy írható könyvtárhoz, amelyre az alkalmazásnak valóban szüksége van.
4. Alkalmazzon seccomp-ot és AppArmor-t vagy SELinux-ot. Ezek a kockázatos rendszerhívásokat a szemétkosárba küldik. A Docker alapértelmezett seccomp-profilt tartalmaz; használja. Adjon hozzá egy AppArmor-profilt egy újabb réteghez. Nem kell minden rendszerhívást ismernie. Meg kell tagadnia azt, amit egy normál webes feldolgozó soha nem igényel. Soha ne futtasson --privileged-del. Ez a kapcsoló szinte minden védelmet kikapcsol, amit éppen beállított.
5. Szegmentálja a hálózatot. Ne adjon minden konténernek útvonalat minden másik konténerhez. Alapértelmezésben tiltson meg mindent, majd csak azokat a portokat nyissa meg, amelyekre szüksége van. Egy feltört adatbázis-konténer ne tudja beolvasni az adminisztrációs felületet. Ha a bérlők külön hálózatokban vannak, az egyik hálózatban bekövetkezett biztonsági rés nem terjedhet oldalirányban.
Egy gyakorlati kezdés:
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
Tegye ugyanezeket a kapcsolókat egy Compose fájlba, és alkalmazza minden bérlőre. Ez nem teljes, de sokkal erősebb alapértelmezés, mint amit a docker run ad alapból.
A részletesebb bemutatóhoz használja lépésről lépésre haladó megerősítési útmutatónkat a Docker-konténerekhez több-bérlős üzemeltetésben.
A Docker Enhanced Container Isolation az a kivétel, amelyről tudnia kell
Ha felügyelt Docker-környezetben fut, keresse a Docker Enhanced Container Isolation (ECI) funkciót. Ez felhasználói névtér-izolációt és biztonságos konténer futási környezetet használ a motorháztető alatt. A konténeren belüli root egy nem privilegizált felhasználóra van leképezve a gazdagépen, így még a rootként futó konténer sem kap gazdagép-root jogosultságokat. Emellett alapértelmezés szerint blokkolja a veszélyes képességeket és rendszerhívásokat. Ezt nem lehet pár kapcsolóval újraalkotni a natív Dockerben. Ha a platform támogatja, kapcsolja be. Nem szünteti meg a nem-root felhasználók és az erőforrás-korlátok szükségességét, de megváltoztatja a kockázati számítást.
Ennek egy részét megközelítheti a felhasználói névtér átképezésével (userns-remap) a Docker daemonban. Ez nem olyan teljes, mint egy biztonságos futási környezet, de jobb, mint a semmi. Ha használja, ellenőrizze, hogy az UID-leképezés működik, mielőtt megbízik benne.
A VM-tévhit: A virtuális gépekre való áttérés nem megerősítés
Itt van az ellentmondásos rész, és ez az a rész, amelyet a legtöbb ember kihagy. Ha egy VM-re vált bérlőnként, majd a szokásos konténereit telepíti bele, nem szüntette meg a konténerek biztonsági problémáját. Hozzáadott egy tágas ketrecet. A konténerszökés továbbra is működik; a támadó csak a VM-ben landol, nem a gazdagépen. Ez valódi javulás, de továbbra is szüksége van a hat lépésre.
A másik csapda az, ha feltételezi, hogy a VM maga biztonságos. Egy alapértelmezett lemezkép gyenge SSH-jelszóval, nem javított alapprogramokkal vagy nyitott kezelési porttal ajándék. A hypervisor-határ csak akkor számít, ha a vendégrendszer meg van erősítve és frissítve. Ellenkező esetben a „biztonságos VM” gyorsabb út a kompromittálódáshoz, mert biztonságban érzi magát, és abbahagyja az ellenőrzést.
Amit egy VM ad, az a csökkentett robbanási sugár. Egy bérlő katasztrófája egy VM-ben marad. Amibe kerül, az az ideje. Ön lesz a rendszergazdája annyi operációs rendszernek, ahány bérlője van. Ha egyedül dolgozó alapító, aki terméket szállít, kérdezze meg, hogy van-e ideje egy flotta javítására és figyelésére. Ha igen, az egy VM bérlőnként lehet a helyes döntés. Ha nem, az erős megerősítésű konténerek őszintébbek lehetnek.
Ne feledje azt is, hogy a hypervisor-gazdagép kritikus célpont. Egy feltört hypervisor minden vendéget láthat. Javítsa a gazdagépet, nem csak a vendégeket. A VM nem menti fel a gazdagépjavítás alól; növeli a tétért, ha kihagyja.
Egy figyelmeztetés a hibriddel kapcsolatban: ne feltételezze, hogy a VM-en belüli konténerek ingyen adnak „két biztonsági réteget”. A VM hozzáad egy határt; a konténernek továbbra is szüksége van nem-root felhasználóra, képességekre és seccomp-ra. Ellenkező esetben az első réteg csak olyan erős, mint a leggyengébb konténer.
Négy kérdés, amely tíz perc alatt eldönti a vitát
Ne optimalizáljon elvontan. Tegye fel magának ezt a négy kérdést sorrendben. Írja le a válaszokat.
1. Mihez fér hozzá a bérlőm? Ha egy bérlő csak a saját webalkalmazásához és adatbázisához fér hozzá, a szigorú hálózati szabályokkal rendelkező bérlőnkénti konténerek védhetők. Ha egy bérlő adatai szabályozottak vagy pénzügyileg érzékenyek, mozduljon a VM-ek felé.
2. Mennyibe kerülne nekem egy bérlő kompromittálódása? Adja össze az elveszett ügyfeleket, a jogi kitettséget és a bizalmat. Ha a szám nagyobb, mint a VM-ek futtatásának költsége, költse el a pénzt. Ha nem, a konténerek racionális választás.
3. Hány bérlőm van, és mennyit fizetnek? Sok kis előfizető: a konténersűrűség számít. Egy maroknyi nagy ügyfél: adjon mindegyiknek egy VM-et, és számlázzon ennek megfelelően. Azok a bérlők, akik kevesebbet fizetnek, mint egy kávé, ne igényeljenek mindegyikük egy operációs rendszert a kezeléshez.
4. Tudom ütemezetten javítani a rendszereket? A konténerek egyetlen gazdagép-kernelt osztanak meg, így a gazdagép javítása mindenkit véd. A VM-ek megsokszorozzák a javítási célpontokat. Ha tudja, hogy ki fogja hagyni a frissítéseket, válassza azt az architektúrát, amelynek kevesebb mozgó alkatrésze és erősebb alapértelmezése van.
A válaszai csoportosulni fognak. Két vagy több VM-központú válasz azt jelenti, hogy nem szabad alapértelmezés szerint bérlőnkénti konténereket használnia. Három vagy több konténer-központú válasz azt jelenti, hogy a VM-ek koraiak. Egy ellentmondásos eredmény: egy alacsony bevételű bérlő, aki érzékeny adatokhoz fér hozzá, továbbra is VM-et igényel, mert a szabályozási költségnek semmi köze ahhoz, hogy mennyit fizet.
Szállítsa a legkevesebbet, amiben megbízhat, majd érdemeljen ki több elkülönítést
Az első architektúrájának nem kell a véglegesnek lennie. Kezdje a legszorosabb felállással, amelyet valóban fenn tud tartani, majd adjon hozzá elkülönítést, ahogy a bérlői bázis indokolja. A legtöbb egyedül dolgozó üzemeltető számára ez bérlőnkénti konténereket jelent nem-root felhasználóval, korlátozott képességekkel, csak olvasható fájlrendszerekkel, seccomp-pal és hálózati szegmentációval. A szabályozott vagy magas értékű bérlők esetében ugorjon egyenesen az egy VM bérlőnként megoldásra, konténerekkel csak csomagolási rétegként belül.
Bármit is választ, írja le a döntést, és vizsgálja felül negyedévente. Amikor megkapja az első „áthelyezzük ezt a bérlőt VM-re?” kérdést, lesz válasza, és lesz egy ellenőrzőlistája, amely alátámasztja. Ezt jelenti valójában az elkülönítés: egy kompromisszum, amelyet kezel, nem egy technológia, amelyet megvásárol.
Az indulás előtt menjen végig a gyakorlati Docker-elkülönítési biztonsági ellenőrzőlistánkon – ez a döntéseket ellenőrizhető listává alakítja, mielőtt oldalt mutatna egy ügyfélnek.

