System zarządzania konfiguracją sieciową filtracji Qrator

System zarządzania konfiguracją sieciową filtracji Qrator

TL;DR: Opis architektury klient-serwer naszego wewnętrznego systemu zarządzania konfiguracją sieci, QControl. Opiera się na dwupoziomowym protokole transportowym, który działa z pakietami wiadomości skompresowanymi w gzip bez dekompresji pomiędzy punktami końcowymi. Rozproszone routery i punkty końcowe otrzymują aktualizacje konfiguracji, a protokół ten umożliwia instalację lokalizowanych pośrednich przekaźników. System został zbudowany zgodnie z zasadą różnicowego backupu (“recent-stable”, wyjaśnione poniżej) i wykorzystuje język zapytań JMESpath wraz z silnikiem szablonów Jinja do renderowania plików konfiguracyjnych.

Qrator Labs zarządza globalnie rozproszoną siecią neutralizacji ataków. Nasza sieć działa na zasadzie anycast, a podsieci są ogłaszane za pomocą BGP. Jako sieć BGP anycast, fizycznie zlokalizowana w kilku regionach świata, możemy przetwarzać i filtrować nielegalny ruch bliżej rdzenia internetu — operatorów Tier-1.

Z drugiej strony, bycie geograficznie rozproszoną siecią nie jest proste. Komunikacja pomiędzy punktami obecności w sieci jest krytycznie ważna dla dostawcy usług bezpieczeństwa, aby mieć spójną konfigurację wszystkich węzłów sieci, aktualizując je w odpowiednim czasie. Dlatego, aby zapewnić maksymalny możliwy poziom podstawowej usługi dla konsumentów, musieliśmy znaleźć sposób na niezawodne synchronizowanie danych konfiguracyjnych pomiędzy kontynentami.

Na początku było Słowo. Szybko stało się protokołem komunikacyjnym, wymagającym aktualizacji.


Fundamentem istnienia QControl, a jednocześnie głównym powodem inwestowania znacznych ilości czasu i zasobów w stworzenie tego typu protokołu, jest konieczność posiadania jednolitego, autorytatywnego źródła konfiguracji oraz ostatecznie synchronizacji naszych punktów obecności z tym źródłem. Samo repozytorium było tylko jednym z kilku wymagań w trakcie rozwoju QControl. Poza tym potrzebne były również integracje z istniejącymi i planowanymi usługami na punktach obecności (PO), inteligentne (i konfigurowalne) metody weryfikacji danych, jak również zarządzanie dostępem. Dodatkowo, chcieliśmy zarządzać tym systemem za pomocą poleceń, a nie modyfikacji plików. Przed QControl dane były wysyłane do punktów obecności praktycznie ręcznie. Jeśli którykolwiek z punktów obecności był niedostępny i zapominaliśmy, aby go później zaktualizować, konfiguracja stawała się niesynchronizowana — trzeba było poświęcić czas na przywrócenie jej do stanu operacyjnego.

W rezultacie opracowaliśmy następujący schemat:
System zarządzania konfiguracją sieciową filtracji Qrator
Serwer konfiguracyjny jest odpowiedzialny za weryfikację danych i przechowywanie, router ma kilka punktów końcowych, które odbierają i przesyłają aktualizacje konfiguracji od klientów oraz zespołu wsparcia na serwer, a z serwera na punkty obecności.

Jakość połączenia internetowego wciąż znacznie różni się w różnych zakątkach świata — dla ilustracji tej tezy, przyjrzyjmy się prostemu MTR z Pragi, Czechy do Singapuru i Hongkongu.

System zarządzania konfiguracją sieciową filtracji Qrator
MTR z Pragi do Singapuru

System zarządzania konfiguracją sieciową filtracji Qrator
To samo do Hongkongu

Wysokie opóźnienia oznaczają mniejszą prędkość. Ponadto występują utraty pakietów. Szerokość pasma nie rekompensuje tego problemu, który zawsze należy brać pod uwagę przy budowaniu zdecentralizowanych systemów.

