10 mejores prácticas para asegurar las imágenes de Docker. Parte 2

Se preparó una traducción del artículo específicamente para estudiantes del curso de seguridad de Linux .


Lee la primera parte


5. No deje datos confidenciales en las imágenes de Docker


A veces, al crear una aplicación dentro de una imagen de Docker, necesita datos tan sensibles como una clave SSH privada para extraer código de un repositorio privado o tokens para instalar paquetes cerrados. Si los copia en un contenedor Docker intermedio, se almacenan en caché en la capa a la que se agregaron, incluso si los elimina más adelante. Estos tokens y claves deben almacenarse fuera del Dockerfile .

Usa compilaciones de varias etapas


Utilizando el soporte de Docker para compilaciones de varias etapas, manipule secretos en la capa media de la imagen, que posteriormente se elimina para que no lleguen datos confidenciales a la compilación final. Use el siguiente código para agregar datos secretos al middleware:

 FROM: ubuntu as intermediate WORKDIR /app COPY secret/key /tmp/ RUN scp -i /tmp/key build@acme/files . FROM ubuntu WORKDIR /app COPY --from=intermediate /app . 

Usar los comandos de Docker Secrets


Use la función alfa en Docker para administrar datos confidenciales para montar archivos confidenciales sin almacenarlos en caché:

 # syntax = docker/dockerfile:1.0-experimental FROM alpine # shows secret from default secret location RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecre # shows secret from custom secret location RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar 

Puede obtener más información sobre la gestión de datos confidenciales en el sitio web de Docker.

Cuidado con la copia recursiva


También debe prestar atención a copiar archivos a la imagen creada. Por ejemplo, el siguiente comando copia recursivamente toda la carpeta de contexto de ensamblaje en una imagen de Docker, lo que también puede provocar la copia de archivos confidenciales:

 COPY . . 

Si hay archivos confidenciales en su carpeta, elimínelos o use .dockerignore para ignorarlos:

 private.key appsettings.json 

6. Use etiquetas fijas para la inmunidad


Cada imagen de Docker puede tener múltiples etiquetas que representan variaciones de las mismas imágenes. La etiqueta más común es la latest , que representa la última versión de una imagen. Las etiquetas de imagen no son inmutables, y un autor de imagen puede publicar la misma etiqueta varias veces.

Esto significa que la imagen base para su archivo Docker puede cambiar entre compilaciones. Esto puede conducir a un comportamiento inesperado debido a los cambios realizados en la imagen base.

Hay varias formas de solucionar este problema:

  • Prefiere la etiqueta más específica disponible. Si la imagen tiene varias etiquetas, como :8 y :8.0.1 o incluso :8.0.1-alpine , prefiera la última, ya que es el enlace más específico a la imagen. Evite usar las etiquetas más comunes, como las más recientes. Al fijar una etiqueta específica, tenga en cuenta que eventualmente se puede eliminar.
  • Para resolver el problema de que una etiqueta de imagen específica se vuelve inaccesible y se convierte en un límite de visualización de anuncios para los grupos que dependen de ella, considere iniciar un espejo local de esa imagen en el registro o cuenta que esté bajo su propio control. Es importante tener en cuenta los costos de mantenimiento necesarios para este enfoque, ya que esto significa que debe mantener el registro. Es una buena práctica replicar la imagen que desea utilizar en su registro para asegurarse de que la imagen que está utilizando no cambie.
  • ¡Sé extremadamente específico! En lugar de extraer la etiqueta, extraiga la imagen utilizando un enlace SHA256 específico a la imagen Docker, lo que garantiza que obtenga la misma imagen para cada solicitud. Sin embargo, tenga en cuenta que el uso de un enlace SHA256 puede tener el siguiente riesgo: si la imagen cambia, es posible que el hash ya no funcione.

7. Use COPY en lugar de ADD


