Ir al contenido
  1. Posts/

Hadolint: Verificando nuestros Dockerfiles

·1265 palabras·6 mins· loading · loading ·
Linux Contenedores DevOps Seguridad docker contenedores infraestructura devops ci seguridad
Autor
Enmanuel Moreira
Ingeniero DevOps de día y aprendiz de Barman en mis tiempos libres, con experiencia en Kubernetes, Cloud, y DevOps. También disfruta de hacer stream de juegos, hablar de CI/CD, desplegar en producción un viernes con Terraform y automatizar tareas aburridas con Ansible.
Docker - Este artículo es parte de una serie.
Parte 10: Este artículo

Hadolint es una herramienta de linea de comandos que nos permitirá analizar nuestros Dockerfiles y ayudarnos a que los mismos cumplan con una serie de reglas y buenas prácticas.

PROMO DigitalOcean
#

Antes de comenzar, quería contarles que hay una promoción en DigitalOcean donde te dan un crédito de USD 200.00 durante 60 días para que puedas probar los servicios que este Proveedor Cloud ofrece. Lo único que tienes que hacer es suscribirte a DigitalOcean con el siguiente botón:

DigitalOcean Referral Badge

O a través del siguiente enlace: https://bit.ly/digitalocean-itsm

Como funciona
#

  • Hadolint lee el Dockerfile.

  • Mediante AST ( Abstract Syntax Tree) identifica las instrucciones y los argumentos contenidos en el archivo.

  • Valida cada instrucción contra una seria de reglas predefinidas que cubren seguridad, eficiencia y calidad de código. Las reglas son parte del código fuente de Hadolint. Podremos encontrar las reglas predefinidas aquí

  • Todas las reglas que se incumplan serán mostradas en la salida en consola y de esta manera crear feedback con todos los problemas detectados.

Funcionamiento de Hadolint tras bambalinas

Instalando Hadolint
#

Linux
#

Descargamos el ejecutable desde el Sitio Oficial de Hadolint en GitHub:

wget -O hadolint https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64

Luego lo movemos al directorio /usr/local/bin:

sudo mv hadolint /usr/local/bin/hadolint

Le damos permisos de ejecución:

sudo chmod +x /usr/local/bin/hadolint

Mac OS
#

A través de Homebrew podremos instalarlo facilmente:

brew install hadolint

Y chequeamos su versión actual:

hadolint --version

Windows
#

Usando scoop:

scoop install hadolint

Docker (Recomendado)
#

Descargamos la imagen:

docker pull hadolint/hadolint

O si queremos directamente analizar un Dockerfile:

docker run --rm -i hadolint/hadolint < Dockerfile

Analizando Dockerfiles
#

Lo mejor para entender como funciona Hadolint es hacerlo práctico, entonces, teniendo el siguiente Dockerfile:

FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get update && apt-get install -y curl
RUN echo "hello world" | grep "world" | wc -l
CMD ["echo", "Hello, world!"]

Teniendo el Dockerfile guardado en el mismo directorio donde vamos a ejecutar lo siguiente:

hadolint Dockerfile
Dockerfile:1 DL3007 warning: Using latest is prone to errors if the image will ever update. Pin the version explicitly to a release tag
Dockerfile:2 DL3009 info: Delete the apt-get lists after installing something
Dockerfile:3 DL3059 info: Multiple consecutive `RUN` instructions. Consider consolidation.
Dockerfile:3 DL3008 warning: Pin versions in apt get install. Instead of `apt-get install <package>` use `apt-get install <package>=<version>`
Dockerfile:3 DL3015 info: Avoid additional packages by specifying `--no-install-recommends`
Dockerfile:4 DL3008 warning: Pin versions in apt get install. Instead of `apt-get install <package>` use `apt-get install <package>=<version>`
Dockerfile:4 DL3015 info: Avoid additional packages by specifying `--no-install-recommends`
Dockerfile:4 DL3009 info: Delete the apt-get lists after installing something
Dockerfile:5 SC2126 style: Consider using 'grep -c' instead of 'grep|wc -l'.
Dockerfile:5 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then considerexplicitly setting your SHELL to /bin/ash, or disable this check

Obtendremos la siguiente salida con mensajes de tipo Warning e Info con las reglas y como solucionarlos como se muestra arriba.

Si prestamos atención a la linea 5, Hadolint nos provee información sobre una instrucción shell. Hadolint utiliza Shellcheck tras bastidores para validar scripts shell que son parte de la instrucción RUN.

Si implementamos todas las recomendaciones, tendriamos el siguiente Dockerfile:

# Use Ubuntu 20.04 as the base image
FROM ubuntu:20.04

# Set the default shell with -o pipefail
SHELL ["/bin/bash", "-o", "pipefail", "-c"]

# Run commands
RUN apt-get update && \
    apt-get install -y curl=8.4.0 --no-install-recommends && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/* && \
    echo "hello world" | grep -c "world"

# Default command to run
CMD ["echo", "Hello, world!"]

Y analizando nuevamente el Dockerfile nos encontraríamos con un mensaje de salida 0 (exitoso):

hadolint Dockerfile
echo $?
0

Excepcionando Reglas
#

Hay casos en los cuales no queremos solucionar todas las recomendaciones (bien sea porque necesitemos un Dockerfile con bastantes RUN porque somos masoquistas), podemos excepcionar algunas reglas especificas usando el parámetro --ignore

Por ejemplo, si quisiéramos excepcionar la regla DL3008 que recomienda tener versiones especificas de los paquetes que instalemos a la imagen, lo excepcionamos de la siguiente manera:

hadolint --ignore DL3008 Dockerfile

Cuando trabajamos con CI/CD, podemos estandarizar toda la configuración de las reglas a través de un archivo hadolint.yaml.

hadolint.yaml
#

Este archivo puede compartirse con desarrolladores o ingenieros de software quienes codean Dockerfiles.

Pasemos a explicar un poco los parámetros con la Documentación en la mano:

  • failure-threshold: Especificamos el nivel en el cual va a fallar la comprobación. Por ejemplo, de manera predeterminada Hadolint devuelve un valor distinto a 0 para fallar. Podemos configurar ese nivel de fallo solo para Warning y Errors pudiendo Info y Style ser ignorados.

  • ignored: Si quieres ignorar reglas especificas, puedes listarlas debajo del parámetro ignore.

  • override: Este parámetro es muy útil si querríamos sobrescribir el nivel de severidad de reglas especificas. Por ejemplo, la regla DL3015 es de tipo Info, sin embargo, podemos modificarla para que se de tipo Warning. Entonces, cuando Hadolint se ejecute, esa regla especifica (DL3015) será mostrada como warning.

  • trustedRegistries: En la mayoría de las organizaciones, solo se permite el uso de un registro de imágenes interno. Si quisiéramos permitir mas de un registro agregando sus endpoints. En caso que el Dockerfile contenga imágenes de otros registros, la comprobación fallara.

Aqui tenemos un ejemplo, el cual debe ser guardado como .hadolint.yaml:

failure-threshold: warning
format: tty
ignored:
- DL3007
override:
  error:
  - DL3015
  warning:
  - DL3015
  info:
  - DL3008
  style:
  - DL3015
trustedRegistries:
- docker.io
- techiescamp.com:5000
- "*.gcr.io"
- quay.io
hadolint --config .hadolint.yaml Dockerfile

Configurando CI/CD
#

¿Un ejemplo con GitLab? Un ejemplo con GitLab :)

Supongamos que ya tenemos nuestro archivo de pipeline (.gitlab-ci.yml) con los stages lint y build. En el stage Lint vamos a declarar las tareas para ejecutar Hadolint y:

stages:
  - lint
  - build

Lint Analisys:
  stage: lint
  image: hadolint/hadolint:v2.12.0-alpine
  script:
    - mkdir -p reports
    - hadolint -f gitlab_codeclimate Dockerfile* > reports/hadolint-$(md5sum Dockerfile | cut -d" " -f1).json
  artifacts:
    name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
    expire_in: 1 week
    when: always
    reports:
      codequality:
        - "reports/*"
    paths:
      - "reports/*"
  allow_failure: true

Bulding image:
  stage: build
  script:
...

Creamos una carpeta que se llame reports, y luego guardamos en un archivo .json el resultado de Hadolint, el cual almacenamos como un artefacto por 1 semana. Con allow_failure controlamos si queremos que permite que falle el stage y poder continuar con la ejecución de los siguientes stages.

Si tuviéramos la versión de GitLab Enterprise, pudiésemos ver los resultados en tiempo real en nuestro panel de stage con la opción gitlab_codeclimate.

Ventajas de usar Hadolint
#

  • Mejora la calidad de código de nuestros Dockerfiles, identificando errores y optimizando la cantidad de capas de la imagen resultante.

  • Reduce los riesgos de seguridad identificando posibles vulnerabilidades, como imágenes antiguas, etc.

  • Mejora el rendimiento identificando posibles problemas que puedan reducirlo, como por ejemplo construir imágenes innecesariamente grandes.

  • Mejora la consistencia de nuestros Dockerfiles y haciendo cumplir las buenas praticas de la empresa u organización.

Hasta aquí el artículo, espero les haya gustado, ¡hasta la próxima!

Referencias
#

Artículos sobre Docker
#

Docker - Este artículo es parte de una serie.
Parte 10: Este artículo