Contenedores Linux frente a máquinas virtuales: una comparación de seguridad

A los desarrolladores les encantan los contenedores. Son fáciles de usar y rápidos de comenzar. Puede ejecutar muchos de ellos incluso en hardware simple. La sobrecarga de inicio siempre ha sido una pesadilla para el desarrollo y las pruebas, y esta sobrecarga solo aumenta con las arquitecturas de microservicios. Si un desarrollador necesita media docena de servicios, fácilmente podría perder uno o dos días con la instalación: configurar hardware, ejecutar instaladores, combatir incompatibilidades.

Con contenedores, eso se colapsa en minutos o segundos y se puede ejecutar en una estación de trabajo de desarrollo. Los repositorios fácilmente disponibles de imágenes de contenedores útiles multiplican la productividad del desarrollador, al igual que lo hace el código abierto, pero sin la molestia de hacer una compilación. Los equipos de operaciones han tardado más en adoptar contenedores. Una razón es que muchas aplicaciones que deben admitir aún no están en contenedores. Otra razón es la renuencia a alejarse de las VM.

Para las operaciones, el cambio de bare metal a máquinas virtuales fue natural. Las máquinas virtuales individuales se ven y pueden administrarse como sistemas individuales, utilizando las mismas herramientas y procesos. Las primeras preocupaciones sobre la seguridad de las máquinas virtuales se disiparon por el largo historial de producción de las máquinas virtuales en el mundo del mainframe, por la capacidad de aplicar los mismos controles que se utilizan para los sistemas bare-metal, por el soporte de virtualización de hardware y por la madurez en evolución de las herramientas de gestión de máquinas virtuales.

Muchas preocupaciones de seguridad iniciales se redujeron a una pregunta: ¿eran las máquinas virtuales tan seguras como el metal desnudo? Ahora se están planteando cuestiones similares sobre los contenedores. ¿Qué tan seguros son los contenedores y cómo se comparan con las VM? Ciertamente, si comparamos los servicios que se ejecutan en contenedores con los mismos servicios que se ejecutan como procesos separados en el mismo sistema, la versión del contenedor es más segura. La separación proporcionada por los espacios de nombres de Linux y los cgroups proporciona barreras que no existen entre procesos simples. La comparación con las máquinas virtuales es menos clara. Echemos un vistazo a las máquinas virtuales y los contenedores desde una perspectiva de seguridad.

En este artículo, adoptaré dos enfoques diferentes para comparar la seguridad de las máquinas virtuales y los contenedores. El primer enfoque será más estructural o teórico, considerando las características de cada uno desde una perspectiva de seguridad. Luego, aplicaré un análisis más práctico al observar lo que sucede en una infracción típica y cómo podría verse afectada por las arquitecturas de contenedores y VM.

Vista estructural

Para el enfoque estructural, compararé la superficie de ataque de ambos sistemas. Una superficie de ataque representa el número de puntos en los que se puede atacar un sistema. No está definido con precisión (como un número, por ejemplo) pero es útil para realizar comparaciones. Para un ladrón, una casa con 10 puertas tiene una mayor superficie de ataque que una casa con una puerta, incluso si las puertas son idénticas. Una puerta podría quedar abierta; una cerradura puede estar defectuosa; las puertas en diferentes ubicaciones pueden ofrecer más privacidad al intruso, y así sucesivamente.

En los sistemas informáticos, la superficie de ataque incluye cualquier elemento en el que el atacante (o el software que actúa en su nombre) pueda "tocar" el sistema objetivo. Las interfaces de red, las conexiones de hardware y los recursos compartidos son todos posibles puntos de ataque. Tenga en cuenta que la superficie de ataque no implica que exista una vulnerabilidad real. Las 10 puertas pueden estar perfectamente seguras. Pero una superficie de ataque más grande significa más lugares para proteger y mayor probabilidad de que el atacante encuentre una debilidad en al menos uno.

La superficie de ataque total depende del número de diferentes puntos de contacto y de la complejidad de cada uno. Veamos un ejemplo sencillo. Imagine un sistema antiguo que ofrece cotizaciones bursátiles. Tiene una única interfaz, una línea serie simple. El protocolo en esa línea también es simple: un símbolo bursátil de longitud fija, digamos cinco caracteres, se envía al servidor, que responde con una cotización de precio de longitud fija, digamos, 10 caracteres. No hay Ethernet, TCP / IP, HTTP, etc. (De hecho, trabajé en tales sistemas hace mucho tiempo en una galaxia muy, muy lejana).

La superficie de ataque de este sistema es muy pequeña. El atacante puede manipular las características eléctricas de la línea serie, enviar símbolos incorrectos, enviar demasiados datos o modificar el protocolo. Proteger el sistema implicaría implementar controles apropiados contra esos ataques.

