Blog

Przewodnik krok po kroku po izolacji środowisk multi-tenant w Dockerze

Izoluj obciążenia multi-tenant w Dockerze, kontrolując koszty hostingu. Dowiedz się, jak konfigurować przestrzenie nazw, grupy cgroups, polityki sieciowe i utwardzanie środowiska uruchomieniowego.

Podsumowanie

Zarządzanie współdzieloną infrastrukturą dla wielu kampanii klienckich lub wewnętrznych serwisów internetowych często prowadzi do spięć z kadrą zarządzającą na tle kosztów hostingu i bezpieczeństwa danych. Kontenery Docker stanowią lekką alternatywę dla dedykowanych maszyn wirtualnych, ale ich domyślna konfiguracja pozostawia poważne luki w izolacji. Prawdziwa wielodostępność (multi-tenancy) wymaga przemyślanych granic na poziomie jądra systemu, procesów, sieci i pamięci masowej. Niniejszy przewodnik przedstawia praktyczny, pięciostopniowy schemat zabezpieczania wdrożeń Docker w architekturze multi-tenant przy użyciu natywnych mechanizmów izolacji systemu Linux. Dowiesz się, jak egzekwować limity zasobów, ograniczać uprawnienia procesów, segmentować sieci kontenerów i dobierać odpowiedni poziom izolacji. Wdrażając ten plan, zabezpieczysz środowiska poszczególnych najemców i skutecznie uzasadnisz budżet infrastrukturalny przed osobami decyzyjnymi bez wiedzy technicznej.

Twój nietechniczny przełożony wchodzi do biura z wydrukiem faktury za hosting w chmurze z zeszłego miesiąca. Koszty wzrosły, a jednocześnie kilka kluczowych landing page'y odnotowało skoki opóźnień podczas równoległego wprowadzania nowego produktu. Padają pytania, dlaczego zasoby marketingowe współdzielą serwery, czy dane klientów są bezpieczne i dlaczego zespół nie może po prostu uruchomić drogiej, dedykowanej maszyny wirtualnej dla każdej pojedynczej kampanii.

Przydzielenie każdemu zasobowi cyfrowemu własnej maszyny wirtualnej (VM) eliminuje problem „uciążliwych sąsiadów” (noisy neighbors), ale błyskawicznie pochłania budżet operacyjny. Standardowe wdrożenia Dockera rozwiązują problem kosztów, uruchamiając wiele witryn na jednym jądrze systemu operacyjnego, jednak ich domyślna konfiguracja pozostawia niebezpieczne luki w izolacji. Jeśli aplikacja jednego klienta padnie ofiarą zapętlonego skryptu lub ataku, zagrożone stają się wszystkie inne aplikacje współdzielące ten sam host.

Skorzystaj z tego technicznego przewodnika krok po kroku, aby skonfigurować rygorystyczną izolację multi-tenant w Dockerze. Wdróż te pięć kroków operacyjnych, aby zadbać o stabilność systemu, odizolować dane najemców i przełożyć techniczne wybory infrastrukturalne na wymierne korzyści biznesowe dla zarządu.


1. Egzekwuj sztywne limity zasobów za pomocą Control Groups (cgroups)

Natychmiast ustaw jawne limity procesora, pamięci RAM i operacji wejścia/wyjścia (I/O) dla każdego kontenera. Gdy wielu najemców współdzieli jeden host, nieograniczone kontenery rywalizują o zasoby systemowe. Jedno przeciążone zapytanie do bazy danych lub generująca wysoki ruch kampania może wyczerpać całą pamięć RAM hosta, zmuszając mechanizm Linux Out-Of-Memory (OOM) killer do losowego zamykania procesów systemowych.

Mechanizm Linux control groups (cgroups) kontroluje, ile mocy obliczeniowej może zużyć dany kontener. Zastosuj te ograniczenia bezpośrednio w plikach konfiguracyjnych wdrożenia:

