Sistemul de management al configurației rețelei de filtrare Qrator

Sistemul de management al configurației rețelei de filtrare Qrator

TL;DR: Descrierea arhitecturii client-server a sistemului nostru intern de gestionare a configurației rețelei, QControl. La bază se află un protocol de transport în două niveluri, care funcționează cu mesaje împachetate în gzip fără decompresie între punctele finale. Routerele distribuite și punctele finale primesc actualizări de configurație, iar protocolul permite instalarea de relee intermediare localizate. Sistemul este construit pe principiul backup-ului diferențial ('recent-stable', explicat mai jos) și folosește limbajul de interogare JMESpath împreună cu motorul de șablonare Jinja pentru a genera fișierele de configurație.

Qrator Labs administrează o rețea global distribuită de neutralizare a atacurilor. Rețeaua noastră funcționează pe principiul anycast, iar subrețelele sunt anunțate prin BGP. Fiind o rețea anycast BGP, situată fizic în mai multe regiuni ale Pământului, putem procesa și filtra traficul nelegitim mai aproape de nucleul internetului — operatorii Tier-1.

Pe de altă parte, a fi o rețea geografic distribuită nu este ușor. Comunicația între punctele de prezență a rețelei este critică pentru furnizorul de servicii de securitate, pentru a avea o configurație coerentă a tuturor nodurilor rețelei, actualizându-le la timp. Prin urmare, pentru a oferi cel mai înalt nivel posibil de serviciu de bază pentru consumator, a fost necesar să găsim o modalitate de a sincroniza fiabil datele de configurație între continente.

La început a fost Cuvântul. Acesta a devenit rapid un protocol de comunicare, care avea nevoie de actualizare.


Piatra de temelie a existenței QControl și, în același timp, motivul principal pentru care a fost cheltuit un timp și resurse semnificative pentru a construi un asemenea protocol este necesitatea de a obține o sursă unică și autorizată de configurare și, în cele din urmă, de a sincroniza punctele noastre de prezență cu ea. Stocarea în sine a fost doar unul dintre numeroasele cerințe în timpul dezvoltării QControl. Pe lângă aceasta, aveam nevoie și de integrări cu serviciile existente și planificate la punctele de prezență (TP), metode inteligente (și personalizabile) de validare a datelor, precum și limitarea accesului. De asemenea, ne-am dorit să gestionăm un astfel de sistem prin comenzi, nu prin modificări ale fișierelor. Până la QControl, datele erau trimise la punctele de prezență aproape manual. Dacă unul dintre punctele de prezență era inaccesibil și uitam să-l actualizăm ulterior, configurația devenea desincronizată – era necesar să investim timp pentru a o readuce la normal.

În cele din urmă, am venit cu următoarea schemă:
Sistemul de management al configurației rețelei de filtrare Qrator
Serverul de configurare este responsabil pentru validarea datelor și stocare, routerul are mai multe endpointuri care primesc și transmiț în actualizările de configurare de la clienți și echipa de suport către server, iar de la server către punctele de prezență.

Calitatea conexiunii la internet variază semnificativ în diferite colțuri ale lumii — pentru a ilustra această teză, haideți să ne uităm la un simplu MTR din Praga, Republica Cehă, în Singapore și Hong Kong.

Sistemul de management al configurației rețelei de filtrare Qrator
MTR din Praga în Singapore

Sistemul de management al configurației rețelei de filtrare Qrator
Același lucru pentru Hong Kong

Întârzierea ridicată înseamnă viteză mai mică. Pe lângă aceasta, există pierderi de pachete. Lățimea canalelor nu compensează această problemă, care trebuie luată întotdeauna în considerare atunci când se construiesc sisteme descentralizate.

Configurarea completă a punctului de prezență reprezintă un volum semnificativ de date care trebuie trimise mulți destinatari prin conexiuni nesigure. Din fericire, deși configurația se schimbă constant, acest lucru se întâmplă în porții mici.

Design recent-stabil

Se poate spune că construirea unei rețele distribuite pe baza principiului actualizărilor incramentale este o soluție destul de evidentă. Dar există o mulțime de probleme legate de difuri. Trebuie să păstrăm toate difurile între punctele de referință și să fim capabili să le trimitem în cazul în care cineva a pierdut o parte din date. Fiecare punct de destinație trebuie să le aplice într-o succesiune strict definită. De obicei, în cazul mai multor puncte de destinație, o astfel de operațiune poate dura un timp considerabil. Destinatarul trebuie, de asemenea, să fie în măsură să solicite părțile pierdute și, desigur, partea centrală trebuie să răspundă corect la o astfel de solicitare, trimițând doar datele lipsă.

În cele din urmă, am ajuns la o soluție destul de interesantă — avem doar un singur strat de referință, fix, pe care îl numim stable, și doar un dif pentru acesta — recent. Fiecare recent se bazează pe ultimul stable generat și este suficient pentru a reconstrui datele de configurare. Atunci când un recent proaspăt ajunge la destinație, cel vechi nu mai este necesar.

Rămâne doar să trimitem din când în când o configurație stable proaspătă, de exemplu, deoarece recent a devenit prea mare. De asemenea, este important de menționat că trimitem toate aceste actualizări în mod broadcast/multicast, fără a ne îngrijora de destinatari individuali și de capacitatea lor de a aduna bucățile de date. Odată ce ne-am asigurat că toți au o stable corectă — trimitem doar noul recent. Merită să subliniem că funcționează? Funcționează. Stable este stocată în cache pe serverul de configurare și pe destinatari, recent este generat la nevoie.