Ahora imagina el mismo servicio, pero en una arquitectura moderna. El servicio está disponible en Internet y expone una API RESTful. El lado eléctrico del ataque se ha ido; todo lo que hará es freír el propio enrutador o interruptor del atacante. Pero el protocolo es enormemente más complejo. Tiene capas para IP, TCP, posiblemente TLS y HTTP, cada una de las cuales ofrece la posibilidad de una vulnerabilidad explotable. El sistema moderno tiene una superficie de ataque mucho mayor, aunque para el atacante todavía parece un punto de interfaz único.

Superficie de ataque de metal desnudo

Para un atacante que no está físicamente presente en el centro de datos, la superficie de ataque inicial es la red en el servidor. Esto llevó a la "vista perimetral" de la seguridad: proteja los puntos de entrada al centro de datos y no ingrese nada. Si el atacante no puede ingresar, no importa lo que suceda entre los sistemas internos. Funcionó bien cuando las interfaces perimetrales eran simples (piense en el acceso telefónico), pero fomentaron debilidades en las interfaces internas. Los atacantes que encontraron un agujero en el perímetro a menudo descubrirían que la superficie de ataque interna de la granja de servidores era mucho más grande que la externa, y podían causar un daño considerable una vez dentro.

Esta superficie de ataque interna incluía conexiones de red entre servidores, pero también interacciones de proceso a proceso dentro de un solo servidor. Peor aún, dado que muchos servicios se ejecutan con privilegios elevados (usuario "root"), entrar con éxito en uno significaría efectivamente acceso sin restricciones a cualquier otra cosa en ese sistema, sin tener que buscar vulnerabilidades adicionales. Toda una industria creció en torno a la protección de servidores (firewalls, antimalware, detección de intrusiones, etc.) con resultados menos que perfectos.

También hay interesantes ataques de "canal lateral" contra servidores. Los investigadores han mostrado ejemplos de uso de consumo de energía, ruido o radiación electromagnética de las computadoras para extraer información, a veces datos muy sensibles como claves criptográficas. Otros ataques han aprovechado las interfaces expuestas, como los protocolos de teclado inalámbrico. Sin embargo, en general, estos ataques son más difíciles (por ejemplo, pueden requerir proximidad al servidor), por lo que la ruta principal de "bajada" es más común.

Superficie de ataque de VM

Cuando las máquinas virtuales se utilizan de la misma manera que bare metal, sin ninguna diferencia en la arquitectura de la aplicación (como suele ocurrir), comparten la mayoría de los mismos puntos de ataque. Una superficie de ataque adicional es la falla potencial en el hipervisor, el sistema operativo o el hardware para aislar adecuadamente los recursos entre las VM, lo que permite que una VM lea de alguna manera la memoria de otra VM. La interfaz entre la VM y el hipervisor también representa un punto de ataque. Si una máquina virtual puede abrirse paso y ejecutar código arbitrario en el hipervisor, entonces puede acceder a otras máquinas virtuales en el mismo sistema. El hipervisor en sí mismo representa un punto de ataque, ya que expone interfaces de administración.

Existen puntos de ataque adicionales según el tipo de sistema de VM. Los sistemas de VM de tipo 2 utilizan un hipervisor que se ejecuta como un proceso en un sistema operativo host subyacente. Estos sistemas pueden ser atacados atacando el sistema operativo del host. Si el atacante puede hacer que el código se ejecute en el sistema host, puede afectar potencialmente al hipervisor y a las máquinas virtuales, especialmente si puede obtener acceso como usuario privilegiado. La presencia de un sistema operativo completo, incluidas las utilidades, las herramientas de administración y posiblemente otros servicios y puntos de entrada (como SSH), proporciona una serie de posibles puntos de ataque. Los sistemas de VM de tipo 1, donde el hipervisor se ejecuta directamente en el hardware subyacente, eliminan estos puntos de entrada y, por lo tanto, tienen una superficie de ataque más pequeña.

Superficie de ataque del contenedor

Al igual que con las máquinas virtuales, los contenedores comparten los puntos fundamentales de ataque de entrada a la red de los sistemas bare-metal. Además, al igual que las máquinas virtuales de tipo 2, los sistemas de contenedor que utilizan un sistema operativo host "completamente cargado" están sujetos a los mismos ataques disponibles contra las utilidades y servicios de ese sistema operativo host. Si el atacante puede obtener acceso a ese host, puede intentar acceder o afectar los contenedores en ejecución. Si obtiene acceso privilegiado ("root"), el atacante podrá acceder o controlar cualquier contenedor. Un sistema operativo "minimalista" (como KurmaOS de Apcera) puede ayudar a reducir esta superficie de ataque, pero no puede eliminarla por completo, ya que se requiere cierto acceso al sistema operativo host para la gestión de contenedores.

Los mecanismos básicos de separación de contenedores (espacios de nombres) también ofrecen puntos de ataque potenciales. Además, no todos los aspectos de los procesos en los sistemas Linux tienen espacio de nombres, por lo que algunos elementos se comparten entre contenedores. Estas son áreas naturales para que los atacantes investiguen. Finalmente, el proceso a la interfaz del kernel (para llamadas al sistema) es grande y está expuesto en cada contenedor, a diferencia de la interfaz mucho más pequeña entre una VM y el hipervisor. Las vulnerabilidades en las llamadas al sistema pueden ofrecer acceso potencial al kernel. Un ejemplo de esto es la vulnerabilidad reportada recientemente en el llavero de claves de Linux.

Consideraciones arquitectónicas

Tanto para las VM como para los contenedores, el tamaño de la superficie de ataque puede verse afectado por la arquitectura de la aplicación y cómo se utiliza la tecnología.

Muchas aplicaciones de VM heredadas tratan a las VM como si fueran bare metal. Es decir, no han adaptado sus arquitecturas específicamente para VM o para modelos de seguridad que no se basan en la seguridad perimetral. Pueden instalar muchos servicios en la misma máquina virtual, ejecutar los servicios con privilegios de root y tener pocos o ningún control de seguridad entre los servicios. Volver a diseñar estas aplicaciones (o más probablemente reemplazarlas por otras más nuevas) podría usar VM para proporcionar separación de seguridad entre unidades funcionales, en lugar de simplemente como un medio para administrar un mayor número de máquinas.

Los contenedores son adecuados para arquitecturas de microservicios que "encadenan" una gran cantidad de (normalmente) pequeños servicios utilizando API estandarizadas. Estos servicios a menudo tienen una vida útil muy corta, cuando un servicio en contenedor se inicia a pedido, responde a una solicitud y se destruye, o cuando los servicios aumentan y disminuyen rápidamente según la demanda. Ese patrón de uso depende de la instanciación rápida que admiten los contenedores. Desde la perspectiva de la seguridad, tiene ventajas e inconvenientes.

La mayor cantidad de servicios significa una mayor cantidad de interfaces de red y, por lo tanto, una mayor superficie de ataque. Sin embargo, también permite más controles en la capa de red. Por ejemplo, en la plataforma Apcera, todo el tráfico de contenedor a contenedor debe estar explícitamente permitido. Un contenedor no autorizado no puede llegar arbitrariamente a ningún punto final de la red.

Una vida útil corta del contenedor significa que si un atacante entra, el tiempo que tiene para hacer algo es limitado, a diferencia de la ventana de oportunidad que presenta un servicio de larga duración. La desventaja es que los forenses son más difíciles. Una vez que el contenedor desaparece, no se puede sondear ni examinar para encontrar el malware. Estas arquitecturas también hacen que sea más difícil para un atacante instalar malware que sobrevive después de la destrucción del contenedor, como lo haría en bare metal al instalar un controlador que se carga al arrancar. Los contenedores generalmente se cargan desde un repositorio confiable de solo lectura, y pueden protegerse aún más mediante controles criptográficos.

Ahora consideremos lo que sucede durante una infracción.

Protección contra infracciones

Los atacantes suelen tener uno o dos objetivos al acceder a un sistema de servidor. Quieren obtener datos o hacer daño.

Si buscan datos, quieren infiltrarse en tantos sistemas como sea posible, con los mayores privilegios posibles, y mantener ese acceso durante el mayor tiempo posible. Lograr esto les da tiempo para encontrar los datos, que pueden estar ya allí (una base de datos mal protegida, por ejemplo) o pueden requerir una recopilación lenta con el tiempo a medida que se filtran, como la recopilación de transacciones a medida que provienen de los usuarios. Mantener el acceso durante mucho tiempo requiere sigilo. El ataque también requiere una forma de sacar los datos.

Si el atacante simplemente intenta hacer daño, el objetivo nuevamente es acceder a tantos sistemas y privilegios como sea posible. Pero hay un acto de equilibrio: una vez que comienza el daño, presumiblemente se notará, pero cuanto más tiempo espere el atacante para comenzar (mientras el malware se filtra de un sistema a otro), mayores serán las posibilidades de ser detectado. Obtener datos es menos importante que el control coordinado del malware. La idea es infectar tantos sistemas como sea posible y luego dañarlos en un punto sincronizado, ya sea preestablecido o por orden.

Las infracciones involucran varios elementos. Analicemos cada uno y veamos si las máquinas virtuales y las arquitecturas en contenedores pueden afectar la superficie de ataque de cada uno.