Sistema di gestione della configurazione di rete di filtraggio Qrator

Sistema di gestione della configurazione di rete di filtraggio Qrator

TL; DR: Descrizione dell'architettura client-server del nostro sistema di gestione della configurazione della rete interna, QControl. Si basa su un protocollo di trasporto a due livelli che funziona con messaggi compressi in gzip senza decompressione tra gli endpoint. I router e gli endpoint distribuiti ricevono aggiornamenti di configurazione e il protocollo stesso consente l'installazione di relè intermedi localizzati. Il sistema è costruito sul principio backup differenziale ("recent-stable", spiegato di seguito) e utilizza il linguaggio di query JMESpath insieme al motore di template Jinja per eseguire il rendering dei file di configurazione.

Qrator Labs gestisce una rete di mitigazione degli attacchi distribuita a livello globale. La nostra rete funziona secondo il principio anycast e le sottoreti vengono pubblicizzate tramite BGP. Essendo una rete BGP anycast situata fisicamente in diverse regioni della Terra, possiamo elaborare e filtrare il traffico illegittimo più vicino al nucleo di Internet - operatori Tier-1.

D’altronde essere una rete geograficamente distribuita non è semplice. La comunicazione tra i punti di presenza della rete è fondamentale affinché il fornitore di servizi di sicurezza abbia una configurazione coerente di tutti i nodi della rete, aggiornandoli in modo tempestivo. Pertanto, per fornire al consumatore il livello più elevato possibile di servizio di base, dovevamo trovare un modo per sincronizzare in modo affidabile i dati di configurazione tra i continenti.

In principio era il Verbo. È diventato rapidamente un protocollo di comunicazione che necessitava di un aggiornamento.


La pietra angolare dell'esistenza di QControl, e allo stesso tempo il motivo principale per dedicare una notevole quantità di tempo e risorse alla creazione di questo tipo di protocollo, è la necessità di ottenere un'unica fonte autorevole di configurazione e, in definitiva, sincronizzare i nostri punti di presenza con esso. Lo storage stesso era solo uno dei numerosi requisiti durante lo sviluppo di QControl. Inoltre, avevamo bisogno anche di integrazioni con i servizi esistenti e pianificati presso i punti di presenza (POP), di metodi intelligenti (e personalizzabili) per la convalida dei dati e del controllo degli accessi. Oltre a ciò, volevamo anche controllare un sistema del genere utilizzando comandi anziché apportare modifiche ai file. Prima di QControl, i dati venivano inviati ai punti di presenza quasi manualmente. Se uno dei punti di presenza non fosse disponibile e ci dimenticassimo di aggiornarlo in seguito, la configurazione finirebbe per non essere sincronizzata e dovremmo perdere tempo per rimetterla in funzione.

Di conseguenza, abbiamo elaborato il seguente schema:
Sistema di gestione della configurazione di rete di filtraggio Qrator
Il server di configurazione è responsabile della convalida e dell'archiviazione dei dati; il router dispone di diversi endpoint che ricevono e trasmettono gli aggiornamenti di configurazione dai client e dai team di supporto al server e dal server ai punti di presenza.

La qualità della connessione Internet varia ancora ampiamente nel mondo: per illustrare questo punto, diamo un'occhiata a una semplice MTR da Praga, Repubblica Ceca, a Singapore e Hong Kong.

Sistema di gestione della configurazione di rete di filtraggio Qrator
MTR da Praga a Singapore

Sistema di gestione della configurazione di rete di filtraggio Qrator
Stessa cosa per Hong Kong

Una latenza elevata significa una velocità inferiore. Inoltre si verifica la perdita di pacchetti. La larghezza del canale non compensa questo problema, di cui bisogna sempre tenere conto quando si costruiscono sistemi decentralizzati.

La configurazione completa di un punto di presenza è una quantità significativa di dati che deve essere inviata a molti destinatari tramite connessioni inaffidabili. Fortunatamente, anche se la configurazione cambia costantemente, ciò avviene con piccoli incrementi.

Design stabile di recente

Possiamo dire che costruire una rete distribuita basata sul principio degli aggiornamenti incrementali è una soluzione abbastanza ovvia. Ma ci sono molti problemi con le differenze. Dobbiamo salvare tutte le differenze tra i punti di riferimento ed essere anche in grado di inviarle nuovamente nel caso qualcuno abbia perso parte dei dati. Ogni destinazione deve applicarli in una sequenza rigorosamente specificata. Tipicamente, nel caso di più destinazioni, tale operazione può richiedere molto tempo. Il ricevente deve essere in grado di richiedere anche le parti mancanti e, ovviamente, la parte centrale deve rispondere correttamente a tale richiesta, inviando solo i dati mancanti.

Di conseguenza, siamo giunti a una soluzione piuttosto interessante: abbiamo solo un livello di riferimento, fisso, chiamiamolo stabile, e solo una differenza per esso - recente. Ogni recente si basa sull'ultima stabile generata ed è sufficiente per ricostruire i dati di configurazione. Non appena quello fresco e recente arriva a destinazione, quello vecchio non serve più.

Non resta che inviare di tanto in tanto una nuova configurazione stabile, ad esempio perché recente è diventata troppo grande. Ciò che è anche importante qui è che inviamo tutti questi aggiornamenti in modalità broadcast/multicast, senza preoccuparci dei singoli destinatari e della loro capacità di mettere insieme pezzi di dati. Una volta che siamo sicuri che tutti abbiano la stalla corretta, inviamo solo quelle nuove e recenti. Vale la pena chiarire che funziona? Lavori. Stabile viene memorizzato nella cache del server di configurazione e dei destinatari, recente viene creato secondo necessità.

