Formatos de imágenes de contenedor por dentro
Agata Krajewska
18 de noviembre de 2020
0 minutos de lecturaEn los últimos años, desde el lanzamiento de Docker, los contenedores se han convertido cada vez más en el mecanismo estándar para la entrega de software.
Vemos un número creciente de soluciones basadas en contenedores y, aunque sin duda celebramos la innovación en este ámbito, es necesario establecer ciertos estándares en torno al formato y el entorno de ejecución.
Debido al rápido crecimiento del proyecto Docker, las imágenes de Docker se convirtieron en un estándar para muchos fines. Sin embargo, hay un interés generalizado en contar con una especificación de contenedores abierta y única que:
no esté vinculada a construcciones de nivel superior, como un cliente o una pila de orquestación específicos,
no esté estrechamente asociada a ningún proveedor comercial o proyecto en particular,
sea portable en una amplia variedad de sistemas operativos, hardware, arquitecturas de CPU, nubes públicas, etc.
OCI (Open Container Initiative) es un proyecto de Linux Foundation para diseñar estándares abiertos de virtualización a nivel del sistema operativo, especialmente de contenedores Linux.
Varias herramientas de compilación de código abierto ya admiten el formato de imágenes OCI, entre ellas:
BuildKit: una versión optimizada y reescrita del motor de compilación de Docker
Podman: una implementación alternativa de la herramienta de línea de comandos de Docker
Buildah: una alternativa de línea de comandos para escribir archivos Dockerfile
Snyk admite todos los formatos de imágenes de contenedor habituales y, por eso, podemos integrarnos con una amplia variedad de herramientas de todo el ecosistema. En esta publicación, veremos algunas de ellas y mostraremos cómo funciona Snyk con estas herramientas.
Archivo de Docker
Primero, veamos el formato de archivo de Docker. Forma parte de la versión 1 obsoleta de la especificación de imágenes de Docker y puedes encontrar la especificación completa aquí. Cuando ejecutas docker save, este es el formato predeterminado que genera el cliente de Docker. Se usa para mantener la compatibilidad con otras herramientas. Los registros de contenedores usan un formato más reciente para almacenar las imágenes
Si ejecutas Docker de forma local y usas la CLI de Snyk o cualquiera de nuestras integraciones de contenedores, usaremos tu instancia local de Docker para extraer la imagen, guardarla en el sistema de archivos e iniciar el análisis.
Exploremos cómo es ese archivo y qué contiene que pueda interesarle a Snyk.
En esta publicación usaré la imagen ubuntu:bionic. Primero, guardemos el archivo en tu sistema de archivos local:
docker save --output ubuntu-docker.tar ubuntu:bionic
La distribución bionic tiene tres capas de imagen, que veremos más de cerca.
Después de descomprimir el archivo tar, podemos inspeccionar su contenido:
Veamos manifest.json:
El archivo nos dirige a la configuración del contenedor, donde encontramos información muy útil, como la arquitectura, la configuración, las capas del sistema de archivos raíz, etc. Además, probablemente la parte más interesante desde el punto de vista de Snyk, la propiedad Layers nos dirige a las capas reales de la imagen, que no son más que directorios dentro del archivo. Si entramos en uno de estos directorios, podemos ver qué contiene:
Profundicemos un poco más y descomprimamos layer.tar:
Como puedes ver arriba, layer.tar es simplemente un conjunto de cambios en el sistema de archivos de la capa de imagen, con todas las dependencias y otros binarios, según el contenido de la imagen. Después de extraer y analizar el contenido
de esas capas, podemos mostrarte la lista de rutas vulnerables.
Ahora ejecutemos snyk test en la imagen del archivo de Docker guardado. Podemos analizar un archivo local especificando el prefijo docker-archive::
snyk container test docker-archive:ubuntu-docker.tar o analizar la imagen desde tu repositorio local de Docker:
snyk container test ubuntu:bionic
Ambos comandos generan exactamente el mismo resultado:
Imagen OCI
En los últimos meses también agregamos el análisis de archivos OCI a la lista de funciones de la CLI de Snyk.
Veamos la especificación y qué encontramos en el archivo. También usaré ubuntu:bionic en esta sección.
Si quieres inspeccionar por tu cuenta un archivo tar de OCI, puedes ejecutar el siguiente comando:
skopeo copy --override-os linux docker://ubuntu:bionic oci-archive:ubuntu.tar
Aquí uso Skopeo para guardar la imagen. Es una utilidad de cli que facilita mucho realizar distintas operaciones con imágenes.
Para guardar una imagen ubuntu en formato OCI, solo tenemos que especificar el prefijo oci-archive: en la salida tar.
Ten en cuenta que también uso la opción --override-os: estoy en macOS y las imágenes de Ubuntu de Docker Hub oficiales solo están disponibles para Linux. Más adelante también hablaremos de las imágenes con varias arquitecturas.
Una vez que descomprimimos el archivo tar, podemos inspeccionar su contenido:
En la raíz encontramos un interesante index.json. Inspeccionemos su contenido:
Este es nuestro manifiesto opcional de nivel superior, que nos dirige a manifiestos de imágenes específicos. Contiene información sobre un conjunto de imágenes que pueden abarcar distintas arquitecturas y sistemas operativos. Si quieres saber más, aquí está la especificación completa.
Ahora inspeccionemos el manifiesto específico de nuestra imagen, al que nos dirigió index.json, en el directorio blobs/sha256:
Empezamos a encontrar contenido interesante, como la configuración del contenedor, donde de nuevo vemos mucha información útil sobre la arquitectura de las imágenes, las capas de la imagen base, la configuración, etc. También tenemos información sobre las capas de la imagen, que nos indica cuáles están disponibles en nuestra imagen ubuntu:bionic.
Como vemos abajo, el contenido de la primera capa es exactamente el mismo que el del archivo de Docker.
Puedes analizar tu archivo OCI local ejecutando:
snyk container test oci-archive:ubuntu.tar
Plataformas y arquitecturas variadas
Al inspeccionar los manifiestos del archivo de Docker y de la imagen OCI, vimos que ambos incluían información sobre la arquitectura. Volvamos a ver el contenido del manifiesto de configuración de nuestro contenedor, en el directorio ubuntu-docker, donde guardamos nuestro docker archive:
Entre otros datos, vemos la arquitectura y el sistema operativo: en mi caso, amd64 y linux. ¿Qué pasa si nuestra imagen se basa en arm64 o si estamos en una plataforma windows?
Tenemos suerte: Snyk también admite otras plataformas. Solo tienes que pasar la opción -—platform a la CLI de Snyk.
Ya hablamos del formato de archivo de docker save. Veamos el formato en que se almacenan las imágenes en Docker Hub: el esquema v2, que tiene aspectos muy interesantes por dentro. Esta es la segunda versión del esquema v2 y se creó para cumplir dos objetivos principales. Según la documentación de Docker:
El primero es permitir imágenes con varias arquitecturas mediante un «manifiesto fat» que hace referencia a manifiestos de imágenes para las versiones de una imagen específicas de cada plataforma. El segundo es acercar el motor de Docker a imágenes direccionables por contenido, mediante la compatibilidad con un modelo de imágenes cuya configuración se puede resumir mediante un hash para generar un ID de imagen.
Con nuestro Docker local, primero podemos inspeccionar el «manifiesto fat» de la imagen que nos interesa para comprobar qué variantes de plataforma están disponibles. Como explicamos arriba, esto significa que un mismo repositorio puede alojar varias imágenes para distintas arquitecturas.
docker manifest inspect ubuntu:bionic
Como resultado, veremos una matriz de manifiestos:
Ahora que sabemos que la imagen ubuntu está disponible para distintas plataformas, veamos cómo analizar la imagen ubuntu para la arquitectura de plataforma arm64.
Asegúrate de que las funciones experimentales estén habilitadas en Docker en tu equipo y ejecuta:
snyk container test --platform=linux/arm64 ubuntu:bionic
Veamos el resultado:
Podemos ver todas las rutas vulnerables que se detectaron y también la información de «Platform» en el resultado del análisis.
En esta publicación, exploramos los dos formatos principales de imágenes de contenedor, Docker y OCI, y mostramos cómo Snyk puede interactuar con ambos, incluso en varias arquitecturas.
Para terminar, sigue las prácticas recomendadas de seguridad para crear imágenes Docker optimizadas para aplicaciones de Node.js y Java:
10 prácticas recomendadas de seguridad para Docker: encontrarás detalles sobre las prácticas de seguridad que debes seguir al crear imágenes base de Docker y al descargarlas. También conocerás Docker Content Trust.
¿Desarrollas en Java? Este recurso te resultará útil: Docker para desarrolladores de Java: 5 aspectos que debes conocer para no poner en riesgo tu seguridad
10 prácticas recomendadas para contenerizar aplicaciones web de Node.js con Docker: si desarrollas en Node.js, te encantará esta guía paso a paso, que muestra cómo crear imágenes base de Docker seguras y eficientes para tus aplicaciones de Node.js.
Puedes acceder gratis a todas estas funciones en Snyk: regístrate para crear una cuenta.
Comienza con Capture the Flag
Aprende a resolver desafíos de Capture the Flag con nuestro taller virtual 101 a pedido.