Arhitectura transportului pe două niveluri

De ce am construit transportul nostru pe două niveluri? Răspunsul este destul de simplu — dorim să separăm rutarea de logica de înalt nivel, inspirându-ne din modelul OSI cu nivelul său de transport și nivelul aplicațiilor. Pentru rolul protocolului de transport am ales Thrift, iar pentru formatul de înalt nivel al mesajelor de control — formatul de serializare msgpack. Tocmai de aceea, routerul (care efectuează multicast/broadcast/relay) nu se uită în interiorul msgpack, nu despachetează și nu reprogramează conținutul și efectuează doar transmiterea datelor.

Thrift (din engleză - „economisire”, pronunțat ca [θrift]) este un limbaj de descriere a interfețelor, folosit pentru a defini și crea servicii pentru diferite limbi de programare. Este un cadru pentru apeluri de proceduri la distanță (RPC). Combină un canal de procesare software cu un motor de generare a codului pentru a dezvolta servicii care funcționează eficient și ușor între limbi.

Am ales cadrul Thrift din cauza RPC-ului și suportului pentru multe limbi. Ca de obicei, părțile ușoare au fost clientul și serverul. Totuși, routerul s-a dovedit a fi o nucă tare, în parte din cauza lipsei unei soluții gata făcute în timpul dezvoltării noastre.

Sistemul de management al configurației rețelei de filtrare QratorExistă și alte opțiuni, precum protobuf / gRPC, totuși, când am început proiectul nostru, gRPC era destul de tânăr și nu ne-am riscat să-l adoptăm.

Desigur, am fi putut (și de fapt, ar fi fost mai bine să facem asta) să ne creăm propriul nostru protocol. Ar fi fost mai simplu să creăm un protocol pentru ceea ce aveam nevoie, deoarece arhitectura client-server este relativ simplă în implementare comparativ cu construirea unui router pe Thrift. În orice caz, există o tradiție de prejudecată împotriva protocoalelor scrise de mână și a implementărilor bibliotecilor populare, de asemenea, întrebarea care apare întotdeauna este: „Cum vom porta asta pe alte limbi?”. Așadar, am abandonat imediat ideile despre bicicletă.

Msgpack este un echivalent al JSON, dar mai rapid și mai compact. Este un format binar de serializare a datelor care permite schimbul de informații între multe limbi.

La primul nivel avem Thrift cu minimul de informații necesar routerului pentru a trimite mesajul. La al doilea nivel sunt structurile ambalate în msgpack.

Am ales msgpack deoarece este mai rapid și mai compact în comparație cu JSON. Dar ceea ce este și mai important, acesta suportă tipuri personalizate de date, permițându-ne să folosim caracteristici interesante precum transmiterea binarilor brute sau a obiectelor speciale care indică absența datelor, ceea ce a fost important pentru schema noastră „recent-stable”.

JMESPath
JMESPath este un limbaj de interogare pentru JSON.
Aceasta este descrierea pe care o primim din documentația oficială JMESPath, dar de fapt oferă mult mai mult. JMESPath permite căutarea și filtrarea subarborilor într-o structură de arbore arbitrară, precum și aplicarea de modificări datelor în timp real. De asemenea, permite adăugarea de filtre speciale și proceduri de transformare a datelor. Cu toate acestea, necesită, desigur, un efort mental considerabil pentru a fi înțeles.

Jinja
Pentru anumite persoane, trebuie să transformăm configurația într-un fișier — de aceea folosim un motor de șabloane, iar Jinja este alegerea evidentă. Cu ajutorul acesteia, generăm fișierul de configurație din șablon și datele obținute în punctul de destinație.

Pentru a genera fișierul de configurație, avem nevoie de o interogare JMESPath, un șablon pentru locația fișierului în sistemul de fișiere, un șablon pentru fișierul de configurație. De asemenea, în această etapă este util să clarificăm permisiunile de acces la fișier. Toate acestea au fost combinate cu succes într-un singur fișier — înainte de a începe șablonul de configurație, plasăm un antet în format YAML, descriind celelalte elemente.

De exemplu:

---
selector: "[@][?@.fft._meta.version == `42`] | items([0].fft_config || `{}`)"
destination_filename: "fft/{{ match[0] }}.json"
file_mode: 0644
reload_daemons: [fft]
...
{{ dict(match[1]) | json(indent=2, sort_keys=True) }}

Pentru a crea fișierul de configurație pentru un nou serviciu, adăugăm doar un nou fișier de șablon. Nu sunt necesare modificări ale codului sursă sau software-ului la punctele de prezență.

Ce s-a schimbat după implementarea QControl în activitatea operațională? Primul și cel mai important lucru — livrarea consistentă și fiabilă a actualizărilor de configurație pe toate nodurile rețelei. Al doilea — obținerea unui instrument puternic de verificare a configurației și de modificare a acesteia de către echipa noastră de suport, precum și de către consumatorii serviciului.

Toate acestea au fost realizate folosind schema de actualizări recent-stable pentru a simplifica comunicarea între serverul de configurație și destinatarii configurației. Folosind un protocol cu două niveluri pentru a susține un mod de rutare a datelor independent de conținut. Am integrat cu succes un motor de generare a configurației bazat pe Jinja într-o rețea distribuită de filtrare. Acest sistem suportă o gamă largă de modalități de configurare pentru periferia noastră distribuită și diversificată.

Mulțumesc pentru ajutor în redactarea materialului. VolanDamrod, serenitate, NoN.

Versiunea în engleză post.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster