Reforzar la seguridad de Amazon EKS con RBAC, IMDS seguro y registros de auditoría
Kamil Potrec
7 de julio de 2021
0 minutos de lecturaLas configuraciones incorrectas en la infraestructura como código (IaC) pueden ser tan peligrosas como las vulnerabilidades en el código. Pequeños errores de configuración pueden hacer que los datos confidenciales queden expuestos en Internet o que los endpoints privados y el panel queden accesibles para usuarios anónimos y se aprovechen como punto de entrada para un ataque. Investigaciones recientes sobre seguridad indican un aumento del malware dirigido a la plataforma Kubernetes, lo que demuestra la necesidad de contar con una configuración segura.
En esta serie de publicaciones del blog, analizaremos la configuración predeterminada de las implementaciones de Amazon Elastic Kubernetes Service (EKS). Luego mostraremos cómo pequeñas configuraciones incorrectas o efectos secundarios no deseados pueden exponer nuestros clústeres a problemas de seguridad en EKS.
¿Qué es Amazon Elastic Kubernetes Service?
Amazon Elastic Kubernetes Service es un servicio de Kubernetes administrado. AWS se encarga de administrar los componentes del plano de control del clúster, mientras que el cliente es responsable de administrar los nodos de trabajo y los recursos del clúster.
Además de ofrecer alta disponibilidad y escalabilidad del plano de control, Amazon EKS se integra con Identity Access Management para administrar los controles de acceso basados en roles, asociar cuentas de servicio de Kubernetes con roles de IAM, usar grupos de nodos administrados para escalar automáticamente la capacidad de los nodos de trabajo según la demanda, centralizar los registros y mucho más. Consulta la documentación oficial de Amazon EKS para ver la lista completa de funciones.
Algunas desventajas de usar un servicio administrado, además de los costos adicionales, son la pérdida de control granular sobre la configuración del plano de control y el hecho de que los datos almacenados en la base de datos del plano de control deben residir en cuentas propiedad de AWS.
Implementación rápida de EKS
Amazon EKS se puede implementar de varias maneras, como mediante una consola web, la herramienta de línea de comandos de Amazon EKS o herramientas de IaC, como CloudFormation o Terraform.
Usaremos Terraform para implementar un clúster con los valores predeterminados. Puedes encontrar los archivos de configuración de Terraform para esta demostración en este repositorio. Usaremos Terraform Cloud para ejecutar los comandos de Terraform y conservar los cambios de estado.
El clúster de EKS debe ejecutarse dentro de una VPC. Puedes implementar una VPC con Terraform usando este módulo.
Para nuestro entorno de demostración, implementaremos 3 subredes privadas y 3 públicas. Las subredes privadas no tienen una ruta predeterminada hacia la puerta de enlace de Internet. Una puerta de enlace NAT permitirá que las subredes privadas accedan a Internet. Nota: Para esta demostración, implementaremos una sola puerta de enlace NAT. A continuación se muestra la arquitectura de red general de nuestro entorno de demostración.

El clúster de EKS necesita el ID de una VPC existente y los ID de las subredes que se usarán para comunicarse con los grupos de nodos y aprovisionar balanceadores de carga para los servicios y controladores de entrada. Como parte de nuestro entorno de demostración, implementaremos un grupo de nodos autoadministrado con 3 instancias.
Terraform Cloud permite ejecutar planes desde su interfaz de usuario o mediante operaciones remotas. Para iniciar acciones desde la interfaz, debes confirmar el código en el sistema de control de versiones. Las operaciones remotas permiten obtener rápidamente comentarios sobre el estado de los archivos de configuración locales. En segundo plano, Terraform carga un archivo comprimido de la configuración local a un servidor remoto, ejecuta el comando de forma remota y transmite los resultados a la terminal. Para usar un archivo de estado administrado por Terraform Cloud, debemos agregar una configuración de backend con el espacio de trabajo y la organización correctos.
Esto también requiere acceso a Terraform Cloud mediante la API. Para obtener más información sobre cómo configurarlo, consulta la documentación oficial de Terraform Cloud.
El plan inicial indica que nuestros archivos de configuración crearán 44 recursos nuevos.
Ahora podemos usar la interfaz de usuario de Terraform Cloud para implementar el entorno. Una vez que termine la implementación, podremos ver información sobre nuestro nuevo clúster en la página de descripción general.

