Sistema de gestión de configuración de red de filtrado Qrator

Sistema de gestión de configuración de red de filtrado Qrator

TL; DR: Descripción de la arquitectura cliente-servidor de nuestro sistema de gestión de configuración de red interna, QControl. Se basa en un protocolo de transporte de dos capas que funciona con mensajes empaquetados en gzip sin descompresión entre puntos finales. Los enrutadores y puntos finales distribuidos reciben actualizaciones de configuración y el protocolo en sí permite la instalación de relés intermedios localizados. El sistema se basa en el principio. respaldo diferencial (“estable reciente”, se explica a continuación) y utiliza el lenguaje de consulta JMESpath junto con el motor de plantillas Jinja para representar archivos de configuración.

Qrator Labs opera una red de mitigación de ataques distribuida globalmente. Nuestra red funciona según el principio anycast y las subredes se anuncian a través de BGP. Al ser una red BGP anycast ubicada físicamente en varias regiones de la Tierra, podemos procesar y filtrar el tráfico ilegítimo más cerca del núcleo de Internet: los operadores de nivel 1.

Por otro lado, ser una red distribuida geográficamente no es fácil. La comunicación entre los puntos de presencia de la red es fundamental para que el proveedor de servicios de seguridad tenga una configuración consistente de todos los nodos de la red, actualizándolos de manera oportuna. Por lo tanto, para brindar el nivel más alto posible de servicio central al consumidor, necesitábamos encontrar una manera de sincronizar de manera confiable los datos de configuración entre continentes.

En el principio era la palabra. Rápidamente se convirtió en un protocolo de comunicaciones que necesitaba una actualización.


La piedra angular de la existencia de QControl, y al mismo tiempo la razón principal para invertir una cantidad significativa de tiempo y recursos en la construcción de este tipo de protocolo, es la necesidad de obtener una única fuente autorizada de configuración y, en última instancia, sincronizar nuestros puntos de presencia. con eso. El almacenamiento en sí fue sólo uno de varios requisitos durante el desarrollo de QControl. Además, también necesitábamos integraciones con servicios existentes y planificados en puntos de presencia (POP), métodos inteligentes (y personalizables) para la validación de datos, así como control de acceso. Además de esto, también queríamos controlar dicho sistema mediante comandos en lugar de realizar modificaciones en los archivos. Antes de QControl, los datos se enviaban a los puntos de presencia casi manualmente. Si uno de los puntos de presencia no estuviera disponible y nos olvidáramos de actualizarlo más tarde, la configuración acabaría desincronizada y tendríamos que perder tiempo para volver a ponerla en funcionamiento.

Como resultado, se nos ocurrió el siguiente esquema:
Sistema de gestión de configuración de red de filtrado Qrator
El servidor de configuración es responsable de la validación y el almacenamiento de datos; el enrutador tiene varios puntos finales que reciben y transmiten actualizaciones de configuración de los clientes y equipos de soporte al servidor, y desde el servidor a los puntos de presencia.

La calidad de la conexión a Internet todavía varía mucho en todo el mundo; para ilustrar este punto, veamos un sencillo MTR desde Praga, República Checa, hasta Singapur y Hong Kong.

Sistema de gestión de configuración de red de filtrado Qrator
MTR de Praga a Singapur

Sistema de gestión de configuración de red de filtrado Qrator
Lo mismo para Hong Kong

Una latencia alta significa una velocidad más baja. Además, hay pérdida de paquetes. El ancho del canal no compensa este problema, que siempre debe tenerse en cuenta a la hora de construir sistemas descentralizados.

La configuración completa de un punto de presencia supone una cantidad importante de datos que deben enviarse a muchos destinatarios a través de conexiones no fiables. Afortunadamente, aunque la configuración cambia constantemente, ocurre en pequeños incrementos.

Diseño reciente-estable

Podemos decir que construir una red distribuida basada en el principio de actualizaciones incrementales es una solución bastante obvia. Pero hay muchos problemas con las diferencias. Necesitamos guardar todas las diferencias entre los puntos de referencia y también poder reenviarlas en caso de que alguien haya perdido parte de los datos. Cada destino debe aplicarlos en una secuencia estrictamente especificada. Normalmente, en el caso de varios destinos, esta operación puede llevar mucho tiempo. El receptor también debe poder solicitar las piezas que faltan y, por supuesto, la parte central debe responder correctamente a dicha solicitud, enviando sólo los datos que faltan.

Como resultado, llegamos a una solución bastante interesante: solo tenemos una capa de referencia, fija, llamémosla estable, y solo una diferencia para ella: reciente. Cada reciente se basa en el último estable generado y es suficiente para reconstruir los datos de configuración. Tan pronto como el nuevo llega a su destino, el viejo ya no es necesario.

Todo lo que queda es enviar una nueva configuración estable de vez en cuando, por ejemplo, porque la reciente se ha vuelto demasiado grande. Lo que también es importante aquí es que enviamos todas estas actualizaciones en modo transmisión/multidifusión, sin preocuparnos por los destinatarios individuales y su capacidad para reunir datos. Una vez que estemos seguros de que todos tienen el establo correcto, solo enviamos los nuevos y recientes. ¿Vale la pena aclarar que esto funciona? Obras. Lo estable se almacena en caché en el servidor de configuración y los destinatarios, y lo reciente se crea según sea necesario.

Arquitectura de transporte de dos niveles.

¿Por qué construimos nuestro transporte en dos niveles? La respuesta es bastante simple: queríamos desacoplar el enrutamiento de la lógica de alto nivel, inspirándonos en el modelo OSI con sus capas de transporte y aplicación. Usamos Thrift para la función del protocolo de transporte y el formato de serialización msgpack para el formato de alto nivel de mensajes de control. Esta es la razón por la que el enrutador (que realiza multidifusión/difusión/retransmisión) no mira dentro de msgpack, no descomprime ni empaqueta el contenido y solo reenvía datos.

Thrift (del inglés - "thrift", pronunciado [θrift]) es un lenguaje de descripción de interfaz que se utiliza para definir y crear servicios para diferentes lenguajes de programación. Es un marco para llamadas a procedimientos remotos (RPC). Combina una canalización de software con un motor de generación de código para desarrollar servicios que funcionen de manera más o menos eficiente y sencilla entre idiomas.

Elegimos el marco Thrift debido a RPC y la compatibilidad con muchos idiomas. Como siempre, las partes fáciles fueron el cliente y el servidor. Sin embargo, el enrutador resultó ser un hueso duro de roer, en parte debido a la falta de una solución preparada durante nuestro desarrollo.

Sistema de gestión de configuración de red de filtrado QratorHay otras opciones, como protobuf/gRPC, sin embargo, cuando comenzamos nuestro proyecto, gRPC era bastante nuevo y no nos atrevimos a incorporarlo.

Por supuesto, podríamos (y de hecho deberíamos haber) construido nuestra propia bicicleta. Sería más fácil crear un protocolo para lo que necesitamos porque la arquitectura cliente-servidor es relativamente sencilla de implementar en comparación con construir un enrutador en Thrift. De una forma u otra, existe una tendencia tradicional hacia los protocolos escritos por nosotros mismos y las implementaciones de bibliotecas populares (con razón); además, durante las discusiones siempre surge la pregunta: "¿Cómo vamos a portar esto a otros lenguajes?" Así que inmediatamente descartamos la idea de una bicicleta.

Msgpack es similar a JSON, pero más rápido y más pequeño. Es un formato de serialización de datos binarios que permite el intercambio de datos entre varios idiomas.

En el primer nivel tenemos Thrift con la información mínima necesaria para que el router reenvíe el mensaje. En el segundo nivel hay estructuras empaquetadas msgpack.

Elegimos msgpack porque es más rápido y compacto en comparación con JSON. Pero lo más importante es que admite tipos de datos personalizados, lo que nos permite usar funciones interesantes como pasar archivos binarios sin formato u objetos especiales que indican la ausencia de datos, lo cual era importante para nuestro esquema "estable reciente".

JMESPath
JMESPath es un lenguaje de consulta JSON.
Así es exactamente como se ve la descripción que obtenemos de la documentación oficial de JMESPath, pero en realidad hace mucho más que eso. JMESPath le permite buscar y filtrar subárboles en una estructura de árbol arbitraria y aplicar cambios a los datos sobre la marcha. También le permite agregar filtros especiales y procedimientos de transformación de datos. Aunque, por supuesto, requiere un esfuerzo cerebral para comprenderlo.

Jinja
Para algunos consumidores, necesitamos convertir la configuración en un archivo, por lo que utilizamos un motor de plantillas y Jinja es la opción obvia. Con su ayuda generamos un archivo de configuración a partir de la plantilla y los datos recibidos en el destino.

Para generar un archivo de configuración, necesitamos una solicitud JMESPath, una plantilla para la ubicación del archivo en el FS y una plantilla para la configuración misma. También es una buena idea en esta etapa aclarar los permisos del archivo. Todo esto se combinó con éxito en un archivo: antes de iniciar la plantilla de configuración, colocamos un encabezado en formato YAML que describe el resto.

Por ejemplo:

---
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) }}

Para crear un archivo de configuración para un nuevo servicio, solo agregamos un nuevo archivo de plantilla. No se requieren cambios en el código fuente ni en el software de los puntos de presencia.

¿Qué ha cambiado desde que QControl entró en funcionamiento? Lo primero y más importante es la entrega consistente y confiable de actualizaciones de configuración a todos los nodos de la red. El segundo es recibir una poderosa herramienta para verificar la configuración y realizar cambios por parte de nuestro equipo de soporte, así como de los consumidores del servicio.

Pudimos hacer todo esto utilizando el esquema de actualización estable reciente para simplificar la comunicación entre el servidor de configuración y los destinatarios de la configuración. Uso de un protocolo de dos capas para admitir una forma de enrutar datos independiente del contenido. Se integró con éxito un motor de generación de configuración basado en Jinja en una red de filtrado distribuida. Este sistema admite una amplia gama de métodos de configuración para nuestros periféricos distribuidos y heterogéneos.

Gracias por su ayuda al escribir el material. VolanDamrod, serenidad, No.

versión inglesa correo.

Fuente: habr.com

Añadir un comentario