Sin embargo, durante el paso del desarrollo al despliegue, así como sí que se suelen tener en cuenta cuestiones de seguridad como los puertos expuestos, los volúmenes que se montan, permisos de usuario, etc. No suele prestarse mucha atención a la imagen que se usa como base del contenedor. Aquí es donde hay que tener en cuenta que el contenido del contenedor es parte de la superficie de ataque de un cluster Kubernetes. Por eso es tan importante tener bien controlados los otros puntos de acceso (puertos, versiones antiguas, volúmenes, permisos, etc.) como lo que el desarrollador mete dentro del contenedor. Un contenedor inseguro en el que pueda escalar privilegios y acceder al nodo anfitrión puede comprometer todo el cluster.
Un ejemplo de esto es la vulnerabilidad CVE-2019-5021 que fue reportada en mayo de 2019 por la que la mayoría de las imágenes que usaban la base Alpine en DockerHub venían con usuario root con contraseña vacía. Esto hacía posible una escalada de privilegios haciendo el contenedor inseguro y facilitando la el escape a la máquina anfitrión.
Usando Trivy para encontrar vulnerabilidades en imágenes Docker
Trivy es una herramienta opensource que cuenta con una extensa base de datos de vulnerabilidades en imágenes de Docker basándose en los sistemas y paquetes que tienen instalados. Esto permite escanearlas y generar informes de seguridad.
La compañía de seguridad Aqua Security la adquirió hace poco más de un mes (agosto 2019) aun teniendo anteriormente su propia herramienta de escáner de vulnerabilidades, y ha asegurado que continuará siendo opensource y que de hecho acabará sustituyendo a la propia de la compañía.
La compañía de seguridad Aqua Security la adquirió hace poco más de un mes (agosto 2019) aun teniendo anteriormente su propia herramienta de escáner de vulnerabilidades, y ha asegurado que continuará siendo opensource y que de hecho acabará sustituyendo a la propia de la compañía.
Su uso es muy sencillo. Tras instalarlo, no hay más que invocarlo con el nombre de la imagen que se quiere auditar y genera un informe de este tipo:
Escaneando con Trivy un contenedor Docker con diferentes imágenes base
Para probar el resultado de utilizar una imagen Docker u otra a la hora de hacer un microservicio en un contenedor he creado una pequeña aplicación de ejemplo en Python que abre un "Hola Mundo" en local en el puerto 5000. Para crear el contenedor he creado varios Dockerfile utilizando diferentes imágenes como base.
Si queréis realizar los pasos que he seguido en este artículo podéis descargaros la aplicación, los Dockerfile e instrucciones de instalación del repositorio de GitHub de este artículo con el siguiente comando:
git clone https://github.com/daviddetorres/jugandocontrivy.git
- python:3.5-alpine
- python:3.5.7-alpine3.10
- python:3.5-stretch
- python:3.5-buster
pythonapp-alpine-python35 (alpine 3.9.4)
========================================
Total: 10 (UNKNOWN: 0, LOW: 1, MEDIUM: 4, HIGH: 5, CRITICAL: 0)
pythonapp-alpine310-python357 (alpine 3.10.2)
=============================================
Total: 6 (UNKNOWN: 0, LOW: 2, MEDIUM: 4, HIGH: 0, CRITICAL: 0)
Este es un ejemplo bastante claro como el simple hecho de elegir entre una imagen genérica y otra con de una versión determinada puede generar un contenedor inseguro en producción.
Las otras dos imágenes con las que hemos hecho imágenes no suelen utilizarse tanto, sobre todo por su peso. Aún así, es interesante ver cómo han salido los informes de seguridad de estas imágenes.
En el caso de la imagen con base python:3.5-stretch (Debian v9.11), el resultado ha sido un número sorprendentemente alto de vulnerabilidades. Nada menos que 3.494, de las que 11 son críticas y 606 altas.
pythonapp-stretch-python35 (debian 9.11)
========================================
Total: 3494 (UNKNOWN: 4, LOW: 134, MEDIUM: 2739, HIGH: 606, CRITICAL: 11)
La imagen con base python:3.5-buster (Debian v10.1) ha salido mejor parada, pero aún así es mucho más insegura que las imágenes de Alpine. En este caso se han detectado 1.184 vulnerabilidades en la imagen, de las cuales 7 son críticas y 95 son altas.
pythonapp-buster-python35 (debian 10.1)
=======================================
Total: 1184 (UNKNOWN: 3, LOW: 70, MEDIUM: 1009, HIGH: 95, CRITICAL: 7)
Algunos consejos de seguridad que podemos extraer de este experimento
El primero que podemos extraer es que no todas las imágenes que se utilizan como base en el Dockerfile son iguales. Hemos visto como la diferencia entre utilizar una imagen python:3.5-alpine (sin especificar la versión) y python:3.5.7-alpine3.10 es importante, sobre todo en las 5 vulnerabilidades altas que elimina la segunda opción.
La segunda conclusión a la que podemos llegar es que cuantos más componentes tenga una imagen de base, más vulnerabilidades puede tener. Esto, en principio hace que Alpine tenga menos que las otras basadas en Debian. Sin embargo debemos hacernos la siguiente pregunta: ¿De verdad para este microservicio necesitamos consola, por ejemplo? Quizás para desarrollo sí, pero para producción no.
En este sentido, han aparecido imágenes Docker sin distribución (distroless). En otro artículo profundizaré un poco más en ellas, pero la idea es que la imagen sólo contiene las librerías necesarias para el microservicio. Por ejemplo, la máquina Java, Python, etc. pero no el resto de componentes que pueden comprometer la imagen convirtiéndolo en producción en un contenedor inseguro y comprometiendo el cluster.