Docker proporciona dos comandos para copiar archivos del host a la imagen de Docker cuando se crea: COPY y ADD . Los comandos son de naturaleza similar, pero difieren en su funcionalidad:

  • COPIAR: copia recursivamente los archivos locales, indicando los archivos o directorios de origen y destino. Con COPY debe declarar ubicaciones.
  • AGREGAR: copia de forma recursiva los archivos locales, crea implícitamente un directorio de destino si no existe y acepta archivos como URL locales o remotas como fuente, que se extiende o carga, respectivamente, en el directorio de destino.
    Aunque las diferencias entre ADD y COPY no son tan fundamentales, son importantes. Esté atento a ellos para evitar posibles problemas de seguridad:
  • Cuando se utilizan URL remotas para descargar datos directamente a su ubicación original, esto puede conducir a ataques de intermediarios que modifican el contenido del archivo descargado. Además, el origen y la autenticidad de las URL remotas deben verificarse más a fondo. Cuando se usa COPY, la fuente de los archivos que se descargarán desde URL remotas debe declararse a través de una conexión TLS segura, y su origen también debe verificarse.
  • Notas sobre el espacio y las capas de imágenes: el uso de COPY le permite separar la adición del archivo de ubicaciones remotas y descomprimirlo en diferentes capas, lo que optimiza el caché de imágenes. Si se requieren archivos remotos, combínelos en un solo comando EJECUTAR, que posteriormente descarga, extrae y purga, optimizando la operación de una sola capa en varias capas que se requerirían usando ADD.
  • Cuando se utilizan archivos locales, ADD los extrae automáticamente al directorio de destino. Aunque esto puede ser aceptable, agrega el riesgo de obtener bombas Zip y vulnerabilidades Zip Slip , que luego se pueden iniciar automáticamente.

8. Use etiquetas de metadatos


Las etiquetas de imagen proporcionan metadatos para las imágenes que crea. Esto facilita a los usuarios descubrir cómo usar la imagen. La etiqueta más común es "mantenedor", que indica la dirección de correo electrónico y el nombre de la persona que admite esta imagen. Agregue metadatos usando el siguiente comando LABEL :

 LABEL maintainer="me@acme.com" 

Además de los contactos del mantenedor, agregue cualquier metadato que sea importante para usted. Estos metadatos pueden contener: un hash de confirmación, un enlace al ensamblado apropiado, estado de calidad (¿se han pasado todas las pruebas?), Código fuente, un enlace a la ubicación del archivo SECURITY.TXT, etc.

Es una buena práctica admitir el archivo SECURITY.TXT (RFC5785), que apunta a su política de divulgación responsable para su esquema de etiqueta Docker al agregar nuevos, por ejemplo:

 LABEL securitytxt="https://www.example.com/.well-known/security.txt" 

Ver más información de la etiqueta para las imágenes de Docker:

https://label-schema.org/rc1/

9. Use el ensamblaje de etapas múltiples para imágenes pequeñas y seguras


Cuando crea una aplicación utilizando el Dockerfile , se crean muchos artefactos que son necesarios solo durante la compilación. Pueden ser herramientas de desarrollo y bibliotecas necesarias para la compilación, o dependencias necesarias para ejecutar pruebas unitarias, archivos temporales, secretos, etc.

El almacenamiento de estos artefactos en una imagen básica que se puede usar en la producción conduce a un aumento en el tamaño de la imagen de Docker, lo que puede afectar en gran medida el tiempo necesario para cargarla y también aumentar la superficie de ataque, ya que esto dará lugar a la instalación de más paquetes. Lo mismo es cierto para la imagen de Docker que está utilizando: es posible que necesite una imagen de Docker específica para generar, pero no para ejecutar el código de su aplicación.

Golang es un gran ejemplo. Para crear una aplicación Golang, necesita un compilador Go. El compilador crea un archivo ejecutable que se ejecuta en cualquier sistema operativo, sin dependencias, incluidas imágenes limpias.

Esta es una buena razón por la cual Docker tiene la capacidad de construir en etapas. Esta función le permite usar varias imágenes temporales durante el proceso de ensamblaje, guardando solo la última imagen junto con la información que copió en ella. Entonces tienes dos imágenes:

  • La primera imagen es de un tamaño muy grande, junto con muchas dependencias que se utilizan para crear la aplicación y ejecutar las pruebas.
  • La segunda imagen es muy clara en términos de tamaño y número de bibliotecas, y contiene solo copias de los artefactos necesarios para ejecutar la aplicación en producción.

10. Usa el linter


Use la interfaz para evitar errores comunes y establecer las mejores prácticas que los ingenieros pueden seguir automáticamente.

Uno de esos linter es hadolint . Analiza el Dockerfile y emite una advertencia sobre cualquier error que no cumpla con sus recomendaciones.



Hadolint se vuelve aún más poderoso cuando se usa en un entorno de desarrollo integrado (IDE). Por ejemplo, cuando se usa hadolint como una extensión VSCode, aparecen errores de linting durante la entrada. Esto ayuda a escribir los mejores dockerfiles más rápido.

Obtenga más información sobre cómo proteger sus imágenes de Docker.

Source: https://habr.com/ru/post/482044/


All Articles