Pełna konfiguracja punktu obecności to znaczna ilość danych, które trzeba przesłać do wielu odbiorców przez niestabilne połączenia. Na szczęście, mimo że konfiguracja ciągle się zmienia, odbywa się to w niewielkich porcjach.

Projekt recent-stable

Można powiedzieć, że budowanie rozproszonej sieci na zasadzie inkrementalnych aktualizacji jest dość oczywistym rozwiązaniem. Jednak z różnicami związane jest wiele problemów. Musimy przechowywać wszystkie różnice między punktami odniesienia, a także mieć możliwość ich dosyłania w przypadku, gdy ktoś przegapił część danych. Każdy punkt docelowy musi stosować je w ściśle określonej kolejności. Zwykle w przypadku wielu punktów docelowych taka operacja może zająć dużo czasu. Odbiorca również musi być w stanie zażądać brakujących części i, oczywiście, centralna część powinna poprawnie odpowiedzieć na to żądanie, wysyłając tylko brakujące dane.

Ostatecznie doszliśmy do dość interesującego rozwiązania — mamy tylko jedną warstwę odniesienia, stałą, nazwijmy ją stable, i tylko jedną różnicę dla niej — recent. Każda różnica recent oparta jest na ostatniej utworzonej stabilnej wersji i jest wystarczająca do odbudowy danych konfiguracyjnych. Gdy nowy recent dotrze do miejsca przeznaczenia, stary już nie jest potrzebny.

Pozostaje jedynie od czasu do czasu wysyłać świeżą konfigurację stable, na przykład ponieważ recent stał się zbyt duży. Ważne jest również to, że rozsyłamy wszystkie te aktualizacje w trybie broadcast/multicast, nie martwiąc się o pojedynczych odbiorców i ich zdolność do zebrania danych razem. Gdy upewnimy się, że wszyscy mają poprawną wersję stable — wysyłamy tylko nowe wartości recent. Czy warto podkreślać, że to działa? Działa. Stable jest buforowane na serwerze konfiguracyjnym i u odbiorców, a recent powstaje w razie potrzeby.

Architektura transportu dwuetapowego

Dlaczego zbudowaliśmy nasz transport na dwóch poziomach? Odpowiedź jest dość prosta — chcieliśmy oddzielić trasowanie od logiki wysokiego poziomu, czerpiąc inspirację z modelu OSI z jego poziomem transportu i poziomem aplikacji. Jako protokół transportowy wybraliśmy Thrift, a dla wysokopoziomowego formatu komunikatów kontrolnych — format serializacji msgpack. Dlatego router (realizujący multicast/broadcast/relay) nie zagląda wewnątrz msgpack, nie rozpakowuje i nie pakuje zawartości z powrotem i wykonuje tylko przesyłanie danych.

Thrift (z ang. „oszczędność”, wymawiane jako [θrift]) to język opisu interfejsów, który służy do definiowania i tworzenia usług w różnych językach programowania. Jest ramą do zdalnego wywoływania procedur (RPC). Łączy w sobie programowy potok z silnikiem generacji kodu do opracowywania usług, które w pewnym zakresie efektywnie i łatwo działają między językami.

Zdecydowaliśmy się na ramy Thrift ze względu na RPC i wsparcie dla wielu języków. Jak zwykle, łatwe części stanowiły klient i serwer. Jednak router okazał się twardym orzechem do zgryzienia, częściowo z powodu braku gotowego rozwiązania podczas naszej pracy.

System zarządzania konfiguracją sieciową filtracji QratorIstnieją również inne opcje, takie jak protobuf / gRPC, jednak gdy zaczynaliśmy nasz projekt, gRPC było stosunkowo nowe i nie zdecydowaliśmy się go wprowadzać.

