jueves, abril 02, 2020

Cómo fortificar containers en Kubernetes … "Like a Boss"

En esta pasada RootedCon 2020 tuvimos la oportunidad y el honor de presentar una charla sobre la fortificación de contenedores cuando desplegamos una aplicación en Kubernetes. En ella, reunimos algunos de los conceptos que hemos ido contando en este blog sobre este mismo tema y la tecnología Kubernetes durante los últimos meses.

Figura 1: Cómo fortificar containers en Kubernetes … "Like a Boss"

La presentación, que comenzamos el viernes 6 de marzo a las 10:00, empezó fuerte ;) directamente con una demo de una aplicación vulnerable desplegada en un clúster de Kubernetes local (minikube), especificando los parámetros necesarios para dicho despliegue. Per antes de continuar, nos gustaría recordaros que nuestro libro Docker:SecDevOps puede ser un buen punto de partida para comenzar en este mundo de los contenedores.

Figura 2: Libro de Docker:SecDevOps

Volviendo a la demo (aquí podéis ver las diapositivas), en ella mostramos una aplicación programada por nosotros, la cual nos permitía crear notas simples. Dichas notas se guardaban directamente en el sistema de ficheros. De forma intencionada, esta aplicación tenía una vulnerabilidad tipo path traversal, y través de la manipulación de una cookie, éramos capaces de listar el contenido que cualquier directorio del sistema, crear notas en cualquier directorio, ver el contenido de ficheros existentes, mostramos un el token de la cuenta de servicio asociada al pod, algo que Kubernetes hace por defecto, e incluso podíamos sobreescribir el contenido de ficheros existentes incluidos lo del sistema.

Figura 3: Demo de hacking web vulnerable

Vamos, que le podías hacer casi cualquier cosa. Esto era así porque como también pudimos ver, la aplicación corría como root (usuario por defecto de un contenedor Docker, a menos que especifiquemos otro). También mostramos cómo existía un punto de depuración que nos permitía ejecutar comandos en el sistema, y por último también demostramos que era posible descargar cualquier fichero desde Internet.

En el vídeo de la Figura 3 tienes muchos ejemplos de lo que podías hacer, pero si quieres aprender a hacerle más cosas, puedes leer el libro de Hacking Web Technologies de Chema Alonso, Pablo González, Enrique Rando, Amador Aparicio y Ricardo Martín.

Figura 4: Libro de Hacking Web Technologies de Chema Alonso,
Pablo González, Enrique Rando, Amador Aparicio y Ricardo Martín

Una vez terminada la demo (que funcionó a la perfección por cierto), mostramos las distintas opciones que tenemos a nuestra disposición en Docker/Kubernetes, para fortificar nuestros contenedores. Así que, cuando nuestro contenedor sea comprometido, podamos mantener confinado al atacante de forma que minimicemos las acciones y evitar que cree persistencia, se mueva lateralmente, etceera.

Primero hablamos de la creación de imágenes Docker, y algunas de las buenas prácticas desde el punto de vista de la seguridad. Como, por ejemplo, la importancia de la cadena de provisión, el escanéo de dichas imágenes y hicimos hincapié en el uso de imágenes pequeñas, a ser posible que tengan lo mínimo que nuestra aplicación necesite para ejecutarse. De esta forma reducimos mucho de los vectores de movimientos en caso de un incidente.

En la presentación usamos una imagen distroless como ejemplo de mejora sobre Alpine, imagen que utilizamos en la demo del inicio de la presentación. Y terminamos esta parte inicial de la charla creando un Dockerfile mejorado, dónde usamos una imagen distroless, y creamos un usuario y grupo con el cual la aplicación se ejecutará.

Figura 5: Dockerfile mejorado

De ahí, pasamos al contexto de seguridad de contenedores. Estos están muy relacionados con las Pod Security Policies que en su día ya hablamos. Nos centramos en la diferencia entre los contenedores privilegiados y los no privilegiados. También vimos las opciones que tenemos en Kubernetes para ejecutar un contenedor como no root, explicamos qué es la escalada de privilegios en contenedores y como evitarla.

Luego hablamos de la importancia de montar el sistema de ficheros como sólo lectura y de esta forma ponerle la vida más difícil a un atacante a la hora de crear persistencia o modificar cosas del sistema como se mostró en la demo inicial, y por último hablamos de la capacidades de GNU/Linux y el cómo remover éstas de nuestro contenedor y aplicar el principio de privilegios mínimos. Si quieres saber más del proceso de fortificación de un servidor GNU/Linux, te recomendamos este libro de Hardening de Servidores GNU/Linux (3ª Edición) de Pablo González y Carlos Álvarez Martín.

