Herramientas de línea de comandos para contenedores: cómo usar Snyk con Buildah, Podman y Skopeo
9 de diciembre de 2020
0 minutos de lecturaA medida que el ecosistema de contenedores ha madurado, algo que no nos falta son opciones, tanto en cuanto al software que usamos como a la forma de integrarlo todo.
Una de estas opciones es la combinación de Buildah, Podman y Skopeo: tres herramientas de línea de comandos de código abierto que surgieron en el ecosistema de RedHat. Como su nombre indica, Buildah ofrece una amplia variedad de funciones para crear contenedores e imágenes compatibles con OCI; Podman permite administrar y ejecutar contenedores OCI, mientras que Skopeo es una herramienta para trabajar con registros de contenedores.
En esta publicación del blog veremos cómo el uso de estándares abiertos permite que el análisis de contenedores de Snyk funcione con todas estas tecnologías.
Primero, veamos Skopeo. Es una herramienta de línea de comandos para mover imágenes de contenedores entre repositorios y también puede guardar imágenes localmente. Skopeo permite generar imágenes como archivos Docker o archivos OCI, dos formatos que Snyk admite al analizar desde el sistema de archivos. Usemos Skopeo para descargar una imagen de Quay.io y analizarla localmente desde nuestro sistema de archivos:
Como podemos ver, esta imagen usa una versión de Ubuntu que llegó al fin de su vida útil y, por lo tanto, contiene varias vulnerabilidades que no se corregirán. Así, con Skopeo podemos descargar imágenes de cualquier registro de contenedores que cumpla con los estándares, en formatos compatibles con Snyk, y analizarlas localmente.
Buildah
Ahora veamos Buildah. Buildah es una herramienta de línea de comandos que crea imágenes, pero no las ejecuta, por lo que está pensada para usarse junto con Podman. También está diseñada para funcionar sin privilegios de root: utiliza espacios de nombres de usuario en el kernel de Linux para aislar un shell similar al de root que solo tiene privilegios de usuario. Esto permite que los administradores faculten a los desarrolladores para crear y mantener imágenes de contenedores y, al mismo tiempo, seguir los principios de privilegios mínimos en el entorno de compilación.
Aunque Buildah puede trabajar con Dockerfiles de forma similar a Docker, también permite desarrollar contenedores e imágenes con otros flujos de trabajo, por ejemplo, usando Bash o Python. Esto puede ofrecer ventajas en flexibilidad y facilitar la depuración de las compilaciones de contenedores. Buildah permite, por ejemplo, montar el contenedor intermedio durante el proceso de compilación, para que los scripts puedan verificar que todo se ejecute correctamente antes de continuar, compilar software de forma externa o incluso solicitar datos al usuario. Esto ofrece una alternativa a los procesos de compilación de varias etapas, a veces complicados, que se han convertido en la práctica recomendada al usar Docker.
Veamos un ejemplo de cómo usar Buildah.
Lo primero que debes saber sobre Buildah es que podemos usar Dockerfiles para crear nuestros contenedores, si ese es el flujo de trabajo que te funciona. Tomemos este Dockerfile como ejemplo:
Aquí usamos la imagen de CentOS 8 como base, clonamos el código fuente de GNU Hello, instalamos algunos requisitos previos y luego compilamos e instalamos el binario.
Podemos compilar esto automáticamente con Buildah y la opción bud (build-using-dockerfile):
Esto claramente no es una buena práctica, ya que incluimos tanto el código fuente como los requisitos previos de compilación en nuestra imagen final, y esta imagen incumple la mayoría de las prácticas recomendadas para desarrollar imágenes seguras. Con Docker, la práctica recomendada en este caso sería una compilación de varias etapas. Podríamos usar un Dockerfile de varias etapas con Buildah, pero es más interesante que también podemos usar comandos nativos de Buildah y escribir scripts para hacerlo. Para replicar exactamente lo que hicimos con el Dockerfile anterior, ejecutaríamos el siguiente script:
Sin embargo, Buildah también nos permite montar el contenedor intermedio durante el proceso de compilación. Así, podemos compilar el código fuente en el host y simplemente copiar el binario resultante en el contenedor antes de crear la imagen. De esta forma, podemos aprovechar los recursos del host durante las compilaciones y hacer otras cosas, como usar el administrador de paquetes del host para instalar paquetes en el contenedor. Tampoco necesitamos acceso de root para hacerlo, ya que Buildah admite el uso de espacios de nombres de usuario para permitir el montaje sin privilegios mediante el comando unshare:
Como puedes ver en el ejemplo anterior, después de ejecutar el comando unshare tenemos un shell de root, aunque está en un espacio de nombres de usuario sin privilegios completos de root. Esto nos permite montar el sistema de archivos del contenedor durante el proceso de compilación. Como se trata de un script de Bash, también podemos aprovechar toda la funcionalidad que ofrece un lenguaje de programación: podríamos usar condicionales y bucles, e incluso solicitar datos al usuario durante el proceso.
Podman
Una vez que ejecutamos este script y creamos nuestra imagen, también podemos analizarla con Snyk; aquí es donde entra en juego Podman. Podman es un motor de contenedores sin daemon para desarrollar, administrar y ejecutar contenedores OCI. Como Buildah y Podman se basan en estándares abiertos, Snyk siempre ha podido analizar imágenes creadas o descargadas con Podman: basta con usar Podman para guardar la imagen en el disco y analizarla desde el sistema de archivos. Podman permite guardar imágenes tanto como archivos Docker estándar como en formato de archivo OCI, y Snyk admite ambos.
Ahora bien, como nuestra imagen base es pública y está disponible en Dockerhub, si queremos analizarla con Snyk CLI, también podemos hacer lo siguiente:
En este caso, Snyk se comunicará directamente con Dockerhub y analizará la imagen de origen.
Sin embargo, ninguna de esas opciones funcionará si la imagen solo existe localmente en Podman o si está en un repositorio privado de Dockerhub que requiere iniciar sesión. Por ejemplo, intentemos analizar nuestra imagen compilada directamente desde Podman:
Para estos casos, Snyk usa el cliente local de Docker, ya sea mediante la API de Registry o el socket de Docker. Como el sistema no tiene el binario de Docker, Snyk intentó usar la API de Registry y no pudo conectarse. De forma predeterminada, Snyk no sabe que esas imágenes existen localmente en Podman ni cómo usar Podman para comunicarse con el origen.
Por suerte, Podman ofrece algunas funciones de compatibilidad sencillas mediante el paquete podman-docker. Este proporciona un binario falso de Docker, que básicamente es un contenedor de shell para el binario de Podman, y agrega un enlace simbólico entre el socket de la API de Podman y la ubicación predeterminada del archivo de socket de Docker. De forma predeterminada, este paquete crea un enlace simbólico a /var/run/podman/podman.sock, que es el valor predeterminado cuando se ejecuta la API de Podman como root.
Esto sigue sin funcionar, pero esta vez tenemos un error distinto. Snyk detectó un binario llamado docker y ahora intenta conectarse a la ubicación predeterminada del socket de Docker con privilegios. Como todavía no estamos ejecutando la API de Podman, no puede conectarse y vuelve a fallar.
Como vimos antes, el paquete podman-docker crea un enlace simbólico desde /var/run/podman/podman.sock hasta /var/run/docker.sock, suponiendo que la API de Podman se ejecutará con privilegios.
Uno de los principales problemas del socket de Docker es que, de forma predeterminada, se ejecuta con privilegios, lo que se considera un riesgo de seguridad en ciertos entornos. En la mayoría de los entornos de desarrollo local no necesitamos ejecutar la API de Podman de esa manera; podemos usar un socket sin privilegios en otra ubicación. También podemos comunicarle esa ubicación a Snyk mediante la variable de entorno DOCKER_HOST, que admite los formatos de URL tcp:// y unix://.
En otra terminal, ejecutemos la API de Podman con un socket sin privilegios:
El proceso se ejecutará en primer plano, así que tendrás que presionar Ctrl+C para finalizarlo cuando termines la prueba. Ahora tenemos que establecer la variable de entorno DOCKER_HOST:
Por último, intentemos analizar de nuevo nuestra imagen local con Snyk:
¡Listo! Snyk ahora funciona correctamente y se comunica con Podman mediante el socket sin privilegios.
Para configurar DOCKER_HOST de forma permanente en tu shell, puedes agregar el comando export al archivo .bashrc para que el valor se mantenga.
Por último, nos gustaría que toda esta configuración estuviera disponible automáticamente cada vez que iniciamos sesión. Para lograrlo, podemos aprovechar las funciones de activación de sockets de systemd, que iniciarán automáticamente nuestro socket cuando iniciemos sesión e intentemos conectarnos a él.
Primero, tenemos que configurar el socket:
Luego, asociamos el socket con un servicio:
Por último, volvemos a cargar la configuración de systemd y habilitamos el servicio.
Conclusión
Y así es como el análisis de imágenes de Snyk CLI funciona con Podman igual que con Docker, lo que permite a los desarrolladores analizar de forma integral y sencilla imágenes locales de Docker u OCI como parte de su flujo de trabajo, sin necesitar privilegios elevados. También vimos cómo usar Skopeo y Buildah con Snyk gracias al poder de los estándares abiertos.
¿Todavía no tienes una cuenta de Snyk? Regístrate gratis y usa Snyk para analizar tanto imágenes de contenedores como dependencias de código abierto.
Empieza con los retos de Capture the Flag
Aprende a resolver retos de Capture the Flag viendo nuestro taller virtual de nivel básico a pedido.


