Descubierta una vulnerabilidad en Kubernetes que permite acceso a redes restringidas (CVE-2020-8562)

Javier Provecho    19 julio, 2021
Descubierta una vulnerabilidad en Kubernetes que permite acceso a redes restringidas (CVE-2020-8562)

Kubernetes es un sistema de código abierto para automatizar las operaciones de contenedores, utilizado por multitud de empresas en servicios de primer nivel. Hoy en día, se ha convertido la tecnología de facto en la industria, lo que ha permitido que se utilice en escenarios completamente alejados de su propósito original.

Parte de su éxito y popularidad se debe a la adopción del sistema por parte de proveedores de nube pública los cuales lo ofrecen como solución gestionada, mejor conocida como Kubernetes as a Service.

En la mayoría de los casos, Kubernetes as a Service corresponde al despliegue, mantenimiento y operación de los componentes pertenecientes al plano de control del sistema, como el “apiserver”, el “scheduler” o el “controller”. El resto de la topología del cluster recae en el cliente o usuario de la solución, aunque a veces dichos proveedores ofrecen sus servicios de infraestructura como servicio para facilitar la integración.

También existen proyectos como OneInfra que ofrecen un sistema de hospedaje de planos de control de Kubernetes de código abierto, equivalente a aquellos propietarios que mueven los principales servicios gestionados de Kubernetes como Google GKE, AWS EKS, o Azure AKS.

En la arquitectura de un servicio gestionado de Kubernetes existen responsabilidades compartidas y por ello deben existir medidas de seguridad que garanticen la separación entre distintas instancias de clústers de Kubernetes. Es por ello por lo que dichos proveedores no ofrecen acceso administrativo a los componentes del plano de control ni su entorno de red.

Esto es especialmente importante a la hora de poner en producción un servicio gestionado de Kubernetes, pues uno de sus componentes, el “apiserver”, puede actuar como un proxy reverso en ciertos escenarios. Veamos un ejemplo:

El sub-recurso “log” dentro de un recurso “pod” sirve para acceder a los registros de sus contenedores, permitiendo un control granular mediante políticas de control de acceso como RBAC. Esta misma operación se puede realizar mediante el sub-recurso “proxy” dentro de los recursos “node” (también está disponible en recursos “pod”) de la siguiente manera:

El acceso a los recursos “node” y sus sub-recursos como “proxy” son operaciones permitidas a los usuarios de un servicio gestionado de Kubernetes, dado que los nodos son instancias bajo el control directo de los mismos.

Esto plantea una oportunidad interesante para investigar, la de “engañar” al proveedor de servicios gestionados de Kubernetes con un nodo falso, el cuál tendría una dirección de red arbitraria. Esta posibilidad puede permitir el acceso a componentes del plano de control de nuestro cluster de Kubernetes (y de otros clientes/usuarios).

Los objetivos más importantes suelen estar accesibles en un par de grupos de direcciones de red, conocidos como “localhost” (127.0.0.0/8) o “linklocal” (169.254.0.0/16). Un ejemplo en el caso de proveedores de nube pública es el servicio de metadatos de infraestructura como servicio, accesible en http://169.254.169.254:80. Este servicio es responsable de servir datos específicos a cada instancia para su correcta configuración, entre los que se suelen incluir credenciales de acceso a otros recursos y/o servicios.

En el caso de los servicios gestionados de Kubernetes, el servicio de metadatos contiene la configuración del clúster de Kubernetes y algunas credenciales del servicio de infraestructura como servicio, utilizadas a la hora de automatizar operaciones externas al clúster de Kubernetes, como configurar un balanceador de red o montar un volumen de datos.

Cuando intentamos crear un nodo con la siguiente definición y acceder a su puerto 80 (el servicio de metadatos), el “apiserver” deniega la petición gracias al filtro de direcciones restringidas implementado en la “pull request” #71980.


La solución implementada consiste en resolver el nombre de dominio del recurso u obtener su dirección de red para evaluar que no corresponda a una dirección de tipo “localhost” (127.0.0.0/8) o “linklocal” (169.254.0.0/16). Posteriormente si esta comprobación resulta satisfactoria, se procede a realizar la petición a la dirección o nombre de dominio indicado.

Para unos ojos inquietos, es fácil darse cuenta de que en caso de que la petición utilice un nombre de dominio, este se resuelve dos veces durante la ejecución de este filtro. La primera, cuando se resuelve el nombre de dominio a una IP que pueda ser utilizada por el filtro, y la segunda, cuando se resuelve el nombre de dominio a una IP para realizar la petición. Esta conclusión se puede implementar mediante un servidor DNS personalizado que devuelva una IP válida en la primera petición y una IP restringida en peticiones consecutivas.

Trasladando esta conclusión a nuestro escenario de Kubernetes con un nodo falso, tenemos que configurar el nombre de dominio de dicho servidor DNS personalizado como una de las direcciones del nodo, la cual debe ser utilizada por el “apiserver” para ser contactado.

Este escenario resultó en una vulnerabilidad reportada al comité de seguridad de Kubernetes el 27 de abril del 2020, la cual se ha mantenido oculta mientras se notificaba a los distintos proveedores que utilizan Kubernetes, para ser finalmente publicada el 27 de mayo del 2021 sin parche de seguridad con el identificador CVE-2020-8562. Desde el comité de seguridad de Kubernetes se ha ofrecido una mitigación temporal en la “issue” #101493, así como otras recomendaciones relacionadas con el control de la red.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *