Comment scanner les vulnérabilités d’une image Docker dans un pipeline Gitlab avec Cyberwatch ?

Comment scanner une image Docker ?
Amel KACHETEL
juin 15, 2022

Cyberwatch permet de scanner les vulnérabilités d’une image Docker. Ce processus peut être très pratique lors d’une utilisation dans un processus de CI / CD, notamment un pipeline Gitlab, en particulier dans le cadre d’une démarche DevSecOps.

Dans cet article, nous allons voir :

  1. Comment créer une image Docker à partir d’un pipeline Gitlab ;
  2. Comment scanner ces images dans Cyberwatch.

Préambule : pourquoi scanner les vulnérabilités d’une image Docker dans un pipeline Gitlab DevSecOps ?

Qu’est-ce qu’un processus de CI / CD ?

Les équipes de développement informatique utilisent très souvent un logiciel de forge pour collaborer. Un logiciel de forge permet d’ajouter une surcouche collaborative plus agréable autour d’un système de gestion des versions comme Git ou Mercurial. Les logiciels de forge les plus communs proposent ainsi des fonctionnalités de suivi de bogues, d’intégration continue, et de livraison continue.

Ces deux derniers termes d’intégration et livraison continue sont plus souvent utilisés sous leurs acronymes anglais de CI / CD pour Continuous Integration et Continuous Delivery.

Un processus de CI / CD est donc un système d’intégration continue et de livraison continue, c’est-à-dire un dispositif où chaque nouvelle ligne de code d’un développeur est poussée dans un référentiel partagé, puisse déclenche des tests de non-régression et de validation fonctionnelle (partie intégration continue ou CI), ainsi que des étapes de déploiement automatique sur différents environnements (partie livraison continue ou CD).

Un processus de CI / CD se met en œuvre sous forme d’étapes liées les unes aux autres, afin de créer ce que l’on appelle un pipeline.

Les processus de CI / CD sont très utilisés dans les démarches dites « DevOps », où les étapes de déploiement sont automatisées à l’aide de morceaux de code.

Dans cet article, nous nous intéressons au cas des pipelines de Gitlab, un logiciel libre de forge très utilisé, notamment pour sa capacité à être déployé en mode « auto-hébergé ».

Pourquoi scanner les vulnérabilités d’une image Docker ?

Un processus de CI / CD peut produire des livrables nommés artefacts logiciels. Un exemple classique est la production d’images Docker, construites par le pipeline CI / CD.

La production automatisée d’images Docker permet par exemple d’avoir une image Docker pour chaque nouvelle modification apportée au logiciel développé par une équipe, et donc de plus facilement déployer et tester ces modifications dans des environnements dédiés.

Or, une image Docker embarque des composants qui font l’objet de vulnérabilités, au moins de vulnérabilités issues des bases CVE.

Ces composants potentiellement vulnérables sont par exemple les paquets liés au socle système de l’image (par exemple les paquets DPKG installés sur une image Docker Debian), ou les binaires déployés au sein de cette image, ou encore les bibliothèques logicielles utilisées par les différents langages de programmation (modules PIP, GEM, NPM, PHAR…).

Toute image Docker mérite ainsi d’être régulièrement scannée à la recherche de vulnérabilités, afin de déterminer les risques présents et de prendre les meilleures décisions ensuite.

Lorsque l’on ajoute des étapes de sécurité dans le cadre d’une démarche DevOps, on parle alors de « DevSecOps » pour préciser que les étapes de vérification de sécurité informatique sont alors aussi vérifiées automatiquement à chaque modification d’un projet informatique.

Pourquoi scanner une image Docker dans un processus de CI / CD ?

Un processus de CI / CD a notamment pour but d’améliorer la qualité des logiciels développés, en lançant régulièrement des tests fonctionnels et des tests de sécurité.

Une étape très connue d’une CI / CD est ainsi l’étape d’analyse statique de code, ou SAST (Static Application Security Testing) qui permet d’identifier des erreurs potentielles introduites dans le code et qui pourraient entraîner des injections SQL ou XSS.

Une autre étape de plus en plus utilisée dans un processus de CI / CD est l’étape du scan de vulnérabilités, où les images Docker produites au cours du processus vont ensuite être scannées afin d’autoriser ou de bloquer leur mise en production.

Cela permet d’identifier très tôt la présence de vulnérabilités CVE dans les composants déployés, et de les corriger avant qu’elles ne puissent impacter les environnements des clients.

1) Comment scanner une image Docker avec Cyberwatch, à partir d’un pipeline Gitlab ?

1.a) Prérequis

Pour connecter Cyberwatch à un pipeline Gitlab, et scanner les images Docker associées, nous aurons besoin des éléments suivants :

  • Un moteur d’exécution Docker (c’est-à-dire une machine avec Docker Engine installé) ;
  • Des images Docker à récupérer depuis un pipeline Gitlab.

