Ir más allá de la vaina en Kubernetes a través de los registros de montaje

Nota perev. : Esta nota fue escrita por un investigador de seguridad de TI en Aqua Security, una compañía DevSecOps. Ella es una excelente ilustración de las sutilezas en la configuración de Kubernetes, que es importante tener siempre en cuenta al servir clústeres en producción. Por supuesto, si piensas en su seguridad ...



Kubernetes consta de muchos componentes y, a veces, combinarlos de cierta manera conduce a resultados inesperados. En este artículo, mostraré cómo un pod lanzado con privilegios de root y un directorio /var/log montado de un nodo puede expandir el contenido de todo el sistema de archivos host a un usuario con acceso a sus registros. También discutiremos soluciones a este problema.

Cómo ve Kubernetes los registros


¿Alguna vez te has preguntado cómo kubectl logs <pod_name> extrae los registros del pod? ¿Quién es responsable de recolectar los registros de los contenedores? ¿Y cómo llegan a tu computadora?

El siguiente diagrama ilustra el proceso:



Kubelet crea una estructura dentro del directorio /var/log en el host que representa los pods en el host. Hay un archivo 0.log (1) en el directorio de nuestro 0.log , pero de hecho es un enlace simbólico al registro del contenedor ubicado en /var/lib/docker/containers . Todo esto desde el punto de vista del anfitrión.

Kubelet abre endpoint /logs/ (2), que simplemente funciona con el servidor de archivos HTTP en el directorio (3), haciendo que los registros estén disponibles para las solicitudes que provienen del servidor API.

Ahora imagine que implementamos pod con hostPath montado en /var/log . Tal pod tendrá acceso a todos los archivos de registro en el host. Aunque esto en sí mismo es un problema potencial, podemos dar el siguiente paso lógico. ¿Qué 0.log si reemplazamos 0.log con un enlace simbólico para ... decir, /etc/shadow ?

 │ ├── var │ ├── logs │ │ ├── pods │ │ │ ├── default_mypod_e7869b14-abca-11e8-9888-42010a8e020e │ │ │ │ ├── mypod │ │ │ │ │ ├── 0.log -> /etc/shadow │ │ │ │ │ │ 

Ahora, al intentar descargar los registros utilizando los registros de kubectl logs en la máquina cliente, obtenemos:

 $ kubectl logs mypod failed to get parse function: unsupported log format: "root:*:18033:0:99999:7:::\n" 

Kubelet sigue el enlace y lee el contenido del archivo al que apunta (puede ser cualquier archivo en el nodo).

Como se esperaba JSON, kubectl se bloqueó después de la primera línea, sin embargo, podemos leer fácilmente las líneas específicas del archivo de shadow ejecutando el comando con el –-tail=-<line_number> .

Esto es asombroso. Como kubelet sigue el enlace simbólico, puede usar sus privilegios de raíz para leer cualquier archivo en el nodo, simplemente creando un enlace simbólico dentro del pod.

Escapar de la vaina


Vamos aún más lejos. Sabemos que al iniciar un pod en Kubernetes, se instala el token de ServiceAccount. Por lo tanto, si la cuenta de servicio permite el acceso a los registros, podemos acceder directamente a los privilegios de kubelet y root en el nodo.

Escribí una prueba de concepto (POC) que demuestra este vector de ataque:

  • despliegue de pod con punto de montaje /var/log ;
  • crear un enlace simbólico al directorio raíz del host;
  • leyendo la clave privada ssh del usuario en el host.

El siguiente video muestra dos comandos especiales que se ejecutan dentro de un pod:

  • lsh == ls (en el sistema de archivos del host);
  • cath == cat (en el sistema de archivos del host).

Nota perev. : Desafortunadamente, no arreglaron la inserción de contenido de asciinema en el hub, aunque ya solucionamos este problema, por lo tanto, nos vemos obligados a "incrustar" el video con el simple enlace de arriba.

Todos los archivos involucrados en este POC se pueden encontrar en el repositorio de GitHub correspondiente . Hay otro script POC que recopila automáticamente claves privadas y tokens de ServiceAccount del sistema de archivos del host.

Montar directorios puede ser peligroso


Entonces, ¿es esto una vulnerabilidad o simplemente una mala práctica?

La implementación de un pod con un hostPath en /var/log es poco frecuente (también hay otras formas de abusar del montaje de directorios secretos de host en el pod). Pero incluso si sabía que montar /var/log era una práctica dudosa, probablemente no esperaba que le permitiera hacerse cargo del nodo con tanta facilidad.

Antes de publicar, contactamos al equipo de seguridad de Kubernetes para averiguar si consideran que esto es una vulnerabilidad. Llegaron a la conclusión de que esto era solo una triste consecuencia de montar un directorio de host privado con permisos de escritura: los riesgos involucrados están bien documentados . Sin embargo, esta vulnerabilidad es bastante fácil de explotar. En el mundo hay muchos proyectos que usan esta montura. Si está utilizando uno de estos proyectos, recuerde que su implementación será vulnerable a esta forma de secuestrar el host.

Este método ha sido probado en Kubernetes 1.15 y 1.13, pero probablemente afecta a otras versiones.

Eliminación


Tal "escape" es posible solo si el pod se está ejecutando como root. Esto generalmente debe evitarse . Aqua CSP le permite establecer una política con un mínimo de esfuerzos que evita que los contenedores se ejecuten bajo la raíz u otorga permisos solo a un grupo específico de imágenes que realmente necesitan raíz.

Otra forma es simplemente no desplegar pods con hostPath con permisos de escritura en /var/log . Este enfoque no está establecido por defecto y no es una práctica común, por lo tanto, es necesario determinarlo conscientemente (sin embargo, la posibilidad aún permanece). ¿Pero cómo verificar?

Agregamos un nuevo script (hunter) a kube-hunter , nuestra herramienta liviana de código abierto para probar Kubernetes, que verifica el clúster en busca de vainas con puntos de montaje tan peligrosos. ( Nota : Kube-hunter estuvo presente en una revisión reciente de las utilidades de seguridad de K8, que publicamos en nuestro blog).

Los usuarios de Aqua pueden protegerse de este riesgo utilizando la política de tiempo de ejecución para evitar que se monten ciertos volúmenes:



Nota perev. : Parte de este problema se puede resolver utilizando las políticas de seguridad de pod , a saber, AllowedHostPaths . Sin embargo, esto tampoco es protección contra enlaces simbólicos. Finalmente, como sugieren los comentarios, simplemente podemos limitar el lanzamiento como root, nuevamente guiado por la PSP .

Resumen


Kubernetes es un sistema complejo con muchas sutilezas en la configuración de seguridad, que no siempre es obvio para el usuario promedio e incluso experimentado. En este artículo, he mostrado cómo, bajo ciertas circunstancias, el registro inocente puede conducir a una vulnerabilidad potencial. En la mayoría de los casos esto no es posible, pero Kubernetes ofrece a los usuarios una mayor libertad de acción que puede afectar la seguridad. Es importante tener esto en cuenta e implementar controles apropiados para evitar tales errores.

PD del traductor


Lea también en nuestro blog:

Source: https://habr.com/ru/post/466625/


All Articles