services:
  tenant_app:
    image: nginx:alpine
    deploy:
      resources:
        limits:
          cpus: '0.75'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M
  • Limity pamięci (limits.memory): Wyznaczają nieprzekraczalny pułap. Jeśli kontener przekroczy 512 megabajtów, jądro systemu zamknie procesy wewnątrz tego kontenera bez wpływu na sąsiednie środowiska.
  • Rezerwacje pamięci (reservations.memory): Gwarantują bazową alokację pamięci, dzięki czemu aplikacje o mniejszym natężeniu ruchu pozostają responsywne.
  • Limity CPU (limits.cpus): Ograniczają kontener do maksymalnego ułamka dostępnych rdzeni procesora, zapobiegając zmonopolizowaniu CPU przez pojedynczego najemcę.

Uzasadniając tę architekturę przed kadrą zarządzającą, opisz cgroups jako automatyczne subliczniki. Tak jak najemcy w biurowcu płacą za indywidualne zużycie prądu zamiast doprowadzać do przeciążenia głównego bezpiecznika, tak cgroups dbają o to, by landing page generujący nagły ruch nie doprowadził do awarii portalu innego klienta. Aby lepiej poznać kompromisy architektoniczne, zapoznaj się z naszym przewodnikiem po projektowaniu architektury multi-tenant.


2. Segmentuj procesy najemców za pomocą przestrzeni nazw i użytkowników non-root

Nigdy nie uruchamiaj procesów w kontenerze z domyślnymi uprawnieniami użytkownika root. W standardowych środowiskach kontenerowych Linuksa root wewnątrz kontenera odpowiada rootowi na poziomie jądra systemu hosta, o ile nie zostanie jawnie przemapowany. Jeśli atakujący przejmie kontrolę nad aplikacją internetową działającą jako root, zyskuje podwyższone uprawnienia w całym współdzielonym hoście.

Wdróż izolację procesów za pomocą przestrzeni nazw użytkowników (user namespaces) oraz jawnego uruchamiania procesów bez uprawnień roota:

  1. Definiuj nieuprzywilejowanych użytkowników: Utwórz dedykowanych użytkowników usługowych o niskich uprawnieniach w plikach Dockerfile.
    FROM php:8.2-fpm-alpine
    RUN addgroup -g 10001 tenantgroup && \n       adduser -u 10001 -D -G tenantgroup tenantuser
    USER tenantuser
    
  2. Włącz przestrzenie nazw użytkowników (userns-remap): Skonfiguruj demona Dockera (/etc/docker/daemon.json), aby mapował identyfikatory użytkowników kontenera na nieuprzywilejowany zakres na hoście.
    {
      "userns-remap": "default"
    }
    

Linuksowe przestrzenie nazw (namespaces) dzielą widoczność systemu. Przestrzeń PID (Process ID) gwarantuje, że Klient A nie widzi, nie może sygnalizować ani wyłączać procesów należących do Klienta B. Przestrzeń MNT (Mount) daje każdemu najemcy odizolowany widok systemu plików, podczas gdy przestrzenie IPC blokują nieautoryzowaną komunikację międzyprocesową.

Remapowanie przestrzeni nazw użytkowników neutralizuje wektory ucieczki z kontenera: proces, który wewnątrz kontenera ma uprawnienia root (UID 0), na maszynie hosta jest mapowany na nieuprzywilejowane ID (np. UID 165536). Jeśli exploit przełamie bariery kontenera, atakujący trafia do nieuprzywilejowanej powłoki, bez możliwości modyfikacji konfiguracji hosta ani dostępu do katalogów innych najemców.


3. Ogranicz uprawnienia jądra i wymuś system plików tylko do odczytu

Ogranicz dostępne możliwości jądra Linuksa (Linux capabilities) i uczyń główny system plików kontenera niezmiennym (read-only) podczas uruchamiania. Domyślne środowiska uruchomieniowe kontenerów przyznają około tuzina uprawnień jądra, z których większość nie jest potrzebna aplikacjom webowym. Nadmiarowe uprawnienia dają atakującym narzędzia do manipulacji routingiem sieciowym, modyfikacji zegara hosta czy omijania kontroli dostępu do plików.

Zabezpiecz kontenery, odbierając wszystkie domyślne możliwości i przywracając wyłącznie te niezbędne do działania:

services:
  tenant_web:
    image: custom-nginx:latest
    read_only: true
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    security_opt:
      - no-new-privileges:true
      - seccomp=default.json
    tmpfs:
      - /tmp:rw,noexec,nosuid,size=64m
      - /var/run:rw,noexec,nosuid,size=16m
  • cap_drop: - ALL: Odbiera procesowi kontenera wszystkie uprawnienia jądra.
  • cap_add: - NET_BIND_SERVICE: Jawnie zezwala na bindowanie do portów uprzywilejowanych (takich jak 80 i 443), blokując jednocześnie bezpośrednią manipulację gniazdami sieciowymi (raw sockets).
  • read_only: true: Montuje cały główny system plików kontenera w trybie tylko do odczytu. Atakujący nie mogą pobrać złośliwych plików binarnych, zmodyfikować skryptów PHP ani zmienić plików konfiguracyjnych serwera www.
  • tmpfs: Alokuje ulotne katalogi w pamięci RAM na niezbędne pliki tymczasowe (np. /tmp), blokując jednocześnie wykonywanie plików binarnych (noexec) oraz eskalację uprawnień (nosuid).

Zastosuj filtry trybu bezpiecznych obliczeń (seccomp) oraz moduły bezpieczeństwa, takie jak AppArmor lub SELinux, aby przechwytywać i ograniczać wywołania systemowe kierowane do współdzielonego jądra hosta. Jeśli Twój zespół zarządza niestandardowymi kompilacjami aplikacji webowych, sprawdź nasze kroki dotyczące utwardzania kontenerów Docker w potokach wdrożeniowych.


4. Podziel sieć pomiędzy środowiskami najemców

Wyłącz domyślną sieć bridge i skonfiguruj dedykowane, odizolowane sieci mostkowe (bridge) definiowane programowo dla stosu technologicznego każdego najemcy. Domyślnie kontenery podłączone do standardowej sieci bridge Dockera mogą się wzajemnie wykrywać i komunikować za pośrednictwem wewnętrznych adresów IP. Luka w usłudze marketingowej jednego klienta otwiera drogę do ataku lateralnego na wszystkie inne bazy danych i aplikacje na danym hoście.

Całkowicie odizoluj ruch najemców, definiując niezależne mostki sieciowe dla każdego z nich:

networks:
  tenant_alpha_net:
    driver: bridge
    internal: true
  tenant_beta_net:
    driver: bridge
    internal: true
  public_gateway_net:
    driver: bridge

services:
  alpha_app:
    image: tenant_a_app:latest
    networks:
      - tenant_alpha_net
      - public_gateway_net

  alpha_db:
    image: mariadb:10.11
    networks:
      - tenant_alpha_net

  beta_app:
    image: tenant_b_app:latest
    networks:
      - tenant_beta_net
      - public_gateway_net

  beta_db:
    image: mariadb:10.11
    networks:
      - tenant_beta_net
  • Izolacja najemców: alpha_app i alpha_db komunikują się wyłącznie w ramach tenant_alpha_net. beta_app nie ma dostępu do alpha_db, nawet jeśli atakujący przeskanuje wewnętrzną podsieć.
  • Flaga sieci wewnętrznej (internal: true): Zapobiega bezpośredniemu routingowi ruchu z sieci bazodanowych do publicznego Internetu, ograniczając dostęp przychodzący i wychodzący wyłącznie do kontenerów aplikacji.
  • Brama Reverse Proxy: Tylko proxy wejściowe (ingress) łączy się z public_gateway_net, aby przekierowywać przychodzące żądania HTTP/HTTPS do odpowiedniego kontenera najemcy na podstawie nazwy hosta.

W bardziej wymagających środowiskach warto rozważyć tryby Enhanced Container Isolation (ECI) w Dockerze lub środowiska uruchomieniowe takie jak Sysbox, które automatycznie wymuszają bardziej rygorystyczne granice przestrzeni nazw użytkowników oraz zwirtualizowane systemy plików /proc i /sys bez konieczności skomplikowanej ręcznej konfiguracji sieci.


5. Stwórz obiektywną macierz decyzyjną dla środowisk multi-tenant

Przełam przekonanie, że każdy zasób cyfrowy bezwzględnie wymaga dedykowanej maszyny wirtualnej. Liderzy marketingu często zakładają, że izolacja sprzętowa na poziomie VM to jedyny bezpieczny model. W praktyce przydzielanie dedykowanych maszyn wirtualnych dla prostych landing page'y czy krótkotrwałych stron kampanijnych generuje ogromne koszty i narzut administracyjny, nie podnosząc realnie bezpieczeństwa samej aplikacji webowej.