Oczywiście mogliśmy (i właściwie powinniśmy byli) stworzyć własny projekt. Łatwiej byłoby stworzyć protokół dla naszych potrzeb, ponieważ architektura klient-serwer jest relatywnie prosta do wdrożenia w porównaniu do budowy routera opartego na Thrift. Tak czy inaczej, istnieje tradycyjne uprzedzenie wobec własnych protokołów i implementacji popularnych bibliotek, a dodatkowo zawsze pojawia się pytanie: „Jak przeniesiemy to na inne języki?”. Dlatego od razu odrzuciliśmy pomysły na własny projekt.

Msgpack to odpowiednik JSON, ale szybszy i mniejszy. To binarny format serializacji danych, który pozwala na wymianę danych między wieloma językami.

Na pierwszym poziomie mamy Thrift z minimalną potrzebną informacją dla routera do przesyłania wiadomości. Na drugim poziomie znajdują się spakowane struktury msgpack.

Wybraliśmy msgpack, ponieważ jest szybszy i bardziej kompaktowy w porównaniu do JSON. Ale co ważniejsze, wspiera niestandardowe typy danych, co pozwala nam korzystać z fajnych funkcji, takich jak przesyłanie surowych danych binarnych lub specjalnych obiektów wskazujących na brak danych, co było kluczowe dla naszej schemy „recent-stable”.

JMESPath
JMESPath to język zapytań do JSON.
Tak właśnie wygląda opis, który uzyskujemy z oficjalnej dokumentacji JMESPath, ale w rzeczywistości oferuje on znacznie więcej. JMESPath pozwala na wyszukiwanie i filtrowanie poddrzew w dowolnej strukturze drzewiastej, a także na wprowadzanie zmian do danych w locie. Dodatkowo umożliwia dodawanie specjalnych filtrów i procedur transformacji danych. Choć oczywiście wymaga wysiłku umysłowego, aby to zrozumieć.

Jinja
Dla niektórych klientów musimy przekształcić konfigurację w plik — dlatego używamy silnika szablonów, a Jinja jest oczywistym wyborem. Dzięki niej generujemy plik konfiguracyjny z szablonu i danych uzyskanych w punkcie docelowym.

Aby wygenerować plik konfiguracyjny, potrzebujemy zapytania JMESPath, szablonu dla lokalizacji pliku w systemie plików, oraz szablonu samej konfiguracji. W tym etapie dobrze jest również określić uprawnienia do pliku. Wszystko to udało się pomyślnie połączyć w jednym pliku — na początku szablonu konfiguracji umieszczamy nagłówek w formacie YAML, opisujący pozostałe elementy.

Na przykład:

---
wskaźnik: "[@][?@.fft._meta.version == `42`] | items([0].fft_config || `{}`)"
docelowa_nazwa_pliku: "fft/{{ match[0] }}.json"
tryb_pliku: 0644
przeładuj_demony: [fft]
...
{{ dict(match[1]) | json(indent=2, sort_keys=True) }}

Aby stworzyć plik konfiguracyjny dla nowej usługi, dodajemy tylko nowy plik szablonu. Nie są wymagane żadne zmiany w kodzie źródłowym ani oprogramowaniu w punktach obecności.

Co zmieniło się po wprowadzeniu QControl do działalności operacyjnej? Pierwsza i najważniejsza rzecz — spójna i niezawodna dostawa aktualizacji konfiguracji do wszystkich węzłów sieci. Drugie — uzyskanie potężnego narzędzia do weryfikacji konfiguracji i wprowadzania w niej zmian przez nasz zespół wsparcia oraz użytkowników usługi.

Udało nam się to osiągnąć, wykorzystując schemat aktualizacji recent-stable w celu uproszczenia komunikacji między serwerem konfiguracyjnym a odbiorcami konfiguracji. Używając dwupoziomowego protokołu do wsparcia niezależnego od zawartości sposobu routingu danych. Skutecznie zintegrowaliśmy oparty na Jinja silnik generacji konfiguracji w rozdzielonej sieci filtracji. System ten wspiera szeroką gamę metod konfiguracji dla naszej rozproszonej i zróżnicowanej infrastruktury.

Dziękujemy za pomoc w napisaniu materiału. VolanDamrod, serenheit, NoN.

Wersja angielska postu.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster