Aller au contenu

Sécuriser les images Docker avec Dockle​

Mise à jour :

logo dockle

La sécurité des conteneurs Docker est devenue un enjeu majeur pour les administrateurs systèmes et les équipes DevOps. Les images non sécurisées peuvent introduire des vulnérabilités critiques dans vos environnements de production. C’est là qu’intervient Dockle, un outil open-source qui m’aide à auditer facilement mes images Docker. Il vérifie leur conformité avec les bonnes pratiques de sécurité, comme celles définies dans les benchmarks CIS Docker. À mon avis, c’est un allié indispensable pour toute démarche DevSecOps.

Qu’est-ce que Dockle ?

Dockle est un outil en ligne de commande spécialement conçu pour analyser la sécurité des images Docker. À la différence des scanners de vulnérabilités classiques comme Trivy, Dockle ne s’intéresse pas uniquement aux paquets logiciels vulnérables. Il se concentre surtout sur des points de configuration souvent négligés, mais critiques. Par exemple : est-ce que l’image utilise un compte utilisateur non privilégié ? Est-ce qu’elle a une instruction HEALTHCHECK ? Y a-t-il des fichiers sensibles laissés dans l’image finale ?

Voici quelques exemples de contrôles que Dockle peut effectuer :

  • Présence d’un utilisateur root par défaut
  • Absence d’un fichier .dockerignore
  • Utilisation de la commande latest dans les FROM
  • Manque d’un HEALTHCHECK
  • Permissions trop larges sur certains fichiers

Dockle se base principalement sur les recommandations du CIS Docker Benchmark, ce qui me permet de rester aligné avec des standards reconnus. Son gros avantage ? Il est simple à utiliser, rapide, et idéal pour une intégration dans un pipeline CI/CD.

Installation de Dockle

Installer Dockle est simple, quelle que soit votre plateforme. Je vais vous montrer comment je procède selon le système d’exploitation utilisé. L’outil est disponible sous forme de binaire, ce qui facilite son intégration dans un environnement automatisé.

Sur macOS

Sur mon Mac, j’utilise Homebrew, c’est le plus rapide :

Terminal window
brew install goodwithtech/r/dockle

Homebrew va automatiquement récupérer et installer la dernière version stable de Dockle.

Sur Linux

Pour les distributions Debian ou Ubuntu :

Terminal window
VERSION=$(
curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \
grep '"tag_name":' | \
sed -E 's/.*"v([^"]+)".*/\1/'
)
curl -L -o dockle.deb https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.deb
sudo dpkg -i dockle.deb && rm dockle.deb

Et pour CentOS, RHEL ou autres distributions RPM-based :

Terminal window
VERSION=$(
curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | \
grep '"tag_name":' | \
sed -E 's/.*"v([^"]+)".*/\1/'
)
sudo rpm -ivh https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit.rpm

Pour toutes les distributions, vous pouvez suivre les dernières versions ici : github.com/goodwithtech/dockle/releases

Controle de la version

Une fois installé, je vérifie la version de Dockle pour m’assurer que tout est fonctionnel :

Terminal window
dockle --version
dockle version 0.4.15

Utilisation de base de Dockle

Une fois Dockle installé, je peux immédiatement commencer à analyser mes images Docker. L’utilisation est très simple : une seule commande suffit pour lancer un audit.

Lancer une analyse

Pour analyser une image, j’utilise cette commande :

Terminal window
dockle NOM_DE_L_IMAGE

Par exemple, pour analyser l’image officielle de Nginx :

Terminal window
dockle nginx:latest

Dockle va alors inspecter l’image et produire un rapport directement dans le terminal. Ce rapport est structuré par types de bonnes pratiques et classé par niveau de gravité :

  • FATAL : erreurs critiques qui nécessitent une action immédiate
  • WARN : configurations risquées ou non recommandées
  • INFO : informations utiles mais non bloquantes
  • PASS : contrôles réussis

Exemples de résultats

Voici le rendu actuelle de Dockle sur l’image Nginx :

FATAL - CIS-DI-0010: Do not store credential in environment variables/files
* Suspicious ENV key found : NGINX_GPGKEYS on RUN /bin/sh -c set -x && groupadd --system --gid 101 nginx && useradd --system --gid nginx --no-create-home --home /nonexistent --comment "nginx user" --shell /bin/false --uid 101 nginx && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates && NGINX_GPGKEYS="573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 8540A6F18833A80E9C1653A42FD21310B49F6B46 9E9BE90EACBCDE69FE9B204CBCDCD8A38D88A2B3"; NGINX_GPGKEY_PATH=/etc/apt/keyrings/nginx-archive-keyring.gpg; export GNUPGHOME="$(mktemp -d)"; found=''; for NGINX_GPGKEY in $NGINX_GPGKEYS; do for server in hkp://keyserver.ubuntu.com:80 pgp.mit.edu ; do echo "Fetching GPG key $NGINX_GPGKEY from $server"; gpg1 --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; done; test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; done; gpg1 --export "$NGINX_GPGKEYS" > "$NGINX_GPGKEY_PATH" ; rm -rf "$GNUPGHOME"; apt-get remove --purge --auto-remove -y gnupg1 && rm -rf /var/lib/apt/lists/* && dpkgArch="$(dpkg --print-architecture)" && nginxPackages=" nginx=${NGINX_VERSION}-${PKG_RELEASE} nginx-module-xslt=${NGINX_VERSION}-${DYNPKG_RELEASE} nginx-module-geoip=${NGINX_VERSION}-${DYNPKG_RELEASE} nginx-module-image-filter=${NGINX_VERSION}-${DYNPKG_RELEASE} nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${NJS_RELEASE} " && case "$dpkgArch" in amd64|arm64) echo "deb [signed-by=$NGINX_GPGKEY_PATH] https://nginx.org/packages/mainline/debian/ bookworm nginx" >> /etc/apt/sources.list.d/nginx.list && apt-get update ;; *) tempDir="$(mktemp -d)" && chmod 777 "$tempDir" && savedAptMark="$(apt-mark showmanual)" && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y curl devscripts equivs git libxml2-utils lsb-release xsltproc && ( cd "$tempDir" && REVISION="${NGINX_VERSION}-${PKG_RELEASE}" && REVISION=${REVISION%~*} && curl -f -L -O https://github.com/nginx/pkg-oss/archive/${REVISION}.tar.gz && PKGOSSCHECKSUM="973690e64fa47e3704e817a3b08205b9e3f8c0cbe31825d9d62a81c11eb3aa186df015f27fdfd48c8799ffc528e38a9168c592ae665e4835c2d28638ec5f7845 *${REVISION}.tar.gz" && if [ "$(openssl sha512 -r ${REVISION}.tar.gz)" = "$PKGOSSCHECKSUM" ]; then echo "pkg-oss tarball checksum verification succeeded!"; else echo "pkg-oss tarball checksum verification failed!"; exit 1; fi && tar xzvf ${REVISION}.tar.gz && cd pkg-oss-${REVISION} && cd debian && for target in base module-geoip module-image-filter module-njs module-xslt; do make rules-$target; mk-build-deps --install --tool="apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends --yes" debuild-$target/nginx-$NGINX_VERSION/debian/control; done && make base module-geoip module-image-filter module-njs module-xslt ) && apt-mark showmanual | xargs apt-mark auto > /dev/null && { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; } && ls -lAFh "$tempDir" && ( cd "$tempDir" && dpkg-scanpackages . > Packages ) && grep '^Package: ' "$tempDir/Packages" && echo "deb [ trusted=yes ] file://$tempDir ./" > /etc/apt/sources.list.d/temp.list && apt-get -o Acquire::GzipIndexes=false update ;; esac && apt-get install --no-install-recommends --no-install-suggests -y $nginxPackages gettext-base curl && apt-get remove --purge --auto-remove -y && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list && if [ -n "$tempDir" ]; then apt-get purge -y --auto-remove && rm -rf "$tempDir" /etc/apt/sources.list.d/temp.list; fi && ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/nginx/error.log && mkdir /docker-entrypoint.d # buildkit (You can suppress it with --accept-key)
WARN - CIS-DI-0001: Create a user for the container
* Last user should not be root
WARN - DKL-DI-0006: Avoid latest tag
* Avoid 'latest' tag
INFO - CIS-DI-0005: Enable Content trust for Docker
* export DOCKER_CONTENT_TRUST=1 before docker pull/build
INFO - CIS-DI-0006: Add HEALTHCHECK instruction to the container image
* not found HEALTHCHECK statement
INFO - CIS-DI-0008: Confirm safety of setuid/setgid files
* setuid file: urwxr-xr-x usr/bin/passwd
* setuid file: urwxr-xr-x usr/bin/su
* setuid file: urwxr-xr-x usr/bin/umount
* setuid file: urwxr-xr-x usr/bin/chfn
* setgid file: grwxr-xr-x usr/bin/expiry
* setuid file: urwxr-xr-x usr/bin/newgrp
* setuid file: urwxr-xr-x usr/bin/gpasswd
* setgid file: grwxr-xr-x usr/sbin/unix_chkpwd
* setgid file: grwxr-xr-x usr/bin/chage
* setuid file: urwxr-xr-x usr/bin/chsh
* setuid file: urwxr-xr-x usr/bin/mount

Ce qui m’aide beaucoup, c’est que Dockle affiche les recommandations détaillées pour chaque point non conforme. Je peux donc adapter mon Dockerfile rapidement.

Les options utiles de Dockle

Lorsque j’utilise Dockle au quotidien, certaines options me permettent d’adapter l’analyse à mes besoins, surtout en environnement CI/CD. Ces options sont précieuses pour personnaliser le comportement de l’outil et affiner les rapports de sécurité.

Voici celles que j’utilise le plus souvent :

--exit-code

Cette option permet de définir le code de sortie de Dockle si des problèmes sont détectés. Par défaut, Dockle retourne toujours 0, ce qui n’est pas idéal en automatisation.

Par exemple :

Terminal window
dockle --exit-code 1 nginx:latest

Cette commande retournera 1 si une alerte de type WARN ou FATAL est présente. Idéal pour bloquer un pipeline CI/CD en cas de configuration non sécurisée.

--format

Elle me permet de changer le format de sortie, ce qui est utile si je veux exploiter les résultats dans un outil externe (parsing, alerting, etc.).

  • raw (par défaut)
  • json

Exemple en JSON :

Terminal window
dockle --format json nginx:latest

J’intègre souvent ce format dans mes scripts d’analyse post-traitement.

--ignore

Il arrive parfois que certaines règles ne soient pas pertinentes pour mon contexte. Grâce à cette option, je peux ignorer des règles spécifiques :

Terminal window
dockle --ignore CIS-DI-0001,CIS-DI-0006 nginx:latest

Attention à ne pas abuser de cette option. À mon avis, ignorer une règle doit toujours être justifié.

--input-type

Par défaut, Dockle analyse les images locales. Mais je peux aussi lui dire d’utiliser une image à distance, par exemple depuis un registre :

Terminal window
dockle --input-type=registry mon-registre.io/mon-image:tag

--no-color

Si je redirige la sortie dans un fichier ou un autre outil, je désactive les couleurs pour un rendu plus lisible :

Terminal window
dockle --no-color nginx:latest

--timeout

Par défaut, Dockle utilise un timeout de 30 secondes. Pour les grosses images ou les réseaux lents, je peux ajuster cette valeur :

Terminal window
dockle --timeout 60 nginx:latest

Intégration de Dockle dans un pipeline CI/CD

À mon avis, l’un des plus grands avantages de Dockle, c’est sa facilité d’intégration dans un pipeline CI/CD. C’est ce que je recommande toujours : automatiser les vérifications de sécurité dès la construction de l’image, pour éviter les mauvaises surprises plus tard.

Pourquoi intégrer Dockle dans un pipeline ?

L’objectif est simple : empêcher la mise en production d’images non conformes. Grâce à Dockle, je peux valider automatiquement qu’une image respecte les bonnes pratiques avant son déploiement.

Les bénéfices sont clairs :

  • Détection précoce des failles de configuration
  • Automatisation du contrôle qualité
  • Blocage conditionnel si des règles critiques échouent

Exemple avec GitLab CI

Voici un exemple de job dans un fichier .gitlab-ci.yml :

dockle_scan:
stage: test
image: docker:latest
services:
- docker:dind
before_script:
- apk add --no-cache curl
- VERSION=$(curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
- curl -L -o dockle https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit
- chmod +x dockle
script:
- docker build -t mon-image .
- ./dockle --exit-code 1 mon-image

Avec l’option --exit-code 1, le job échoue si une alerte de type WARN ou FATAL est détectée. Cela me permet de forcer les correctifs avant de passer à l’étape suivante.

Le mieux est de construire sa propre image contenant Dockle, pour éviter de télécharger le binaire à chaque fois.

Exemple avec GitHub Actions

Et voici un exemple équivalent pour GitHub Actions :

name: CI Dockle
on: [push]
jobs:
dockle:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Build Docker image
run: docker build -t mon-image .
- name: Install Dockle
run: |
VERSION=$(curl --silent "https://api.github.com/repos/goodwithtech/dockle/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
curl -L -o dockle https://github.com/goodwithtech/dockle/releases/download/v${VERSION}/dockle_${VERSION}_Linux-64bit
chmod +x dockle
- name: Run Dockle
run: ./dockle --exit-code 1 mon-image

Bonnes pratiques

Je préfère toujours :

  • Exécuter Dockle juste après le build
  • Échouer le job sur les erreurs critiques
  • Personnaliser la politique de sécurité avec --ignore si nécessaire

Intégré dans mon CI/CD, Dockle devient un gardien automatique de mes standards de sécurité. Je peux livrer plus sereinement, tout en respectant les exigences de conformité.

Conclusion

Dockle est, à mon avis, un outil à adopter sans hésitation pour toute personne soucieuse de la sécurité de ses images Docker. Simple à installer, facile à intégrer dans un pipeline CI/CD, il m’offre une analyse fine des configurations souvent négligées. C’est un excellent moyen d’automatiser la détection des erreurs courantes et de garantir un niveau de sécurité minimum avant mise en production.

Mais pour aller encore plus loin, je recommande vivement de le combiner à deux autres outils :

  • Hadolint pour analyser la qualité et les bonnes pratiques de vos Dockerfile.
  • Trivy pour détecter les vulnérabilités dans les paquets logiciels et dépendances embarquées dans les images.

À eux trois, Dockle, Hadolint et Trivy me permettent de construire des images à la fois propres, optimisées et sécurisées. Ce trio est, selon moi, le meilleur combo pour un workflow Docker robuste et conforme aux exigences modernes de la sécurité DevOps.

Plus d’infos