Le pipeline Gitlab pilotera Cyberwatch par API, pour indiquer une image à scanner. Cyberwatch analysera cette image à partir du moteur d’exécution Docker, et enverra les résultats au pipeline Gitlab via le format Junit-XML.

1.b) Configurer le moteur d’exécution Docker pour le rendre accessible à Cyberwatch

Tout d’abord, nous allons configurer Docker pour autoriser les connexions et les ordres envoyés par Cyberwatch.

Pour que ces éléments se fassent par une communication sécurisée, nous aurons besoin des éléments suivants :

  • Une autorité de certification, avec son certificat ;
  • Un certificat client signé par l’autorité de certification ;
  • Une clé privée associée au certificat client.
Générer le certificat de l’autorité de certification

Afin de générer une autorité de certification, et son certificat, nous allons lancer les lignes de commande suivantes.

openssl req -new -newkey rsa:4096 -nodes -sha256 -keyout cakey.pem -out cacert.pem \
-x509 -days 730 -subj '/CN=Docker CA for Cyberwatch'
Générer le certificat client et la clé privée

Pour générer la clé privée, nous allons saisir les lignes de commande suivantes :

openssl genrsa -out dockerdkey.pem 4096

Ensuite, pour générer le certificat du client, nous utiliserons les lignes ci-dessous, en remplaçant <IP> par l’adresse IP de la machine Docker :

openssl req -new -key dockerdkey.pem -sha256 -out dockerdcsr.pem -subj '/CN=Docker daemon certificate for Cyberwatch'

openssl x509 -req -in dockerdcsr.pem -CA cacert.pem -CAkey cakey.pem -CAcreateserial -sha256 -out dockerdcert.pem \
 -days 730 -extfile <(echo "subjectAltName = IP:<IP>" ; echo 'extendedKeyUsage = serverAuth')
Configurer le service DockerD pour utiliser les certificats générés

Une fois les certificats générés, il nous reste à configurer DockerD pour utiliser les certificats ainsi créés. Pour cela, nous allons modifier le fichier /etc/docker/daemon.json en lui ajoutant les éléments suivants :

{
    "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"],
    "tls": true,
    "tlsverify": true,
    "tlscacert": "$PWD/cacert.pem",
    "tlscert": "$PWD/dockerdcert.pem",
	  "tlskey": "$PWD/dockerdkey.pem"
}

Il faut ensuite redémarrer Docker pour que la configuration soit prise en compte, avec les commandes ci-après :

systemctl daemon-reload
systemctl restart docker

1) Comment construire une image Docker dans un pipeline Gitlab ?

Nous utiliserons ici Gitlab Container Registry, présent de base dans Gitlab depuis la version 8.8, pour stocker nos imagse.

Gitlab Container Registry vous permet de tester, construire, et déployer vos projets à partir d’une image Docker directement créée dans Gitlab.

Pour la démonstration, nous pouvons utiliser un fichier Dockerfile très simple, basé sur Nginx :

FROM nginx:alpine

Pour pousser cette image dans le registre Gitlab, via le pipeline, nous utilisons le fichier .gitlab-ci.yml ci-dessous (en remplaçant <group>, <project>, et <image> par les paramètres adaptés à votre projet Gitlab) :

stages:
    - build

docker-push:
  image: docker:latest
  stage: build
  services:
    - docker:dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  script:
    - docker build --pull -t $CI_REGISTRY/<group>/<project>/<image>:latest .
    - docker push $CI_REGISTRY/<group>/<project>/<image>:latest

Cette configuration permet de se connecter au Gitlab Container Registry, de construire une image Docker à partir du Dockerfile précédent, et de la pousser sur le registre.

2) Comment scanner une image Docker avec Cyberwatch en ligne de commande ?

2.a) Ajouter une image Docker dans Cyberwatch

Dans l’interface Cyberwatch, créer un identifiant enregistré de type « Moteur d’exécution Docker », en renseignant l’URL sous le format « tcp://<IP_MOTEUR_DOCKER>:2376, puis fournir le certificat de l’autorité de certification, ainsi que le certificat client et sa clé privée.

Créer ensuite un deuxième identifiant, de type « Registre Docker », et renseigner l’URL du registre Gitlab, avec vos identifiants.

Vous pouvez ensuite créer un nouvel actif de type Image Docker, en renseignant les identifiants précédents, et le nom de l’image que vous souhaitez analyser (<group>/<project>/<image>:latest).

2.b) Utiliser la Cyberwatch CLI pour déclencher des scans d’images Docker

La Cyberwatch CLI vous permet de déclencher des actions en ligne de commande (CLI est l’acronyme de Command Line Interface). La Cyberwatch CLI permet ainsi de créer, mettre à jour, et scanner des images Docker depuis des appels simples à construire en lignes de commande. La syntaxe de la Cyberwatch CLI est la suivante :

cyberwatch-cli [RESSOURCE] [ACTION]

Dans le cas de la gestion des images Docker, nous utiliserons :

  • RESSOURCE : docker-image
  • ACTION : list, create, update, ou scan

La documentation complète de la Cyberwatch CLI est disponible sur https://github.com/Cyberwatch/cyberwatch_api_toolbox/blob/master/docs/cli.md.

La Cyberwatch CLI peut alors être insérée dans les commandes du pipeline Gitlab afin de déclencher des scans à la volée.

Lister toutes les images Docker avec Cyberwatch CLI

La commande suivante permet de lister toutes les images Docker présentes sur votre instance Cyberwatch :

cyberwatch-cli docker-image list

Scanner une image Docker avec Cyberwatch CLI

L’approche recommandée pour scanner une image Docker avec Cyberwatch CLI consiste à dupliquer une image Docker déjà présente sur l’instance Cyberwatch, et de spécifier uniquement les changements à apporter, par exemple à changer les tags à scanner.

La commande ci-dessous permet par exemple de scanner une image Docker, à partir des paramètres de l’image d’ID 4, et de changer son tag à latest.

cyberwatch-cli docker-image create --from-image 4 --tag latest

Il est aussi possible de donner tous les paramètres manuellement pour les personnes qui souhaitent un contrôle plus fin de l’ensemble du processus. Il faut alors préciser le nom de l’image, le tag, son ID de registre, son ID de moteur Docker, et son ID de scanner.

La commande ci-dessous va par exemple scanner l’image Ubuntu avec le tag latest prise sur le registre d’ID 7, en lançant le scan via le moteur Docker d’ID 3, et en déclenchant le tout depuis le scanner Cyberwatch d’ID 1.

cyberwatch-cli docker-image create --name ubuntu --tag latest --registry-id 7 --engine-id 3 --node-id 1

Mettre à jour une image Docker avec Cyberwatch CLI

Pour modifier une image Docker, il faut spécifier son identifiant ainsi que les paramètres à modifier. La ligne de commande ci-dessous modifie l’image Docker scannée d’ID 4, en changeant le nom de l’image et le tag ciblés.

cyberwatch-cli docker-image update 4 --name ubuntu --tag latest

Relancer le scan d’une image Docker avec Cyberwatch CLI

Pour relancer le scan d’une image, il suffit de spécifier son ID Cyberwatch.

cyberwatch-cli docker-image scan 4

Le paramètre wait permet également d’attendre la fin du scan avant de vous rendre la main. Ceci est fort utile pour une approche CI / CD.

cyberwatch-cli docker-image scan 4 --wait

Récupérer les vulnérabilités d’une image avec Cyberwatch CLI

Vous pouvez récupérer la liste des vulnérabilités associées à une image Docker en utilisant la commande suivante (remplacer IMAGE_ID par l’ID de l’image ciblée) :

cyberwatch-cli docker-image show IMAGE_ID vulnerabilities

Par défaut, les résultats sont obtenus au format texte. Vous pouvez aussi demander à Cyberwatch de donner tous les résultats au format Junit-XML afin d’afficher les CVE directement dans Gitlab.

cyberwatch-cli docker-image show IMAGE_ID vulnerabilities --format junit-xml

3) Scanner les images Docker automatiquement dans un pipeline Gitlab à l’aide de la Cyberwatch CLI

Nous pouvons maintenant assembler les éléments vus précédemment pour déclencher des scans d’images Docker à l’aide de Cyberwatch CLI, directement depuis un pipeline Gitlab.

Il suffit pour cela de créer une étape dans le pipeline Gitlab de votre choix, pour déclencher un scan des images chaque fois que nécessaire. Un extrait de fichier .gitlab-ci.yml figure ci-après :

docker-scan-image:
  stage: tests
  image:
    name: <gitlab_url>/<projet>/<nom_image>:latest
    entrypoint: [""]
  tags:
    - security-scans
  only:
    refs:
      - schedules
  script:
    - cyberwatch-cli docker-image scan $IMAGE_ID --wait
    - cyberwatch-cli docker-image show vulnerabilities $IMAGE_ID --format junit-xml | tee report.xml
  artifacts: *report_artifacts

Cet extrait, à adapter à vos besoins, permet de déclencher un scan de vulnérabilités sur une image Docker depuis un Scheduled Pipeline.

Les résultats des scans apparaissent alors dans Gitlab, et peuvent déclencher le blocage du pipeline si vous ne souhaitez aucune CVE, en fonction de vos réglages.

Intégrez Cyberwatch dans votre chaîne d’intégration et de livraison continue, et scannez les vulnérabilités de vos images Docker

Notre plateforme Cyberwatch vous permet de scanner les vulnérabilités et de contrôler la conformité de vos actifs, en continu, y compris dans un pipeline de CI/CD.

Demandez une démonstration via notre formulaire et découvrez toutes les fonctionnalités de notre logiciel.

Vous avez des questions ?

Vous souhaitez une démonstration ?

Contactez-nous et nos experts reviendront vers vous sous 24h.

Votre demande