Dlaczego procesy w kontenerach Dockera nie powinny działać jako root

Opublikowany: 2022-08-19

Grafika przedstawiająca logo Docker

Procesy w kontenerze Docker nie powinny być uruchamiane jako root. Bezpieczniej jest uruchamiać aplikacje jako użytkownik inny niż root, który określasz jako część pliku Dockerfile lub podczas korzystania z docker docker run . Minimalizuje to ryzyko, prezentując zmniejszoną powierzchnię ataku na wszelkie zagrożenia w Twoim kontenerze.

W tym artykule dowiesz się o zagrożeniach związanych z uruchamianiem aplikacji kontenerowych jako root. Zobaczysz również, jak utworzyć użytkownika innego niż root i skonfigurować przestrzeń nazw w sytuacjach, w których nie jest to możliwe.

Dlaczego bieganie jest niebezpieczne dla roota?

Kontenery są domyślnie uruchamiane jako root. Demon Docker jest wykonywany jako root na twoim hoście, a uruchomione kontenery również będą rootem.

Chociaż może się wydawać, że root w kontenerze jest niezależnym użytkownikiem, w rzeczywistości jest to to samo, co konto root na twoim hoście. Separację zapewniają tylko mechanizmy izolacji kontenerów platformy Docker. Nie ma silnej fizycznej granicy; inny proces twojego kontenera uruchamiany przez użytkownika root w jądrze hosta. Oznacza to, że luka w Twojej aplikacji, środowisku uruchomieniowym platformy Docker lub jądrze systemu Linux może umożliwić atakującym wyrwanie się z kontenera i wykonanie na komputerze operacji z uprawnieniami roota.

Istnieje kilka wbudowanych zabezpieczeń, które zmniejszają ryzyko takiego zdarzenia. Root wewnątrz kontenera jest nieuprzywilejowany i ma ograniczone możliwości. Uniemożliwia to kontenerowi korzystanie z poleceń administracyjnych systemu, chyba że ręcznie dodasz możliwości lub użyjesz trybu uprzywilejowanego podczas uruchamiania kontenerów.

Pomimo tego ograniczenia, pozwolenie aplikacjom na uruchamianie jako root pozostaje zagrożeniem. Tak jak ograniczyłbyś użycie roota w tradycyjnym środowisku, niemądre jest niepotrzebne używanie go w swoich kontenerach. Zapewniasz nadmiernie uprzywilejowane środowisko, które daje atakującym większą przyczółek w przypadku wystąpienia naruszenia.

Uruchamianie aplikacji kontenerowych jako użytkownik inny niż root

Najlepszym rozwiązaniem w przypadku aplikacji kontenerowych jest uruchamianie jako zwykły użytkownik. Większość oprogramowania nie wymaga dostępu do roota, więc zmiana użytkownika zapewnia natychmiastową ochronę przed pęknięciem kontenera.

Powinieneś utworzyć nowe konto użytkownika jako jeden z ostatnich etapów w pliku Dockerfile. Możesz to osiągnąć za pomocą instrukcji USER :

 Z obrazu bazowego: najnowszy
URUCHOM apt install demo-pakiet
USER demo-user:demo-group
PUNKT WEJŚCIOWY ["demo-binarny"]

Kontenery uruchomione z tego obrazu będą działały jako demo-user . Użytkownik będzie członkiem grupy demo-group group. Możesz pominąć nazwę grupy, jeśli nie chcesz, aby użytkownik był w grupie:

 USER demo-użytkownik

Zamiast nazw możesz podać identyfikator użytkownika (UID) i identyfikator grupy (GID):

 UŻYTKOWNIK 950:950

Przypisanie znanego UID i GID jest zwykle najbezpieczniejszym sposobem postępowania. Zapobiega mapowaniu użytkownika w kontenerze na nadmiernie uprzywilejowane konto hosta.

USER jest często określany jako przedostatni etap w pliku Dockerfile. Oznacza to, że nadal możesz uruchamiać operacje wymagające rootowania wcześniej w kompilacji obrazu. Instrukcja apt install w powyższym przykładzie ma uzasadnioną potrzebę rootowania. Jeśli instrukcja USER zostałaby umieszczona nad nim, apt zostałby uruchomiony jako demo-user który nie posiadałby niezbędnych uprawnień. Ponieważ instrukcje Dockerfile dotyczą tylko kompilacji obrazów, a nie uruchomionych kontenerów, można bezpiecznie pozostawić zmianę użytkownika na później w pliku Dockerfile.

Zmiana użytkownika uruchamianego przez kontener może wymagać zaktualizowania uprawnień do plików i folderów, do których uzyskuje dostęp. Ustaw własność na dowolnych ścieżkach, które będą używane przez Twoją aplikację:

 KOPIUJ Initial-config.yaml /data/config.yaml

USER demo-user:demo-group
URUCHOM chown demo-user:demo-group /data

W tym przykładzie katalog /data musi należeć do demo-user aby aplikacja mogła wprowadzać zmiany w swoim pliku konfiguracyjnym. Wcześniejsza instrukcja COPY skopiuje plik jako root. Skrót jest dostępny za pomocą flagi --chown z copy :

 KOPIUJ --chown=demo-user:demo-group Initial-config.yaml /data/config.yaml

Zmiana użytkownika podczas uruchamiania kontenera

Chociaż możesz łatwo zmienić użytkownika we własnych plikach Docker, wiele aplikacji innych firm nadal działa jako root. Ryzyko związane z ich użyciem można zmniejszyć, ustawiając flagę --user przy każdym wywołaniu docker run . Zastępuje to użytkownika ustawionego w pliku Dockerfile obrazu.

 $ docker run -d --user demo-user:demo-group obraz-demo:ostatni
$ docker run -d --user demo-user demo-image: najnowszy
$ docker run -d --user 950:950 obraz demonstracyjny: najnowszy

Flaga --user uruchamia proces kontenera jako określony użytkownik. Jest mniej bezpieczna niż instrukcja Dockerfile USER , ponieważ trzeba ją zastosować indywidualnie do każdego polecenia docker run dockera. Lepszą opcją w przypadku regularnie używanych obrazów jest utworzenie własnego obrazu pochodnego, który może założyć nowe konto użytkownika:

 OD obrazu, który działa jako root: najnowszy
USER demo-użytkownik
 $ kompilacja dockera . -t obraz-który-teraz-działa-jako-nie root:najnowszy

Zmiana użytkownika obrazu innej firmy może spowodować problemy: jeśli kontener oczekuje na uruchomienie jako root lub potrzebuje dostępu do ścieżek systemu plików należących do roota, podczas korzystania z aplikacji pojawią się błędy. Możesz spróbować ręcznie zmienić uprawnienia na ścieżkach, które powodują problemy. Alternatywnie sprawdź, czy dostawca ma obsługiwaną metodę uruchamiania aplikacji z kontem użytkownika bez uprawnień.

Obsługa aplikacji, które muszą działać jako root

Przestrzenie nazw użytkowników to technika radzenia sobie z aplikacjami, które wymagają pewnych uprawnień administratora. Pozwala mapować root wewnątrz kontenera na użytkownika innego niż root na twoim hoście. Symulowany root w kontenerze ma uprawnienia, których potrzebuje, ale wybicie nie zapewni hostowi dostępu do roota.

Zmiana mapowania przestrzeni nazw jest aktywowana poprzez dodanie pola userns-remap do pliku /etc/docker/daemon.json :

 {
    "userns-remap": "domyślny"
}

Użycie default jako wartości dla userns-remap nakazuje Dockerowi automatyczne utworzenie nowego użytkownika na twoim hoście o nazwie dockremap . Root w kontenerach zostanie zmapowany z powrotem do mapy dockremap na Twoim hoście. Możesz opcjonalnie określić istniejącego użytkownika i grupę, używając kombinacji UID/GID lub nazwy użytkownika/nazwy grupy:

 {
    "userns-remap": "użytkownik demo"
}

Po zastosowaniu zmiany uruchom ponownie demona Docker:

 $ restart dokera usługi sudo

Jeśli używasz nsuser-remap: default , użytkownik dockremap powinien teraz istnieć na twoim hoście:

 $ ID mapy dok

uid=140(dockremap) gid=119(dockremap) groups=119(dockremap)

Użytkownik powinien również pojawić się w /etc/subuid i /etc/subgid identyfikatorów podrzędnych:

 $ mapa doków: 231500:65535

Użytkownikowi przydzielono zakres 65 535 identyfikatorów podrzędnych, począwszy od 231500. W przestrzeni nazw użytkownika identyfikator 231500 jest mapowany na 0 , co czyni go użytkownikiem root w Twoich kontenerach. Będąc identyfikatorem UID o wysokim numerze, 231500 nie ma żadnych uprawnień na hoście, więc ataki przełamywania kontenerów nie będą w stanie zadać tak dużych obrażeń.

Wszystkie uruchomione kontenery będą uruchamiane przy użyciu zmienionej przestrzeni nazw użytkownika, chyba że zrezygnujesz z docker run --userns=host . Mechanizm działa poprzez tworzenie katalogów z przestrzenią nazw w /var/lib/docker , które są własnością podrzędnego UID i GID użytkownika z przestrzenią nazw:

 $ sudo ls -l /var/lib/docker/231500.231500

łącznie 14
drwx------ 5 231500 231500 13 lipca 22 19:00 aufs
drwx------ 3 231500 231500 13 lipca 22 19:00 kontenerów
...

Przestrzenie nazw użytkowników to skuteczny sposób na zwiększenie izolacji kontenerów, unikanie wybić i zachowanie zgodności z aplikacjami, które wymagają uprawnień administratora. Istnieją jednak pewne kompromisy: funkcja działa najlepiej na świeżej instancji platformy Docker, woluminy zamontowane z hosta muszą mieć dostosowane uprawnienia, a niektóre zewnętrzne sterowniki pamięci masowej w ogóle nie obsługują mapowania użytkowników. Przed przyjęciem tej opcji należy zapoznać się z dokumentacją.

Streszczenie

Uruchamianie aplikacji kontenerowych jako root stanowi zagrożenie bezpieczeństwa. Chociaż łatwo przeoczyć, izolacja zapewniana przez kontenery nie jest wystarczająco silna, aby w pełni oddzielić użytkowników jądra od użytkowników kontenerów. Root w kontenerze jest taki sam jak root na twoim hoście, więc udany kompromis może zapewnić kontrolę nad twoją maszyną.

Jako autor obrazu powinieneś dołączyć instrukcję USER w pliku Dockerfile, aby aplikacja działała bez uprawnień administratora. Użytkownicy obrazu mogą to zmienić za pomocą docker run --user , aby przypisać określony UID i GID. Pomaga to złagodzić przypadki, w których obraz zwykle używa roota.

Możesz jeszcze bardziej zwiększyć bezpieczeństwo, usuwając wszystkie możliwości z kontenera przy użyciu --cap-drop=ALL , a następnie umieszczając na białej liście te, które są wymagane za pomocą flag --cap-add . Połączenie tych technik spowoduje uruchomienie aplikacji jako użytkownik inny niż root z minimalnym zestawem wymaganych uprawnień, poprawiając stan bezpieczeństwa.