Możesz uruchomić Dockera w środowisku produkcyjnym przez wiele miesięcy bez widocznego problemu. Kontenery uruchamiają się, aplikacje odpowiadają, nic się nie psuje. Następnie jeden odsłonięty port lub jedno błędnie skonfigurowane uprawnienie tworzy przyczółek, na który osoba atakująca nie musi zdobywać. Większość błędów bezpieczeństwa Dockera nie wygląda na błędy, dopóki coś nie pójdzie nie tak.
W tym artykule opisano konkretne konfiguracje, które narażają środowiska kontenerowe na ryzyko, możliwości każdej z nich dla atakującego, a na zakończenie przedstawiono listę kontrolną, którą można już dziś uruchomić w odniesieniu do własnej konfiguracji.
Dlaczego bezpieczeństwo platformy Docker jest trudniejsze, niż się wydaje
Kontenery czują się odizolowane. Uruchamiasz jeden, uruchamia on własną przestrzeń procesową, a z jego wnętrza następny kontener nie istnieje. Dostajesz izolację, ale tylko częściową. Kontenery współdzielą jądro hosta, co oznacza, że proces wewnątrz kontenera może, w określonych warunkach, w całości dotrzeć do systemu hosta.
Statki dokerów są konfigurowane z myślą o wygodzie programistów, a nie o wzmocnieniu produkcji. Dostęp do roota włączony. Wszystkie porty można powiązać ze wszystkimi interfejsami. Brak monitorowania czasu działania. Większość programistów akceptuje te ustawienia, wysyła kontener i kontynuuje pracę. To rozsądne podejście na początek; nie jest to gotowy poziom bezpieczeństwa.
Według Raport firmy Red Hat o stanie bezpieczeństwa Kubernetes za rok 2024, 67% organizacji opóźniło lub spowolniło wdrażanie aplikacji ze względu na obawy dotyczące bezpieczeństwa kontenera lub Kubernetes. To tarcie zwykle nie wynika z ataków. Pochodzą od zespołów, które odkryły, że ich konfiguracje kontenerów wymagają wzmocnienia, a którego nie wbudowały.
Często widzimy kontenery działające w środowisku produkcyjnym z tą samą konfiguracją, jaką miały na lokalnej maszynie programisty. To właśnie tam błędy bezpieczeństwa Dockera zwykle narastają po cichu, bez widocznych symptomów, dopóki coś nie zostanie poddane audytowi lub nie powiedzie się.
Błędy tworzące te luki są specyficzne, przewidywalne i w większości możliwe do uniknięcia, zaczynając od poziomu konfiguracji.
Typowe błędy konfiguracji Dockera
Większość naruszeń kontenerów nie zaczyna się od exploita zero-day. Zaczynają od konfiguracji ustawionej pierwszego dnia, bez większego zastanowienia się nad narażeniem sieci lub zakresem uprawnień.
Domyślne ustawienia Dockera są stworzone do działania. Luka między funkcjonalnością a bezpieczeństwem to miejsce, w którym kumulują się zagrożenia bezpieczeństwa kontenerów Docker, szczególnie w konfiguracjach hostowanych samodzielnie, które są wdrażane i nigdy nie odwiedzane ponownie.
Często widzimy ten wzorzec: kontenery na serwerach z publicznym adresem IP z powiązaniami portów, ustawieniami użytkownika i konfiguracjami sieci dokładnie takimi, jakie były przy początkowym wdrożeniu.
Uruchamianie kontenerów jako root
Kiedy uruchamiasz kontener Docker bez określenia użytkownika, działa on jako root. Oznacza to, że każdy proces wewnątrz kontenera, w tym Twoja aplikacja, ma uprawnienia na poziomie root w przestrzeni nazw kontenera.

Root w kontenerze to nie to samo, co root na hoście, ale separacja nie jest absolutna. Exploity polegające na eskalacji uprawnień atakujące środowisko wykonawcze, takie jak dobrze udokumentowany błąd runc CVE-2019-5736 i podobne wady środowiska wykonawczego, często wymagają pomyślnego procesu kontenera głównego.
Kontenery inne niż root usuwają wymagania dotyczące procesu root, od których zależą te exploity, znacznie zawężając powierzchnię ataku dla tej klasy luk w zabezpieczeniach, choć nie eliminują całkowicie ryzyka ucieczki z kontenera.
Dodanie dyrektywy USER do pliku Dockerfile rozwiązuje ten problem. Niektóre oficjalne obrazy są dostarczane z nieuprzywilejowanym użytkownikiem, którego można aktywować za pomocą dyrektywy USER, ale wiele z nich nadal domyślnie uruchamia root bez gotowego użytkownika aplikacji. W takich przypadkach tworzysz użytkownika w pliku Dockerfile przed przełączeniem na niego. W przypadku większości konfiguracji hostowanych samodzielnie ta pojedyncza zmiana usuwa całą kategorię ryzyka eskalacji.
Udostępnianie zbyt wielu portów publicznemu Internetowi
Kiedy publikujesz port za pomocą Dockera, Docker bezpośrednio pisze własne reguły iptables. Reguły te działają przed regułami zapory na poziomie hosta. To jest dobrze znane zachowanie zgłoszone przez społeczność I udokumentowane w przewodniku filtrowania pakietów Dockera, a nie błędną konfigurację i oznacza, że UFW i podobne narzędzia nie blokują tego, co już otworzył Docker.

Docker zapisuje bezpośrednio do iptables, omijając domyślne ustawienia UFW i zapory ogniowej na wielu hostach z Linuksem. Oznacza to, że port powiązany z 0.0.0.0 może być publicznie dostępny nawet wtedy, gdy zapora wygląda na skonfigurowaną. Grupy zabezpieczeń w chmurze i reguły łańcucha DOCKER-USER mogą nadal blokować ten ruch, więc rzeczywista ekspozycja zależy od konkretnej konfiguracji sieci.
Jeśli to możliwe, powiąż usługi z adresem 127.0.0.1, kieruj ruch publiczny przez odwrotne proxy i publikuj tylko to, co rzeczywiście wymaga dostępu zewnętrznego. Odwrotne proxy to najbardziej niezawodny sposób kontrolowania tego, co jest ujawniane spoza hosta.
Ignorowanie izolacji sieci pomiędzy kontenerami
Każdy kontener w tej sieci może bez ograniczeń dotrzeć do dowolnego innego kontenera w tej sieci. Domyślny most nie stosuje żadnego filtrowania ruchu między współdzielącymi go kontenerami, a większość konfiguracji nigdy nie zmienia tej konfiguracji.

Jeśli jeden kontener zostanie naruszony, otwarta komunikacja stanie się boczną ścieżką ruchu. Kontener frontonu może uzyskać dostęp do bazy danych, wewnętrznego interfejsu API lub czegokolwiek innego w tej samej domyślnej sieci pomostowej, nawet jeśli taki dostęp nigdy nie był zamierzony.
Sieci zdefiniowane przez użytkownika dają wyraźną kontrolę nad tym, które kontenery mogą się komunikować, ale pojedyncza sieć niestandardowa współdzielona przez wszystkie usługi nadal umożliwia bezpłatny ruch między kontenerami. Prawdziwa izolacja wymaga umieszczenia usług, które nie powinny ze sobą rozmawiać, w oddzielnych sieciach. Wyłączenie domyślnego mostu to punkt startu, a nie meta.
Z widokiem na gniazdo Docker
Gniazdo Dockera w /var/run/docker.sock to interfejs kontrolny dla całego silnika Dockera. Zamontowanie go w kontenerze zapewnia temu kontenerowi bezpośredni dostęp API do demona działającego na hoście.

Dzięki temu dostępowi kontener może uruchamiać nowe kontenery, montować katalogi hosta, sprawdzać i modyfikować działające kontenery oraz skutecznie kontrolować maszynę hosta. Powierzchnia ataku jest równoważna rootowi na hoście, dlatego każde narzędzie wymagające dostępu do gniazda zasługuje na dokładną ocenę.
W większości przypadków istnieją bezpieczniejsze alternatywy: interfejsy API o ograniczonym zakresie lub Narzędzia do zarządzania Dockerem które nie wymagają dostępu do gniazdka. Docker-in-Docker niesie ze sobą własne kompromisy w zakresie bezpieczeństwa i funkcjonalności i nie jest prostym substytutem.
Błędy konfiguracyjne powodują początkową ekspozycję. Wybór obrazu i zależności określa, w jaki sposób ekspozycja zmienia się w czasie.
Błędy wizerunkowe i tajemnice, które przetrwają w pojemniku
Kiedy zatrzymasz kontener, błędy konfiguracyjne w nim zakończą się wraz z nim. Podczas odbudowy z obrazu zawierającego lukę w zabezpieczeniach lub zakodowane na stałe dane uwierzytelniające problem zaczyna się od nowa z kontenerem. Błędy na poziomie obrazu nie resetują się pomiędzy wdrożeniami.
Podróżują z obrazem do każdego środowiska, które go pobiera, do każdego rejestru, w którym go przechowuje, i do każdego członka zespołu, który go uruchamia. Ta trwałość sprawia, że zarządzanie obrazami i tajemnicami stanowi odrębną kategorię ryzyka, którą warto kontrolować niezależnie od konfiguracji.
Często widzimy ten wzorzec: obraz wybrany starannie na początku projektu i od tego czasu nigdy nie przebudowywany, powoli oddalający się od początkowego poziomu bezpieczeństwa, który reprezentował.
Korzystanie z niezaufanych lub nieaktualnych obrazów
Rejestry publiczne są otwarte dla każdego. Za pośrednictwem Docker Hub rozesłano złośliwe obrazy zawierające kopacze kryptowalut i backdoory osadzone w historii warstw, które utrzymują się po ponownym uruchomieniu kontenera. Weryfikacja przed wyciągnięciem ma znaczenie, zwłaszcza w przypadku obrazów od nieoficjalnych lub nieznanych wydawców.

Osobnym problemem jest nieaktualność. Oficjalny obraz, który pobrałeś sześć miesięcy temu i od tego czasu nigdy nie został odbudowany, gromadzi niezałatane luki w zabezpieczeniach Dockera z każdym ujawnionym CVE w jego pakietach. Obraz nie jest uszkodzony. To po prostu nie jest już aktualne.
Raport Sonatype o stanie łańcucha dostaw oprogramowania za rok 2024 odkryli, że w 95% przypadków wykorzystania podatnego komponentu dostępna jest już poprawiona wersja, a 80% zależności aplikacji pozostaje nieaktualizowanych przez ponad rok. Ten wzorzec dotyczy również podstawowych obrazów Dockera, ponieważ opierają się one na tych samych pakietach open source.
Używaj oficjalnych obrazów od zweryfikowanych wydawców i przypinaj znaczniki konkretnej wersji, zamiast polegać na „najnowszych”. Stwórz regularny rytm odbudowy, aby Twoje obrazy były aktualne.
Sekrety kodowania na stałe w plikach Dockerfile i plikach Compose
Poświadczenia zapisane w instrukcji Dockerfile ENV lub ARG, zakodowane na stałe w bloku środowiska Compose, przekazane jako argumenty kompilacji lub przechowywane w pliku .env przeznaczonym do kontroli wersji nie znikają po zatrzymaniu kontenera. Pozostają w historii warstwy obrazu lub kontroli źródła, dostępne dla każdego, kto ma do nich dostęp.

Jest to jeden z najczęściej pomijanych błędów bezpieczeństwa Dockera, ponieważ nie powoduje widocznych problemów podczas programowania. Klucz API w instrukcji ENV działa poprawnie. Znajduje się on także w Twoim repozytorium, jest osadzony w obrazie i rozpowszechniany wszędzie tam, gdzie obraz się przemieszcza.
Modern Docker Compose obsługuje natywny mechanizm sekretów, który montuje poświadczenia w czasie wykonywania bez zapisywania ich w obrazie. API Dockera i menedżerowie sekretów zewnętrznych kierują się tą samą zasadą. Są to opcje, które całkowicie utrzymują poświadczenia poza artefaktami kompilacji i zatwierdzonymi plikami.
Zmienne środowiskowe środowiska wykonawczego stanowią ulepszenie w stosunku do poświadczeń zakodowanych na stałe, ale nadal są ujawniane poprzez dane wyjściowe, dzienniki i zrzuty awaryjne Docker Inspect. Stanowią krok naprzód w stosunku do ukrytych tajemnic, a nie gotowe rozwiązanie.
Brak regularnej aktualizacji obrazów kontenerów
Wyświetlanie tego samego obrazu przez miesiące jest powszechnym nawykiem. Każdy dzień po ujawnieniu nowej luki w zabezpieczeniach, ale przed przebudowaniem, Twoje kontenery mają okno ekspozycji, które rośnie bez żadnych widocznych zmian.
Stwórz spójny harmonogram odbudowy. Zautomatyzuj ten proces, jeśli to możliwe, i okresowo uruchamiaj skaner podatności na bieżące obrazy. Celem nie jest doskonałość. Skraca czas między wydaniem łatki a jej wdrożeniem.
W przypadku szybkich wdrożeń kontrola dostępu i monitorowanie mogą stracić priorytety. Są to także kategorie, w których zdarzenia najdłużej pozostają niewykryte.
Kontrola dostępu i luki w widoczności
Po uruchomieniu kontenera z solidną konfiguracją i bieżącymi obrazami pozostają dwie kategorie awarii. Obydwa są z natury niewidoczne: nie zauważysz problemu ze słabą kontrolą dostępu, dopóki ktoś z niego nie skorzysta, i nie zauważysz luki w monitorowaniu, dopóki nie będziesz musiał sprawdzić aktywności, która nigdy nie była rejestrowana.
Ten sam Badania Red Hat 2024 wykazało, że 42% zespołów nie miało wystarczających możliwości, aby zająć się bezpieczeństwem kontenerów i powiązanymi zagrożeniami.
Ustaliliśmy, że luki w monitorowaniu zwykle ujawniają się podczas dochodzenia w sprawie incydentu, a nie wcześniej. Zanim widoczność stanie się priorytetem, często reaguje na coś, a nie zapobiega.
Słabe uwierzytelnianie i odsłonięte pulpity zarządzania
Panel zarządzania kontenerami na publicznym adresie IP bez uwierzytelniania nie wymaga wyrafinowanego atakującego. Wymaga to od nich znajomości adresu. To niższa poprzeczka, niż zdaje sobie sprawę większość zespołów.

Własne narzędzia do monitorowania i zarządzania są zazwyczaj dostarczane z interfejsem internetowym dostępnym na wszystkich interfejsach sieciowych. Pozostawienie osób znajdujących się na publicznym adresie IP bez autoryzacji przed nimi jest równoznaczne z pozostawieniem otwartego panelu administracyjnego.
Uwierzytelnianie, odwrotne proxy i rozmieszczenie sieci prywatnej to podstawa. Kontrola dostępu to krok konfiguracji, który dodajesz do dowolnego interfejsu zarządzania, a nie coś, co jest domyślnie włączone.
Ta sama zasada dotyczy Zarządzanie Docker CLI i GUI; dostęp do demona na poziomie administratora niesie ze sobą to samo ryzyko niezależnie od interfejsu.
Brak monitorowania tego, co robią Twoje kontenery
Jeśli kontener zostanie naruszony, aktywność atakującego tworzy ślad: zmiany w zachowaniu procesu, nietypowe połączenia sieciowe i nieoczekiwane modyfikacje plików. Bez gromadzenia dzienników ślad ten nie istnieje w formie, na podstawie której można podjąć działania.
Scentralizowane gromadzenie dzienników, rejestrowanie inspekcji kontenerów i narzędzia do monitorowania środowiska wykonawczego zapewniają dane umożliwiające wykrycie nieprawidłowej aktywności, zanim się ona połączy. Celem nie jest analizowanie każdej linii. Oznacza to, że dane są dostępne, gdy trzeba je zbadać.
Konfiguracje kontenerów, które działają w trybie cichym w środowisku produkcyjnym, bez potoku dzienników i alertów, nie wymagają niewielkiej konserwacji. Są niesprawdzone. To dwa różne stany operacyjne.
Dlaczego środowisko infrastrukturalne również ma znaczenie
Bezpieczeństwo kontenera zaczyna się od konfiguracji, ale konfiguracja działa na infrastrukturze. Host z źle skonfigurowaną siecią, udostępnionymi zasobami lub bez filtrowania na poziomie sieci tworzy warunki, które wpływają na każdy kontener nad nim. Właściwa konfiguracja kontenera i właściwa konfiguracja serwera to dwa osobne zadania.
Wiele luk w zabezpieczeniach platformy Docker jest wzmacnianych przez warunki dziedziczone przez same kontenery:
- Serwer współdzielony bez izolacji sprzętowej pomiędzy dzierżawcami
- Jądro hosta działające bez poprawek
- Host bez wbudowanego filtrowania na poziomie sieci
Nie eliminuje to konieczności wykonywania powyższych kroków konfiguracyjnych, ponieważ odpowiednie wzmocnienie kontenera ma znaczenie niezależnie od warstwy infrastruktury. Rozpoczęcie od izolowanej infrastruktury eliminuje jeden poziom obaw z równania.
W Cloudzy oferujemy dwie ścieżki w zależności od wymagań Twojej konfiguracji:
- Serwer VPS z Linuksem: czyste środowisko do samodzielnego wdrożenia Dockera i zastosowania kroków wzmacniających opisanych w tym artykule
- Portainer VPS: opcja jednego kliknięcia z preinstalowanym Portainerem; serwer uruchamia się i jesteś już w panelu kontrolnym
Obie opcje działają na tej samej infrastrukturze: wirtualizacja KVM, procesory AMD Ryzen 9 z zegarem boost do 5,7 GHz, pamięć DDR5, pamięć masowa NVMe SSD, sieć do 40 Gb/s oraz bezpłatna ochrona DDoS poprzez filtrowanie BuyVM w 12 lokalizacjach na całym świecie z umową SLA na czas sprawności na poziomie 99,95%.
Aby uzyskać głębsze spojrzenie na uruchamianie Portainera na VPS, omówimy to w dedykowanym artykule.
Praktyczna lista kontrolna bezpieczeństwa dla wdrożeń platformy Docker
Powyższe błędy bezpieczeństwa Dockera wynikają głównie z pojedynczych decyzji konfiguracyjnych podjętych raz i nigdy nie wracanych do nich ponownie. Uruchomienie tej listy kontrolnej w odniesieniu do istniejącej konfiguracji pozwala wykryć te luki. Działa jako audyt, a nie przewodnik po wdrażaniu.
Te najlepsze praktyki dotyczące bezpieczeństwa platformy Docker dotyczą zabezpieczania kontenerów platformy Docker przed najczęstszymi błędami konfiguracji opisanymi powyżej.
Krótkie omówienie: wszystkie 9 błędów
| Błąd | Kategoria | Poprawka jednoliniowa |
| Działa jako root | Konfiguracja | Dodać UŻYTKOWNIK dyrektywę do pliku Dockerfile |
| Porty powiązane z 0.0.0.0 | Konfiguracja | Powiąż z 127.0.0.1 i kieruj przez odwrotne proxy |
| Brak izolacji sieci | Konfiguracja | Podziel usługi na oddzielne sieci zdefiniowane przez użytkownika w oparciu o potrzeby dostępu. |
| Zamontowane gniazdo Docker | Konfiguracja | Zdejmij uchwyt; używaj interfejsów API o ograniczonym zakresie lub alternatyw |
| Niezaufane lub nieaktualne obrazy | Obraz | Używaj oficjalnych obrazów z przypiętymi tagami wersji |
| Zakodowane na stałe sekrety | Obraz | Przenieś poświadczenia do środowisk wykonawczych lub menedżera wpisów tajnych |
| Brak harmonogramu odbudowy obrazu | Obraz | Ustaw miesięczną częstotliwość odbudowy; zautomatyzować, jeśli to możliwe |
| Nieuwierzytelnione pulpity nawigacyjne | Dostęp | Dodaj uwierzytelnianie i przenieś interfejsy zarządzania do sieci prywatnych |
| Brak gromadzenia dzienników kontenerów | Dostęp | Skonfiguruj scentralizowane rejestrowanie i monitorowanie czasu działania |
Zalecamy najpierw uruchomić go w oparciu o istniejące konfiguracje, ponieważ tam najprawdopodobniej już występują luki.
Kontenery działające jako użytkownik inny niż root: Sprawdź swoje pliki Dockerfile pod kątem dyrektywy USER. Jeśli żaden nie istnieje, kontener działa jako root.
Powiązania portów ograniczone do hosta lokalnego lub serwera proxy: Uruchom docker ps i przejrzyj powiązania portów. Wpis 0.0.0.0:PORT może być publicznie dostępny na hostach, gdzie nie blokuje go żadna nadrzędna grupa zabezpieczeń, zewnętrzna zapora ogniowa ani reguła łańcucha DOCKER-USER.
Używane niestandardowe sieci mostowe: Kontenery na domyślnym moście Dockera mogą swobodnie się ze sobą łączyć. Kontenery na tym samym moście zdefiniowanym przez użytkownika mogą nadal komunikować się ze sobą, dlatego należy podzielić usługi w oddzielnych sieciach według granicy zaufania w celu rzeczywistej izolacji.
Gniazdo dokujące nie montowane w kontenerach: Zaznacz opcję Utwórz pliki i uruchom argumenty. Jeśli /var/run/docker.sock pojawia się jako wolumin, potwierdź, że jest to wymagane i zamierzone.
Obrazy bazowe od zweryfikowanych wydawców z przypiętymi wersjami: A FROM ubuntu:latest pobiera nieokreśloną, potencjalnie nieaktualną wersję. Przypnij do konkretnej wersji.
Żadnych tajemnic w plikach Dockerfile, plikach Compose ani argumentach kompilacji: Historia warstwy obrazu zachowuje poświadczenia po usunięciu kontenera. Skorzystaj z funkcji tworzenia sekretów, roju sekretów, budowania tajnych wierzchowców lub zewnętrznego menedżera sekretów. Zmienne środowiskowe środowiska wykonawczego są lepsze niż wartości zakodowane na stałe, ale nadal pojawiają się w wynikach kontroli i dziennikach.
Zdefiniowano harmonogram przebudowy obrazu: Stare obrazy kumulują luki w zabezpieczeniach. Miesięczna częstotliwość odbudowy umożliwia zarządzanie oknem ekspozycji w przypadku większości konfiguracji.
Interfejsy zarządzania stojące za uwierzytelnianiem: Każdy pulpit nawigacyjny na publicznym adresie IP bez autoryzacji jest otwartym punktem wejścia. Jeśli to możliwe, preferowane jest umieszczanie w sieci prywatnej.
Gromadzone logi kontenerów: Bez potoku dziennika wykrywanie incydentów zależy od widocznego wpływu na system. To późny sygnał, że należy działać.
Wniosek
Domyślna konfiguracja Dockera została stworzona dla wygody, a nie bezpieczeństwa. Większość błędów opisanych w tym artykule wynika z ustawień, które nigdy nie zostały zmienione po pierwszym wdrożeniu, a nie z wyrafinowanych ataków.
Poprawki to głównie jednorazowe decyzje konfiguracyjne: dyrektywa USER, zmiana powiązania portów, niestandardowa sieć, harmonogram przebudowy. Żadne z nich nie wymaga nowego oprzyrządowania w przypadku większości konfiguracji.
Pierwszym zadaniem jest prawidłowe skonfigurowanie kontenera. Infrastruktura, na której działa, to drugie. Jedno i drugie ma znaczenie i żadne nie zastępuje drugiego.