Architettura del trasporto a due livelli

Perché abbiamo costruito il nostro trasporto su due livelli? La risposta è abbastanza semplice: volevamo disaccoppiare il routing dalla logica di alto livello, ispirandoci al modello OSI con i suoi livelli di trasporto e applicazione. Abbiamo utilizzato Thrift per il ruolo del protocollo di trasporto e il formato di serializzazione msgpack per il formato di alto livello dei messaggi di controllo. Questo è il motivo per cui il router (eseguendo multicast/broadcast/relay) non guarda all'interno di msgpack, non decomprime o ricomprime i contenuti e inoltra solo i dati.

Thrift (dall'inglese - "thrift", pronunciato [θrift]) è un linguaggio di descrizione dell'interfaccia utilizzato per definire e creare servizi per diversi linguaggi di programmazione. È un framework per chiamate di procedure remote (RPC). Combina una pipeline software con un motore di generazione di codice per sviluppare servizi che funzionano in modo più o meno efficiente e semplice tra le lingue.

Abbiamo scelto il framework Thrift per via di RPC e del supporto per molte lingue. Come al solito, le parti facili erano il client e il server. Tuttavia, il router si è rivelato un osso duro, in parte a causa della mancanza di una soluzione pronta durante il nostro sviluppo.

Sistema di gestione della configurazione di rete di filtraggio QratorCi sono altre opzioni, come protobuf / gRPC, tuttavia, quando abbiamo iniziato il nostro progetto, gRPC era abbastanza nuovo e non abbiamo osato adottarlo.

Naturalmente avremmo potuto (e in effetti avremmo dovuto) costruire la nostra bicicletta. Sarebbe più semplice creare un protocollo per ciò di cui abbiamo bisogno perché l'architettura client-server è relativamente semplice da implementare rispetto alla creazione di un router su Thrift. In un modo o nell'altro, c'è una tradizionale propensione verso i protocolli autoprodotti e le implementazioni delle librerie popolari (per una buona ragione); inoltre, durante le discussioni emerge sempre la domanda: "Come lo porteremo in altri linguaggi?" Quindi abbiamo subito buttato via l’idea della bicicletta.

Msgpack è simile a JSON, ma più veloce e più piccolo. È un formato di serializzazione dei dati binari che consente lo scambio di dati tra più lingue.

Al primo livello abbiamo Thrift con le informazioni minime necessarie affinché il router possa inoltrare il messaggio. Al secondo livello ci sono le strutture msgpack pacchettizzate.

Abbiamo scelto msgpack perché è più veloce e compatto rispetto a JSON. Ma, cosa ancora più importante, supporta tipi di dati personalizzati, permettendoci di utilizzare funzionalità interessanti come il passaggio di file binari grezzi o oggetti speciali che indicano l'assenza di dati, il che era importante per il nostro schema "stabile di recente".

Percorso JMES
JMESPath è un linguaggio di query JSON.
Questo è esattamente ciò che appare nella descrizione che otteniamo dalla documentazione ufficiale di JMESPath, ma in realtà fa molto di più. JMESPath consente di cercare e filtrare sottoalberi in una struttura ad albero arbitraria e di applicare modifiche ai dati al volo. Permette inoltre di aggiungere filtri speciali e procedure di trasformazione dei dati. Anche se, ovviamente, richiede uno sforzo cerebrale per capirlo.

Jinja
Per alcuni consumatori è necessario trasformare la configurazione in un file, quindi utilizziamo un motore di modelli e Jinja è la scelta più ovvia. Con il suo aiuto, generiamo un file di configurazione dal modello e dai dati ricevuti a destinazione.

Per generare un file di configurazione, abbiamo bisogno di una richiesta JMESPath, un modello per la posizione del file in FS e un modello per la configurazione stessa. È anche una buona idea in questa fase chiarire i permessi dei file. Tutto questo è stato combinato con successo in un unico file: prima di avviare il modello di configurazione, abbiamo inserito un'intestazione in formato YAML che descrive il resto.

Per esempio:

---
selector: "[@][[email protected]._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) }}

Per creare un file di configurazione per un nuovo servizio, aggiungiamo solo un nuovo file modello. Non sono necessarie modifiche al codice sorgente o al software sui punti di presenza.

Cosa è cambiato da quando QControl è stato pubblicato? La prima e più importante cosa è la consegna coerente e affidabile degli aggiornamenti di configurazione a tutti i nodi della rete. Il secondo è ricevere un potente strumento per verificare la configurazione e apportarvi modifiche da parte del nostro team di supporto, così come da parte degli utenti del servizio.

Siamo stati in grado di fare tutto questo utilizzando lo schema di aggiornamento stabile di recente per semplificare la comunicazione tra il server di configurazione e i destinatari della configurazione. Utilizzo di un protocollo a due livelli per supportare una modalità di instradamento dei dati indipendente dal contenuto. Integrato con successo un motore di generazione della configurazione basato su Jinja in una rete di filtraggio distribuita. Questo sistema supporta un'ampia gamma di metodi di configurazione per le nostre periferiche distribuite ed eterogenee.

Grazie per il tuo aiuto nella scrittura del materiale. Volan Damrod, serenità, Non.

Versione inglese la posta.

Fonte: habr.com

Aggiungi un commento