Blog
Klam důvěry: Jak náš multi-tenant Docker setup unikl data (a jak jsme to opravili)
Přečtěte si, jak naivní Docker nastavení jednoho týmu vedlo k úniku dat mezi tenanty a jaká vrstvená strategie izolace tomu zabránila.
Shrnutí
Docker kontejnery nejsou ve výchozím nastavení izolované – sdílejí jádro hostitele a bez promyšlené konfigurace mohou tenanti navzájem interferovat. Tento článek popisuje reálný scénář, kdy poskytovatel multi-tenant hostingu zjistil, že klientské kontejnery mohou přistupovat k databázím ostatních klientů kvůli sdílené síti a slabým bezpečnostním výchozím nastavením. Ukazujeme postupné změny, které prolomení opravily: sítě definované na úrovni tenanta, uživatele bez root oprávnění, odebrané schopnosti, souborové systémy pouze pro čtení a profily seccomp. Běžným předpokladem je, že kontejnery poskytují silnou izolaci; my to zpochybňujeme vysvětlením, proč virtuální stroje stále nabízejí pevnější hranici a kdy zvážit hybridní přístup. Závěr zdůrazňuje, že izolace je vrstvené cvičení, nikoliv jediné zaškrtávací políčko.
Incident: Když kontejnery mluví příliš mnoho
Nastavili jste Docker na jednom hostiteli pro provozování několika klientských webů. Každý klient má svůj vlastní kontejner – úhledné, izolované prostředí, že? To jsme si mysleli i my. Dokud rutinní bezpečnostní audit neodhalil, že kontejner klienta A čte MySQL socket kontejneru klienta B na stejném hostiteli. Sdíleli výchozí síť bridge. Horší bylo, že kontejnery běžely jako root, takže útočník, který jeden z nich kompromitoval, mohl manipulovat s Docker socketem hostitele nebo se souborovým systémem jiného kontejneru. Průnik nebyl sofistikovaný exploit; byla to základní chybná konfigurace. Data unikla. Důvěra zmizela.
Tento scénář selhání není neobvyklý. Mnoho týmů předpokládá, že Docker jmenné prostory a cgroups automaticky oddělují tenanty, ale podceňují, kolik únikových cest zůstává ve výchozím nastavení otevřených. Výchozí bridge sítě nenabízejí žádnou síťovou izolaci mezi kontejnery. Běh jako root dává kontejneru více moci, než je potřeba. A bez explicitních limitů zdrojů může jeden hlučný soused připravit ostatní o CPU nebo paměť.
Krok 1: Přestat sdílet jednu síť
Naší první opravou bylo přidělit každému tenantovi vlastní uživatelem definovanou Docker síť. Tím se zabrání tomu, aby se kontejnery vzájemně dosahovaly, pokud je výslovně nepřipojíte. Vytvořili jsme skript, který pro každého tenanta spustí vyhrazenou síť a připojí k ní jeho aplikační kontejner. Databázový kontejner žije ve stejné tenantové síti, ale také jsme přidali interní síť pouze pro komunikaci v rámci tenanta. Žádné více vměšování mezi tenanty.
Také jsme izolovali databáze tím, že jsme je spouštěli v samostatných kontejnerech ve stejné tenantové síti s oddělenými datovými svazky. Tím jsme zajistili, že i kdyby se útočník dostal do aplikačního kontejneru, nemohl by zachytit databázový provoz jiného tenanta.
Pro hlubší ponor do strategií síťové izolace si přečtěte Praktický kontrolní seznam bezpečnosti Docker izolace pro multi-tenant hosting.
Krok 2: Odebrání zbytečných oprávnění
Ve výchozím nastavení běží Docker kontejnery s omezenou sadou Linuxových schopností, ale stále mají více, než většina aplikací potřebuje. Naše kontejnery běžely jako root, což umožňovalo procesům uvnitř provádět akce jako připojování souborových systémů nebo změna parametrů jádra. Přepnuli jsme se na běh aplikace jako uživatele bez root oprávnění uvnitř kontejneru (pomocí direktivy USER v Dockerfile) a odebrali všechny schopnosti kromě těch, které jsou naprosto nezbytné. Pro typickou webovou aplikaci to může být pouze NET_BIND_SERVICE (pro vázání na porty pod 1024) a CHOWN (pro zápis do adresářů). Také jsme přidali --security-opt no-new-privileges pro zabránění eskalaci oprávnění.
Tento jediný krok eliminoval mnoho běžných vektorů úniku z kontejneru. Útočník, který kompromituje webový server, nemůže instalovat balíčky, upravovat systémové binární soubory ani přistupovat k Docker socketu hostitele, protože procesu chybí schopnosti CAP_SYS_ADMIN nebo CAP_DAC_OVERRIDE.
Krok 3: Uzavření souborového systému
Zapisovatelné souborové systémy jsou běžným útočným povrchem. Pro všechny kontejnery jsme nastavili kořenový souborový systém pouze pro čtení (--read-only) a poté připojili dočasné souborové systémy (tmpfs) pro adresáře, které potřebují zápis, jako /tmp a adresář mezipaměti aplikace. Tím se zabrání útočníkovi v úpravě aplikačního kódu nebo v trvalém ukládání škodlivých binárek.
Kromě toho jsme použili možnost Dockeru --mount pro bind-mount citlivých adresářů, jako je Docker socket, pouze když je to naprosto nutné – a nikdy na produkčních kontejnerech. Princip: pokud kontejner nepotřebuje zapisovat do cesty, nastavte ji jako pouze pro čtení.
Krok 4: Aplikace profilů Seccomp a AppArmor
Výchozí seccomp profily již blokují mnoho nebezpečných systémových volání, ale my jsme je dále přizpůsobili, aby povolovaly pouze ta systémová volání, která naše aplikace skutečně potřebuje. To je kompromis, protože vyžaduje profilování aplikace. Jednodušší přístup je použít výchozí seccomp profil Dockeru a poté přidat --security-opt seccomp=cesta/k/profilu.json, pokud potřebujete přísnější pravidla. Podobně mohou profily AppArmor omezit procesy v kontejneru na konkrétní cesty k souborům a schopnosti. Povolili jsme AppArmor a použili vlastní profil, který omezil přístup pouze na datové adresáře aplikace.
Pro komplexního průvodce těmito kroky zesílení zabezpečení se podívejte na Zesílení zabezpečení Docker kontejnerů pro multi-tenant hosting: průvodce krok za krokem izolací.
Opačný pohled: Někdy potřebujete virtuální stroje
Bez ohledu na to, jak zesílené jsou kontejnery, sdílejí jádro hostitele. Zranitelnost jádra může narušit veškerou izolaci najednou. Proto mnoho bezpečnostně uvědomělých platforem spouští kontejnery uvnitř lehkých virtuálních strojů – každý tenant má své vlastní jádro. To přidává režii, ale poskytuje hranici na úrovni hardwaru, kterou samotné kontejnery nemohou poskytnout. Pokud vaši tenanti zpracovávají údaje o kreditních kartách nebo zdravotní záznamy, hybridní přístup (kontejnery uvnitř virtuálních strojů) může být správnou volbou. Nepředpokládejte, že izolace kontejnerů je dostatečná pro váš model hrozeb; zhodnoťte citlivost dat a regulační požadavky.
Pro hlubší srovnání úrovní izolace si přečtěte Navrhování multi-tenant Docker architektury: výběr správné úrovně izolace.
Závěr: Izolace je zásobník, nikoli přepínač
Oprava nebyla jediná změna – bylo to vrstvení: síťová izolace, omezená oprávnění, souborové systémy pouze pro čtení a filtrování systémových volání. I tak jsme přijali, že dokonalá izolace je u kontejnerů sdílejících jádro nemožná. Pro naše nejbezpečnější tenanty jsme je přesunuli na vyhrazené hostitele. Poučení: nedůvěřujte výchozímu nastavení. Auditovat svou Docker konfiguraci, jako by k prolomení již došlo. Čas na uzamčení je před únikem, ne po něm.


