Este es el cuarto blog de una serie que cubre diversos aspectos de lo que nos llevó construir y operar nuestro servicio SaaS :
En el blog anterior , brindamos información sobre el desafío de usar técnicas criptográficas para proteger nuestra plataforma (infraestructura, aplicaciones y datos). Este blog tratará sobre las técnicas que utilizamos para proteger la plataforma contra ataques dirigidos desde la red, tanto desde Internet como desde dentro. Dado que las aplicaciones ya no están limitadas a ninguna ubicación física, los firewalls tradicionales basados en perímetro y las soluciones de seguridad basadas en firmas ya no son efectivas. Describiremos las deficiencias de nuestra implementación de seguridad de confianza cero inicial y por qué y cómo la aumentamos con aprendizaje automático y técnicas algorítmicas para proteger adecuadamente nuestra infraestructura distribuida y clústeres de aplicaciones.
Nuestra plataforma ejecuta una gran cantidad de aplicaciones en múltiples equipos que operan sus propios clústeres en el borde, nuestra red global y las nubes públicas de AWS y Azure. Si bien la mayoría de las cargas de trabajo están orquestadas por microservicios mediante Kubernetes, tenemos un puñado de monolitos de gran escala (por ejemplo, elasticsearch) que administramos mediante Terraform. La figura 1 demuestra la naturaleza distribuida de nuestra plataforma. Por ejemplo, en cada uno de nuestros más de 18 PoP de red global (con unas pocas decenas o un poco más de cien servidores físicos), ejecutamos miles de pods de aplicaciones. Sin embargo, en el borde, hoy tenemos implementaciones de clientes individuales con más de 3000 ubicaciones activas (cada una con uno a siete computadores) que ejecutan algunas decenas de pods de aplicaciones.
La plataforma es totalmente multiinquilino y cada nodo ejecuta cargas de trabajo de diferentes clientes (y las nuestras). Dado que algunas de estas aplicaciones están expuestas a Internet público, debemos asegurarnos de que toda la comunicación hacia/desde las aplicaciones sea segura. Como hemos descrito en los dos blogs anteriores, construimos un sistema robusto de identidad, autenticación y autorización junto con nuestra propia ruta de datos de red L3-L7+ (VoltMesh) que se utiliza para impulsar nuestra malla de servicios y puerta de enlace API . Como se muestra en la Figura 2, esto nos ha permitido brindar seguridad a nivel de transporte en todos los clústeres de aplicaciones (mTLS), desde usuarios (TLS/mTLS) y empleados (mTLS), así como control de acceso basado en autenticación+autorización.
Si bien esta implementación de confianza cero ofrece muchos beneficios, no resuelve automáticamente varios problemas de seguridad:
Durante los últimos 2,5 años de desarrollo en esta plataforma, también nos dimos cuenta de que, a menudo, nuestros desarrolladores incorporan aplicaciones de código abierto, las contienen en contenedores y le piden a nuestro equipo de DevOps que las implemente en la plataforma. Sin embargo, a menudo carecen de detalles sobre las interacciones a nivel de API dentro de estas aplicaciones que nuestro equipo de seguridad necesita para crear políticas para incluir la comunicación en la lista blanca. Este es un gran obstáculo para nuestra implementación de seguridad de confianza cero, ya que exige políticas de lista blanca que solo permiten las API utilizadas por las aplicaciones y bloquean todo el resto del tráfico. Cada vez que hicimos excepciones a este requisito, algunas aplicaciones quedaron con una segmentación a nivel de red muy básica, lo que aumentó la superficie de ataque.
Como resultado, necesitábamos ampliar nuestra solución de seguridad de confianza cero existente con capacidades de seguridad adicionales para manejar los problemas enumerados anteriormente. Identificamos una lista de capacidades de seguridad adicionales que tuvimos que incorporar a la plataforma:
Decidimos utilizar una combinación de técnicas tradicionales basadas en firmas, algoritmos estadísticos y enfoques de aprendizaje automático más dinámicos para resolver estos problemas. Esto requirió que hiciéramos cambios en nuestro backend SaaS, así como también agregar nuevas capacidades en nuestra ruta de datos de red.
Para proteger la plataforma, solo permitimos conexiones de red según la lista blanca de API para cada aplicación. Esto requiere que nuestro equipo de seguridad se coordine con los desarrolladores y garantice que nuestro motor de políticas programable reciba la información correcta de la API. Rápidamente nos dimos cuenta de que era imposible para nuestros desarrolladores proporcionar esta información para aplicaciones que no se crearon utilizando nuestro marco de servicio.
Dado que nuestro proxy de malla de servicio está en la ruta de red de cada acceso a la aplicación, decidimos aprender las API y los recursos estáticos que expone la aplicación haciendo un análisis en tiempo de ejecución de cada acceso que pasa por el proxy. El desafío de este enfoque es identificar los puntos finales de la API inspeccionando las URL y separando los componentes que se generan dinámicamente. Por ejemplo, para una API “api/user/<user_id>/vehicle/”, el proxy verá accesos como:
Puede haber millones de solicitudes de este tipo, lo que hace que sea muy difícil descifrarlas. Como resultado, la identificación de componentes dinámicos en estas solicitudes relacionadas se realiza mediante aprendizaje profundo y análisis de gráficos. Representamos todo el conjunto de componentes de URL como un gráfico y luego realizamos la agrupación de gráficos para encontrar subgráficos con propiedades similares utilizando conjuntos de características que capturan propiedades específicas de componentes generados dinámicamente, como:
Como resultado, los componentes dinámicos se clasifican y la salida del sistema se ve así:
Al utilizar este aprendizaje automático de API, podemos generar de manera fácil y automática una política que nuestro proxy de malla de servicio pueda aplicar. Con base en los puntos finales de API descubiertos, también aprendemos otras propiedades, como qué aplicaciones usan qué API para comunicarse con otras aplicaciones, el comportamiento típico de estas API, etc. Esto nos permite crear un gráfico de servicios que ayuda a nuestro equipo de seguridad a visualizar la interacción de servicio a servicio para análisis forense, descubrimiento y microsegmentación a nivel de API.
Antes de embarcarnos en agregar las dos capacidades restantes (detección de anomalías y creación de perfiles de comportamiento), decidimos ver si las soluciones existentes podrían ayudarnos. Si bien existen muchos firewalls perimetrales y productos de firewall para aplicaciones web en el mercado, la mayoría de estas soluciones están orientadas a proteger las aplicaciones que miran a Internet. Parten de ciertas suposiciones de que el tráfico atendido es tráfico web y brindan protección específica para HTML, javascript, sql, CMS, etc., lo que hace relativamente más fácil escribir firmas y reglas para detectar vulnerabilidades y exploits conocidos.
Si bien esta capacidad es importante para nuestro tráfico web, también necesitamos atender una cantidad cada vez mayor de tráfico de API y de máquina a máquina en nuestro entorno. Para resolver esto, nuestro equipo de seguridad tendría que escribir reglas específicas para la aplicación que no se encuentren dentro de las reglas web típicas conocidas (como OWASP CRS). Generalmente, los administradores de seguridad saben poco sobre las aplicaciones y, dada la naturaleza dinámica del entorno, se vuelve aún más difícil realizar un seguimiento de los tipos y la estructura de las aplicaciones para escribir reglas específicas de cada aplicación. Como resultado, si bien nuestro equipo de plataforma proporciona esta capacidad en nuestra ruta de datos de red, nuestro equipo de seguridad no la utiliza con frecuencia.
Otro problema para el cual tenemos una cantidad significativa de datos de nuestra red es que los ataques a las aplicaciones se están volviendo mucho más sofisticados con el tiempo. El atacante pasa días realizando tareas de reconocimiento para determinar los detalles de las API, la aplicación, la infraestructura subyacente y el tipo de sistema operativo observando las firmas HTTP/TCP, etc. Los enfoques tradicionales basados en reglas y firmas tienen una utilidad muy limitada en estas situaciones y decidimos continuar con nuestro enfoque basado en IA para aprender automáticamente el comportamiento del usuario y aplicar el comportamiento bueno frente al malo.
La mayoría de las aplicaciones tienen ciertos flujos de trabajo (secuencia de API) y contexto (datos dentro de las API) para los cuales se diseñan diferentes casos de uso/implementaciones que normalmente siguen los usuarios de las aplicaciones. Explotamos estas propiedades y entrenamos nuestros algoritmos de aprendizaje automático para modelar patrones de comportamiento “válidos” en una interacción típica del usuario con la aplicación.
Nuestra ruta de datos muestrea solicitudes/respuestas para cada API junto con los datos asociados y las envía a nuestro motor de aprendizaje central como se muestra en la Figura 3. Este motor genera y actualiza continuamente el modelo de patrones de comportamiento válidos que luego utiliza el motor de inferencia que se ejecuta en la ruta de datos para alertar o bloquear comportamientos sospechosos.
El motor de aprendizaje analiza muchas métricas, como la secuencia de API, las brechas entre solicitudes, las solicitudes repetidas a las mismas API, las fallas de autenticación, etc. Estas métricas se analizan para cada usuario y de forma agregada para clasificar el comportamiento bueno y malo. También realizamos agrupamiento de comportamientos para identificar múltiples secuencias diferentes de “buen comportamiento”. Tomemos un ejemplo para ilustrar esto:
El sistema marcará la siguiente secuencia de API como comportamiento sospechoso o malo, que será mitigado automáticamente por el sistema o generará una alerta para que intervenga un administrador.
Cuando pusimos este sistema en producción hace más de un año, hemos ido perfeccionando el modelo en función del uso y los comentarios de los clientes. Hemos podido identificar con éxito los siguientes tipos de ataques:
Dicho esto, también nos dimos cuenta de que este enfoque tiene algunos problemas: no puede descubrir ataques lentos y de baja intensidad (fuerza bruta, denegación de servicio de la aplicación, escáner) para los cuales necesitamos aplicar técnicas de detección de anomalías.
A veces, vemos ataques altamente sofisticados que utilizan grandes botnets distribuidas que pasan desapercibidas para nuestra técnica de análisis de comportamiento. Ejemplos de tales ataques son:
Dado que nuestra ruta de datos de red recopila información de cada nodo de nuestra red global, resulta relativamente fácil realizar análisis de las métricas agregadas de una aplicación en particular, como la tasa de solicitud, la tasa de error, el rendimiento de respuesta, etc. Este análisis nos permite detectar ataques distribuidos y mitigarlos (en cada nodo) identificando los usuarios que podrían formar parte de dichas botnets. Tomemos un ejemplo en el que intentamos detectar anomalías en diferentes ventanas de tiempo (últimos 5 minutos, 30 minutos, 4 horas, 24 horas) al observar las tasas de solicitud y, si la tasa de solicitud es alta dentro de una ventana de tiempo determinada, el sistema realizará el siguiente análisis más profundo de los registros de acceso:
Si bien la detección de anomalías siempre ha sido una técnica importante para la detección y prevención de intrusiones (IDS/IPS) en dispositivos de firewall, estos dispositivos no pueden mitigar los ataques globales a la capa de aplicación. Gracias a nuestra capacidad de realizar marcado y aprendizaje de API en toda nuestra plataforma global, ahora podemos suprimir los ataques en la fuente a lo largo de nuestra red distribuida.
Si bien estábamos extremadamente satisfechos con nuestra implementación de confianza cero basada en una malla de servicios y una puerta de enlace API, nos dimos cuenta de que no era integral para proteger los clústeres de aplicaciones distribuidas de vulnerabilidades y ataques maliciosos. Tuvimos que ampliarlo con aprendizaje automático para el análisis de comportamiento + detección de anomalías junto con técnicas tradicionales basadas en reglas y firmas para brindar una mejor solución de seguridad.
Hemos visto tres ganancias significativas a partir de la incorporación de inferencias distribuidas en nuestra ruta de datos de red L3-L7+ junto con el núcleo de aprendizaje que se ejecuta en nuestro SaaS centralizado:
La seguridad de la red y de las aplicaciones es un camino sin fin y parece que aún tenemos un largo retraso en la incorporación de nuevas funciones. Volveremos en un futuro próximo para compartir información adicional sobre los algoritmos y técnicas incrementales que hemos implementado.
Esta serie de blogs cubrirá diversos aspectos de lo que nos llevó construir y operar nuestro servicio SaaS distribuido globalmente con muchos clústeres de aplicaciones en nubes públicas, nuestros PoP de red privada y sitios de borde. El próximo tema será “Observabilidad en nuestra plataforma distribuida globalmente” (próximamente).