NET_ADMIN w kontenerze VPN: co i gdzie może zmienić
Uprawnienie pozwala na zmiany interfejsów, tras i zapory w obrębie jednej przestrzeni nazw sieci. W sieci hosta tą przestrzenią jest własny stos hosta.
NET_ADMIN to uprawnienie Linuksa, które pozwala procesowi wykonywać administrację sieci, a w kontenerze robi dokładnie to w tej przestrzeni nazw sieci, w której działa proces. Nie jest to licencja na otwarcie gniazda ani zamiennik urządzenia czy trasy. Ciekawe pytanie nigdy nie brzmi, czy uprawnienie przyznano, lecz która przestrzeń nazw otrzymuje zmianę.
Co obejmuje uprawnienie
W obrębie swojej przestrzeni nazw proces mający NET_ADMIN może podnosić i opuszczać interfejsy, przypisywać adresy, dodawać i usuwać trasy oraz pisać reguły zapory, czyli grupę operacji, którą capabilities(7) zbiera w ramach tego uprawnienia. Może też dostrajać ustawienia na poziomie interfejsu, które kontrolują, jak jądro kolejkuje i filtruje ruch. Klient VPN zwykle potrzebuje kilku z nich przy starcie i niczego więcej później. Dlatego większość obrazów prosi o szerszy zakres, niż wykorzystuje.
Operacje poza tą przestrzenią nazw nie są objęte, a sąsiednie uprawnienia są osobne. Czytanie i zapis surowych pakietów należy do NET_RAW, a utworzenie urządzenia tun wymaga zarówno uprawnienia, jak i dostępu do węzła urządzenia. Proces bez urządzenia otrzymuje błąd uprawnień, który wygląda jak problem sieci, ale nim nie jest.
Przestrzeń nazw decyduje o zasięgu szkód
Kontener we własnej sieci mostkowej dociera do własnego loopbacku, własnych interfejsów i własnej tablicy routingu. Przyznanie tam NET_ADMIN pozwala klientowi VPN zbudować tunel bez dotykania decyzji routingu hosta, co jest układem zakładanym przez większość obrazów kontenerów.
Przełącz ten kontener na sieć hosta, a to samo przyznanie edytuje teraz trasy hosta i zaporę hosta, ponieważ nie została już żadna osobna przestrzeń nazw. Klient, który miał zarządzać jednym tunelem, może wtedy przekierować ruch całej maszyny, a błąd w jego skrypcie demontażu zostawia na hoście reguły, których nikt nie napisał. W samym uprawnieniu nic się nie zmieniło; zmienił się kontekst. Dlatego ten sam plik compose zachowuje się inaczej na dwóch hostach.
Trzy warunki zlane w jeden
Błędy uruchamiania kontenerów VPN zwykle dotyczą jednej z trzech osobnych rzeczy: uprawnienia, urządzenia tunelu i wsparcia jądra dla protokołu. Przyznanie wszystkich trzech naraz działa i zarazem czyni następny błąd niemożliwym do przypisania. Minimalny fragment compose przyznaje uprawnienie i jawnie przekazuje węzeł urządzenia:
services:
vpn:
image: example/vpn-client:latest
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun
sysctls:
- net.ipv4.conf.all.src_valid_mark=1Przeczytaj dokumentację samego obrazu, jakich sysctl potrzebuje, ponieważ sysctl w kontenerze może wymagać dodatkowego uprawnienia lub ustawienia na poziomie hosta. Tam, gdzie obraz obsługuje tylko tryb przestrzeni użytkownika, urządzenie nie jest w ogóle potrzebne, a lista uprawnień odpowiednio się kurczy.
Przyznaj wąską operację, nie tryb
Tryb uprzywilejowany przekazuje każde uprawnienie i jednocześnie poszerza dostęp do urządzeń, więc ukrywa, którego z trzech warunków brakowało. Czyni też sposoby awarii kontenera nieodróżnialnymi od zmian na hoście. Preferuj jawną listę, nawet gdy jest dłuższa do napisania.
Wdrożenia bez roota i w przestrzeniach nazw użytkownika zmieniają praktyczne znaczenie uprawnienia, ponieważ proces może je mieć tylko w obrębie zmapowanej przestrzeni nazw. Kopiowanie listy uprawnień z przykładu z rootem do środowiska bez roota i oczekiwanie tego samego zasięgu to częsty sposób na utratę popołudnia.
Sekrety należą do osobnej decyzji. Posiadanie NET_ADMIN nic nie mówi o tym, jaką tożsamość partnera przedstawia klient, jakie dane uwierzytelniające ładuje ani jak są rotowane. Administracja siecią nie daje zaufania.
Zweryfikuj zmianę i zapisz, dlaczego przyznanie istnieje
Zanim zaczniesz debugować tunel, potwierdź, co kontener faktycznie otrzymał. Poniższa inspekcja raportuje dodane uprawnienia i tryb sieci, a następnie pokazuje, jak lista interfejsów wygląda od środka:
docker inspect --format '{{.HostConfig.CapAdd}} {{.HostConfig.NetworkMode}} {{.HostConfig.Privileged}}' vpn
docker exec vpn sh -c 'grep CapEff /proc/self/status'
docker exec vpn ip -br addr
docker exec vpn ip routeJeśli uprawnienie jest obecne, a lista interfejsów nadal jest pusta, klient zawiódł, zanim zdążył cokolwiek utworzyć, i następnym miejscem do sprawdzenia są logi kontenera. Jeśli tunel istnieje, ale ruch nie płynie, na następne pytanie odpowiada tablica routingu wewnątrz kontenera.
Przetestuj też ścieżkę demontażu, ponieważ klient piszący reguły zapory może je zostawić. Zatrzymaj kontener i ponownie sprawdź zestaw reguł hosta, jeśli używana jest sieć hosta. Przyznanie potrzebne tylko przez dwie sekundy przy starcie nie powinno być opisywane w pliku compose jako stały wymóg bez notatki, która to wyjaśnia.
Zapisz powód obok każdego uprawnienia: która operacja go potrzebowała i co zawodzi bez niego. Ta notatka przetrwa aktualizacje obrazu i to ona odróżnia przejrzaną listę uprawnień od listy, która urosła przez kopiowanie i wklejanie.