Una vez implementado el entorno, podemos seguir la documentación oficial de AWS para acceder al clúster de demostración.
Este clúster será nuestro punto de referencia para la evaluación. Empecemos por observar lo fácil que fue conectarnos al clúster.
Restringir el acceso a la API de Kubernetes
El servicio EKS permite acceder a la API de Kubernetes mediante endpoints de servicio. De forma predeterminada, el endpoint del clúster es de acceso público. Esto significa que cualquier persona en Internet puede intentar acceder a él. De forma predeterminada, la API de Kubernetes acepta solicitudes anónimas; sin embargo, los autorizadores ABAC y RBAC requieren autorización explícita para los usuarios anónimos o no autenticados. Los clústeres de EKS tienen RBAC habilitado de forma predeterminada, y podemos comprobarlo revisando los indicadores del servidor de API.
Los registros también muestran que EKS implementa un método de autenticación de tokens mediante webhook. Esto significa que los usuarios de Kubernetes deben obtener el token de autenticación de la API de AWS, que es independiente del endpoint de la API de Kubernetes del clúster. Amazon EKS no afecta las decisiones de autorización que toma el clúster.
Para tener aún más certeza, podemos intentar conectarnos al clúster sin credenciales autenticadas. Para simular usuarios anónimos, debemos enviar una solicitud a la API sin un encabezado de autorización. kubectl tiene una opción de depuración muy útil que muestra todas las solicitudes como comandos CURL que podemos reutilizar.
Si enviamos la misma solicitud sin el encabezado de autorización correcto, veremos que no se autorizó la solicitud.
Ahora que hemos confirmado que el acceso a nuestros recursos está algo restringido de forma predeterminada, es momento de hablar de la defensa en profundidad. Este concepto se refiere a implementar varias capas de controles de seguridad para evitar unúnico punto de falla en nuestro sistema de seguridad. En nuestra implementación actual, los permisos de RBAC son el único control que impide que cualquier persona en Internet acceda a nuestro clúster.
Este archivo de configuración muestra cómo se podría habilitar el acceso anónimo:
Una vez aplicada esta configuración, podemos ver que la solicitud anónima se procesa correctamente:
Los desarrolladores de Kubernetes han incorporado algunas medidas de seguridad para garantizar que este tipo de configuración sea explícita. El usuario system:anonymous y el grupo system:unauthenticated deben aparecer explícitamente en el atributo subjects. El uso de caracteres comodín, como *, no otorga acceso a estos dos sujetos. Puedes comprobarlo si cambias el name del sujeto de nuestro ejemplo por el carácter *.
El acceso público al servidor de API de Kubernetes también aumenta el impacto de cualquier filtración de credenciales. Si la API es de acceso público, las credenciales filtradas podrían usarse desde cualquier parte del mundo. Una vulnerabilidad de día cero descubierta en el flujo de autorización es otro motivo importante para limitar quién puede enviar paquetes al servidor de API. En el pasado se han reportado vulnerabilidades de este tipo, como CVE-2019-11253 y CVE-2020-8559.
Podemos reducir el impacto de los endpoints públicos si limitamos las direcciones IP que tienen acceso. En Terraform, esto se puede expresar agregando el atributo cluster_endpoint_public_access_cidrs a la definición del módulo.
La segunda opción es deshabilitar por completo el endpoint público y habilitar un endpoint privado de VPC. Esto se puede habilitar en el módulo de Terraform mediante los atributos cluster_endpoint_private_access y cluster_endpoint_public_access. Así, solo los usuarios que tengan acceso a la red de VPC podrán acceder al clúster.
Sin embargo, ambas opciones tienen un gran impacto en los costos operativos. No contar con un endpoint público puede causar problemas si se usa un sistema de implementación continua público, como Terraform Cloud. En nuestro entorno de demostración, deshabilitar el endpoint público provocó un error de acceso denegado durante la implementación.

Este error se produce porque, internamente, el módulo de Terraform intenta actualizar el mapa de configuración aws-auth, lo cual solo se puede hacer mediante la API de Kubernetes. Como puedes ver, el FQDN del servidor de API se resolvió como una dirección IP privada y el proveedor no puede conectarse. Podemos corregir este error si deshabilitamos la administración del mapa de configuración en nuestro módulo de Terraform. Esto implica que, a partir de ese momento, tendremos que administrar el mapa de configuración de autorización mediante otro método.
Para deshabilitar por completo el endpoint público, tendrás que implementar un sistema de CD que se ejecute dentro de la VPC y tenga acceso al endpoint privado, o que actúe como proxy de la conexión. Este es un excelente artículo sobre cómo lograrlo con AWS CodePipeline, y puedes usar este módulo de Terraform para ejecutar Atlantis dentro del servicio AWS Fargate.
El acceso para los desarrolladores también puede complicarse, ya que tendrás que implementar un servicio de bastión o VPN para proporcionar acceso al endpoint privado.
Restringir el acceso al servicio de metadatos de instancia
EKS utiliza perfiles de instancia para otorgar permisos de AWS a un kubelet que se ejecuta en un nodo. El kubelet puede acceder a estas credenciales mediante el servicio de metadatos de instancia (IMDS). Se puede acceder a IMDS mediante una solicitud HTTP a una dirección IP de enlace local. De forma predeterminada, todos los pods del nodo pueden acceder a este servicio de metadatos. Podemos comprobarlo si ejecutamos un pod y obtenemos un token de STS.
En el ejemplo anterior, podemos usar todos los permisos asignados al nodo. Esto representa un claro problema de seguridad de escalamiento de privilegios, ya que, de forma predeterminada, los pods no deberían necesitar acceso a AWS.
La única forma de mitigar este problema es limitar el acceso de red de los pods al servicio IMDS. IMDS tiene dos versiones. La versión 1 usa un método de solicitud y respuesta y cualquier proceso que pueda enviar paquetes a la dirección de enlace local puede consultarla. La versión 2 usa sesiones e incorpora la posibilidad de establecer un tiempo de vida (TTL) arbitrario para los mensajes de respuesta. Según la documentación de AWS, IMDSv1 seguirá disponible junto con IMDSv2.
Para limitar el alcance de este problema con la configuración nativa de AWS, debemos deshabilitar IMDSv1 por completo. Esto se logra configurando el atributo metadata_http_tokens de los nodos de trabajo como required. El segundo paso consiste en limitar a 1 el TTL de los paquetes de respuesta, que de hecho es el comportamiento predeterminado del servicio. Al establecer el TTL en 1, la capa de red de Kubernetes no puede reenviar el paquete al espacio de nombres de red del pod.
El módulo de Terraform para Amazon EKS usa grupos de escalamiento automático y plantillas de lanzamiento para crear nodos. Esto significa que, si actualizas la configuración del servicio de metadatos, tendrás que renovar las instancias.
La limitación de esta solución es que cualquier pod cuyo atributo hostNetworking esté configurado como true todavía podrá obtener las credenciales.
También se pueden usar las políticas de red nativas de Kubernetes para restringir el acceso a direcciones IP de enlace local y, así, impedir el acceso a IMDS. La documentación de AWS Calico explica cómo instalar el complemento CNI de Calico. La siguiente política de red debería impedir el acceso a IMDS. El complemento de Calico no aísla los pods que tienen hostNetwork configurado como true, por lo que presenta la misma desventaja que la solución nativa de deshabilitar IMDSv1 y establecer el TTL máximo en 1. Sin embargo, las políticas de red no requieren renovar los nodos y se pueden aplicar a pods específicos si realmente necesitan usar IMDS.
Habilitar el registro de eventos
Ahora que vimos algunas configuraciones incorrectas que pueden exponer los clústeres de EKS a amenazas externas e internas, veamos si podemos auditar estos eventos. Kubernetes proporciona registros de auditoríapara que los administradores puedan monitorear las acciones que realizan los usuarios y servicios del clúster. Lamentablemente, estos registros no están habilitados de forma predeterminada en EKS ni en la configuración predeterminada del módulo de Terraform. Para habilitarlos, debemos usar el atributo cluster_enabled_log_types y especificar los tipos de registros necesarios.
EKS nos permite habilitar varios tipos de registros de forma independiente. Desde el punto de vista de la seguridad, nos interesan sobre todo los registros audit y authenticator.
Los registros de auditoría nos permiten monitorear las solicitudes de Kubernetes y atribuirlas a las entidades correspondientes. Ten en cuenta que generan eventos por cada acción realizada en el clúster y, por lo tanto, transmiten grandes volúmenes de datos al destino configurado, que de forma predeterminada es CloudWatch. Si nos limitamos a audit y authenticator, podemos reducir el volumen.
Por ejemplo, podemos buscar actualizaciones en el mapa aws-config para identificar si alguien lo manipuló. Podemos usar el siguiente filtro para obtener todos los eventos de tipo patch relacionados con un objeto llamado aws-auth.
Los eventos de auditoría contienen información muy útil que puede ayudarnos a identificar quién hizo el cambio, desde dónde se conectó y mucho más.
Estos registros también pueden ser muy útiles para detectar intentos de acceso a recursos por parte de usuarios no autorizados. La siguiente consulta permite buscar solicitudes enviadas por usuarios anónimos:
Por otro lado, los registros de Authenticator pueden ayudarnos a rastrear quién intenta iniciar sesión en el clúster y relacionar esas entidades con grupos y usuarios de Kubernetes. En el ejemplo anterior, sabemos que el usuario con el ID de clave AROAYREY3WYOBFHU7VIRM cambió el configmap; sin embargo, no sabemos a qué entidad de AWS pertenece ese ID de clave.
A continuación: Protección avanzada de Amazon EKS
En esta publicación del blog, exploramos algunos de los problemas de seguridad que pueden surgir al usar Amazon Elastic Kubernetes Service, incluidos los relacionados con la autenticación y autorización, y el acceso al servicio de metadatos de instancias. También vimos cómo podemos mitigar estos problemas en producción. En la próxima parte de esta serie, exploraremos la arquitectura multicuenta como paso esencial para aislar los clústeres de Amazon EKS, la importancia de usar roles de IAM dedicados al crear clústeres de Amazon EKS y cómo proteger aún más los secretos almacenados en los planos de control de Amazon EKS. Vuelve a consultar las novedades o síguenos en Twitter en @snkysec para recibir una notificación cuando se publique.
El análisis de Snyk Infrastructure as Code (Snyk IaC) también puede ayudar a mitigar los problemas de seguridad al usar Amazon EKS mediante Cloud Formation o Terraform, ya que identifica problemas de seguridad en el código de implementación antes de que llegue a producción. Crea una cuenta gratuita y comienza a analizar.
Protege la infraestructura desde el origen
Snyk automatiza la seguridad y el cumplimiento de IaC en los flujos de trabajo, y detecta recursos con desviaciones de configuración y recursos faltantes.
