
Śledzenie połączeń („conntrack”) jest podstawową funkcją stosu sieciowego jądra Linux. Pozwala jądru na śledzenie wszystkich logicznych połączeń sieciowych lub strumieni, a tym samym identyfikację wszystkich pakietów, które tworzą każdy strumień, aby mogły być przetwarzane wspólnie w odpowiedniej kolejności.
Conntrack to ważna funkcja jądra, która jest wykorzystywana w niektórych podstawowych przypadkach:
- NAT polega na informacji z conntrack, dzięki czemu może równocześnie obsługiwać wszystkie pakiety z jednego strumienia. Na przykład, kiedy pod zwraca się do usługi Kubernetes, load balancer kube-proxy wykorzystuje NAT do kierowania ruchu do konkretnego pod w obrębie klastra. Conntrack zapisuje, że dla określonego połączenia wszystkie pakiety skierowane do IP usługi powinny być wysyłane do tego samego pod, oraz że pakiety zwracane przez backendowy pod powinny być kierowane przez NAT z powrotem do pod, z którego wyszedł żądanie.
- Zapory sieciowe z monitorowaniem stanu, takie jak Calico, polegają na informacji z conntrack, aby dodawać ruch „odpowiedzi” do białej listy. Pozwala to napisać politykę sieciową, która mówi: „zezwól mojemu podowi na łączenie się z dowolnym zdalnym adresem IP” bez konieczności pisania polityki dla jawnego zezwolenia na ruch zwrotny. (Bez tego musiałbyś dodać znacznie mniej bezpieczne zasady „zezwól na pakiety do mojego poda z dowolnego IP”.)
Ponadto, conntrack zazwyczaj zwiększa wydajność systemu (zmniejszając zużycie czasu procesora i opóźnienia pakietów), ponieważ tylko pierwszy pakiet w strumieniu
musi przejść pełne przetwarzanie stosu sieciowego, aby określić, co z nim zrobić. Zobacz post „”, aby zobaczyć przykład tego, jak to działa.
Niemniej jednak, conntrack ma swoje ograniczenia...
Więc gdzie wszystko poszło źle?
Tabela conntrack ma konfigurowalny maksymalny rozmiar, a jeśli się zapełni, połączenia zazwyczaj zaczynają być odrzucane lub przerywane. W przypadku przetwarzania ruchu większości aplikacji tabela ma wystarczająco dużo wolnego miejsca, i nigdy nie staje się to problemem. Niemniej jednak istnieje kilka scenariuszy, w których warto rozważyć użycie tabeli conntrack:
- Najbardziej oczywistym przypadkiem jest sytuacja, gdy twój serwer obsługuje wyjątkowo dużą liczbę aktywnych połączeń jednocześnie. Na przykład, jeśli twoja tabela conntrack jest ustawiona na 128 tys. rekordów, ale masz > 128 tys. jednoczesnych połączeń, na pewno napotkasz problem!
- Nieco mniej oczywisty przypadek: jeśli twój serwer obsługuje bardzo dużą liczbę połączeń na sekundę. Nawet jeśli połączenia są krótkotrwałe, są one śledzone przez system Linux przez pewien czas (domyślnie 120s). Na przykład, jeśli twoja tabela conntrack jest ustawiona na 128 tys. rekordów i próbujesz obsłużyć 1100 połączeń na sekundę, będą one przekraczać rozmiar tabeli conntrack, nawet jeśli połączenia są bardzo nietrwałe (128k / 120s = 1092 połączenia / s).
Istnieje kilka niszowych typów aplikacji, które mieszczą się w tych kategoriach. Dodatkowo, jeśli masz wielu przeciwników, to wypełnianie tabeli conntrack twojego serwera wieloma półotwartymi połączeniami może być wykorzystywane w ramach ataku typu "odmowa usługi" (DOS). W obu przypadkach conntrack może stać się ograniczającym wąskim gardłem w twoim systemie. W niektórych przypadkach dostosowanie parametrów tabeli conntrack może wystarczyć do zaspokojenia twoich potrzeb — poprzez zwiększenie rozmiaru lub skrócenie czasów oczekiwania conntrack (ale jeśli zrobisz to źle, napotkasz poważne trudności). W innych przypadkach konieczne będzie ominięcie conntrack dla agresywnego ruchu.
Przykład z życia wzięty
Podajmy konkretny przykład: jeden z dużych dostawców SaaS, z którym współpracowaliśmy, miał szereg serwerów memcached na hostach (nie maszynach wirtualnych), z których każdy obsługiwał ponad 50 tys. krótkotrwałych połączeń na sekundę.
Eksperymentowali z konfiguracją conntrack, zwiększali rozmiary tabel i skracali czasy śledzenia, ale konfiguracja była niestabilna, znacznie zwiększyło się zużycie RAM-u, co stanowiło problem (rzędu GB!), a połączenia były tak krótkie, że conntrack nie przynosił zwykłych korzyści w zakresie wydajności (redukcja zużycia CPU lub opóźnień pakietów).
Alternatywnie skontaktowali się z Calico. Polityki sieciowe Calico pozwalają na wyłączenie conntrack dla określonego rodzaju ruchu (korzystając z opcji doNotTrack). Zapewniło to im niezbędny poziom wydajności oraz dodatkowy poziom bezpieczeństwa, oferowany przez Calico.
Co trzeba zrobić, aby obejść conntrack?
- Polityki do-not-track zazwyczaj powinny być symetryczne. W przypadku dostawcy SaaS: ich aplikacje działały w zabezpieczonej strefie, dlatego dzięki polityce sieciowej mogli dodać do białej listy ruch z innych konkretnych aplikacji, którym zezwolono na dostęp do memcached.
- Polityka do-not-track nie uwzględnia kierunku połączenia. W ten sposób, w przypadku włamania do serwera memcached, teoretycznie można spróbować połączyć się z dowolnym z klientów memcached, jeśli używa on odpowiedniego portu źródłowego. Jednak jeśli prawidłowo zdefiniowano politykę sieciową dla klientów memcached, te próby połączenia i tak zostaną odrzucone po stronie klienta.
- Polityka do-not-track stosuje się do każdego pakietu, w przeciwieństwie do zwykłych polityk, które stosują się tylko do pierwszego pakietu w strumieniu. Może to zwiększyć zużycie zasobów CPU na jeden pakiet, ponieważ dla każdego pakietu trzeba zastosować politykę. Jednak w przypadku krótkotrwałych połączeń to zwiększone zużycie jest równoważone przez zmniejszenie zużycia zasobów na przetwarzanie conntrack. Na przykład, w przypadku dostawcy SaaS, liczba pakietów dla każdego połączenia była bardzo mała, dlatego dodatkowe zużycie zasobów CPU przy stosowaniu polityk do każdego pakietu było uzasadnione.
Przystąpmy do testów
Przeprowadziliśmy test na jednym podzie z serwerem memcached i wieloma podami klientów memcached uruchomionymi na zdalnych węzłach, abyśmy mogli uruchomić bardzo dużą liczbę połączeń na sekundę. Serwer z pod’iem memcached miał 8 rdzeni i 512k wpisów w tabeli conntrack (standardowo skonfigurowany rozmiar tabeli dla hosta).
Mierzyliśmy różnicę w wydajności między: bez polityki sieciowej; z normalną polityką Calico; a polityką Calico do-not-track.
Dla pierwszego testu ustawiliśmy liczbę połączeń na 4 000 na sekundę, dzięki czemu mogliśmy skupić się na różnicy w zużyciu CPU. Nie było istotnych różnic pomiędzy brakiem polityki a zwykłą polityką, ale polityka do-not-track zwiększyła zużycie CPU o około 20%.

W drugim teście uruchomiliśmy tyle połączeń, ile mogli wygenerować nasi klienci i mierzyliśmy maksymalną liczbę połączeń na sekundę, które mógł obsłużyć nasz serwer memcached. Jak się spodziewano, w przypadku „bez polityki” i „zwykłej polityki” oba osiągnęły limit conntrack powyżej 4 000 połączeń na sekundę (512k / 120s = 4 369 połączeń/s). Z polityką do-not-track nasi klienci wysyłali 60 000 połączeń na sekundę bez jakichkolwiek problemów. Jesteśmy pewni, że moglibyśmy zwiększyć tę liczbę, podłączając więcej klientów, ale uważamy, że te liczby są już wystarczające, aby zilustrować przesłanie tego artykułu!

Podsumowanie
Conntrack to ważna funkcja jądra. Doskonale spełnia swoje zadanie. Często jest wykorzystywana przez kluczowe komponenty systemu. Jednak w niektórych określonych scenariuszach przeciążenie spowodowane przez conntrack przewyższa normalne korzyści, które oferuje. W tym scenariuszu polityki sieciowe Calico mogą być wykorzystane do selektywnego wyłączenia użycia conntrack, jednocześnie zwiększając poziom bezpieczeństwa sieci. Dla całego pozostałego ruchu conntrack pozostaje Twoim towarzyszem!
Przeczytaj również inne artykuły na naszym blogu:
Źródło: habr.com