Skorzystaj z poniższej tabeli porównawczej, aby ocenić wymagania obciążeń i przedstawić decydentom racjonalną strategię wdrożeniową:

Poziom izolacjiZastosowana technologiaGranica bezpieczeństwaNarzut na zasobyNajlepsze zastosowanie
Współdzielone konteneryNamespaces i cgroups na jednym systemieLogiczna izolacja na poziomie systemu operacyjnegoBardzo niskiLanding page o dużym natężeniu ruchu, środowiska stagingowe, tymczasowe serwisy kampanijne
Utwardzone kontenery (ECI / Sysbox)Przestrzenie nazw użytkowników, AppArmor, system plików tylko do odczytuZaawansowana izolacja OS i wirtualizacjaNiskiHosting agencyjny dla wielu klientów, portale z logowaniem, formularze z danymi wrażliwymi
Dedykowane maszyny wirtualne (VM)Wirtualizacja sprzętowa (hiperwizor)Ścisła separacja na poziomie sprzętu i jądraWysokiPrzetwarzanie płatności, dane objęte regulacjami HIPAA/PCI, uruchamianie niezaufanego kodu
Model hybrydowy (kontenery w dedykowanych VM)Utwardzone kontenery wewnątrz dedykowanych maszyn wirtualnych najemcyWielowarstwowe granice sprzętowe i systemoweUmiarkowany do wysokiegoKlienci korporacyjni najwyższego szczebla z rygorystycznymi wymaganiami umownymi

Przeanalizuj każdy projekt według ścisłych kryteriów przed przydzieleniem budżetu infrastrukturalnego:

  1. Wrażliwość danych: Czy projekt przechowuje dane regulowane prawnie (np. dane kart płatniczych lub dokumentację medyczną)? Jeśli tak, wdróż dedykowaną maszynę wirtualną.
  2. Pochodzenie kodu: Czy wdrażasz ustandaryzowany, zweryfikowany przez zespół kod, czy dopuszczasz niesprawdzone wtyczki firm trzecich? Standardowy kod może działać w utwardzonych kontenerach; nieprzetestowany kod z zewnątrz wymaga izolacji na poziomie hiperwizora.
  3. Budżet i cykl życia: W przypadku sezonowych landing page'y i głównych serwisów firmowych, utwardzona architektura kontenerowa multi-tenant zapewnia najlepszy stosunek wydajności do kosztów.

Prezentując plany infrastrukturalne zarządowi, skorzystaj z naszego przewodnika po ocenie, kiedy klienci potrzebują dedykowanych maszyn wirtualnych, aby poprzeć swoje rekomendacje jasnymi argumentami opartymi na poziomach izolacji.


Podsumowanie: Przełożenie zabezpieczeń na zwrot z inwestycji (ROI)

Zabezpieczenie środowiska multi-tenant w Dockerze nie wymaga budżetu na poziomie wielkich korporacji chmurowych. Wymaga rygorystycznego, zdyscyplinowanego stosowania wbudowanych mechanizmów kontroli systemu operacyjnego.

Omawiając infrastrukturę z nietechnicznym kierownictwem, przedstaw te techniczne konfiguracje przez pryzmat trzech kluczowych wskaźników biznesowych:

  • Efektywność kosztowa: Kontenery multi-tenant pozwalają zespołowi hostować dziesiątki witryn marketingowych przy ułamku zasobów obliczeniowych wymaganych przez osobne maszyny wirtualne.
  • Ochrona ciągłości działania (Uptime): Grupy kontrolne (cgroups) gwarantują, że skoki ruchu podczas sezonowej kampanii nie pogorszą wydajności głównych serwisów marki.
  • Ograniczenie zasięgu awarii (Blast Radius): Systemy plików tylko do odczytu, odebrane uprawnienia jądra i izolowane mostki sieciowe gwarantują, że przełamanie zabezpieczeń pojedynczej strony nie pozwoli na dostęp do baz danych innych klientów ani do kontroli nad hostem.

Wdrażaj te zabezpieczenia systematycznie we wszystkich szablonach kontenerów. W ten sposób zapewnisz wydajną, zoptymalizowaną kosztowo infrastrukturę, która spełnia zarówno inżynieryjne standardy bezpieczeństwa, jak i ramy budżetowe zarządu.

Sources (5)