Figura 6: Libro de "Hardening de Servidores GNU/Linux" 3ª Edición
de Pablo González y Carlos Álvarez Martín

Siguiendo con la charla, continuamos hablando un poco de las cuentas de servicio en Kubernetes, y cómo cada pod tiene asociada una cuenta de servicio (default si no especificamos una explícitamente). Por defecto, como se mostró en la demo, Kubernetes monta dentro del pod el secreto asociado a la cuenta de servicio asignado al pod, este secreto contiene un token JWT, que no es más que una credencial que te da acceso al clúster. Con este token puedes hacer lo que tenga autorizado, pero es una credencial que el 90% de las aplicaciones no necesita.

A menos que tu aplicación necesite comunicarse con la API de Kubernetes, este token está demás, y si no lo necesitas, se recomienda que no se monte, para así evitar que se pueda exfiltrar en caso de un incidente. Por útltimo hablamos muy brevemente de las redes en Kubernetes, y nos enfocamos en las políticas de red, de las que ya hablamos en su día en el artículo: "Kubernetes: Gestionar Políticas de red Like a Boss".

Figura 7: Esquema que muestra el control de acceso en el contexto de seguridad de los Pods

En la fase final de la charla mostramos los cambios que hicimos en el fichero de despliegue con respecto al fichero utilizado para el despliegue de la demo inicial. Y con dichos cambios cambios, teníamos preparada una segunda demo con la que terminamos la presentación. En dicha demo no habíamos cambiado nada del código de dicha aplicación, por lo que las vulnerabilidades mostradas al principio aún existían, la diferencia en este caso era demostrar que ahora el atacante, tenía poco que hacer.

Mostramos, por ejemplo, que este todavía era capaz de listar el contenido de directorios y ficheros a los que el usuario appuser (usuario con el que se ejecutaba ahora el contenedor), sin embargo, ya no podía crear ficheros en otros directorios (el sistema de ficheros estaba montado como sólo lectura) o modificar el contenido de ficheros del sistema (además del sistema de fichero estar en modo sólo lectura, el contendor ya no corría como root).

Figura 8: Rafael Troncoso (izquierda) y Fran Ramírez minutos antes de la charla

De esta forma demostramos que, gracias a que usamos una imagen distroless, ya no podíamos ejecutar comandos a través del punto de acceso de depuración, ya que en las imágenes distroless no existe shell o utilidades extras.

Y por último aplicamos una política de red restrictiva que bloqueaba tanto el tráfico de entrada como de salida a nuestra aplicación, lo cual que no era de mucha ayuda ya que no podíamos acceder a la misma en principio, para ello aplicamos un nueva política que permitía el tráfico de entrada, pero no el de salida. De forma que ahora ya no podíamos descargar nada desde internet, tal y como ocurría durante la primera demo.


Figura 9: Demo de fortificación de la app insegura


También quisimos dejar muy claro que esto no es una forma de arreglar vulnerabilidades en una aplicación, sino más bien puede ser un Plan B o Plan de Contingencia para cuando tu aplicación sea comprometida, algo que seguro, pasará.

Figura 10: Repositorio de GitHub con todo el material de la charla

Finalmente, afortunadamente todo salió como teníamos previsto y la experiencia fue muy buena. Pronto estará la charla publicada en la web de la RootedCon, os avisaremos por las redes sociales. De momento, el contenido del material usado en las demos, así como las diapositivas se encuentran disponibles en nuestro repositorio de GitHub. Gracias a RootedCon y todos aquellos que fuisteis a la charla.

¡Quédate en casa!

Autores:

Fran Ramírez, (@cyberhadesblog) es investigador de seguridad y miembro del equipo de Ideas Locas en CDO en Telefónica, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps", también de "Machine Learning aplicado a la Ciberseguridad” además del blog CyberHades. Puedes contactar con Fran Ramirez en MyPublicInbox.


 Contactar con Fran Ramírez en MyPublicInbox

Rafael Troncoso
(@tuxotron) es Senior Software Engineer en SAP Concur, co-autor del libro "Microhistorias: Anécdotas y Curiosidades de la historia de la informática (y los hackers)", del libro "Docker: SecDevOps" además del blog CyberHades. Puedes contactar con Rafael Troncoso en MyPublicInbox.



Contactar con Rafael Troncoso en MyPublicInbox

No hay comentarios:

Publicar un comentario