Skip to main content

Codefresh + Snyk = livrer rapidement et en toute sécurité

Écrit par
Headshot of Antoine Arlaud

Antoine Arlaud

11 décembre 2018

0 minutes de lecture

Le développement logiciel moderne, c’est écrire du code. Pas construire, pas livrer, mais développer : on code, on fusionne, on compile, on livre. Il est important de tester des deux côtés de la frontière du dépôt, entre le code et la partie automatisée. L’objectif est de tester avant la fusion, afin que les modifications passent sans encombre dans le pipeline.

Les pipelines ne sont pas là pour permettre aux développeurs de tester leurs modifications pour la première fois. Ils servent à bloquer la livraison d’une nouvelle version si notre code ne répond pas aux critères requis. C’est comme une dernière liste de vérification pendant que la fusée est encore sur la rampe de lancement. Dans l’idéal, il est même déjà un peu trop tard si nous devons corriger des problèmes pendant l’exécution d’un pipeline. Mieux vaut le faire pendant le développement et/ou la fusion. Cependant, le monde n’étant pas toujours idéal, nous devrions tout de même nous efforcer, en règle générale, de corriger les problèmes pendant la phase de développement.

Pour y parvenir, testez plus tôt afin d’obtenir des retours le plus en amont possible, par exemple sur votre machine ou dans votre dépôt de code. Bien sûr, vous devrez tout de même commencer par créer ce pipeline et y intégrer les tests nécessaires. C’est là que Codefresh intervient. La plateforme vous permet de créer des pipelines automatisés pour livrer vos applications sous forme de conteneurs et de déploiements Kubernetes.

Ces tests DOIVENT inclure la sécurité. C’est indispensable. Si vous n’en êtes pas convaincu, arrêtez la lecture et allez en parler à votre équipe, à un collègue, à vos pairs ou à un groupe de discussion, voire à nous. Nous vous expliquerons pourquoi c’est important… C’est là que Snyk intervient.

Nous allons consacrer 5 à 10 minutes à créer ce pipeline dans Codefresh et à y intégrer des tests de sécurité avec Snyk. Les tests seront rapides et efficaces : nous pourrons ainsi reprendre le codage et, à terme, livrer des fonctionnalités. Codefresh et Snyk proposent tous deux des offres gratuites, vous pouvez donc suivre les étapes sans frais. J’ai également animé un webinaire avec l’équipe de Codefresh. Si vous préférez regarder la vidéo, vous pouvez la retrouver ici.

Nous allons créer une application Node d’exemple et la livrer dans un conteneur Docker que nous publierons sur Docker Hub. Un autre pipeline se déclenchera ensuite pour déployer le résultat sous forme d’application Kubernetes. Codefresh détectera les modifications fusionnées dans notre dépôt, créera les images Docker, puis lancera les tests Snyk pour déterminer si le résultat peut être livré en toute sécurité.

Commençons par un bref rappel sur les applications et les conteneurs. Le schéma ci-dessous illustre l’architecture type d’une application exécutée sur une infrastructure de conteneurs.

Le pipeline récupère le code source de mon application dans mon dépôt GitHub, le transforme en conteneur Docker, puis vérifie la sécurité des dépendances de l’application et du système d’exploitation avant de publier le conteneur sur Docker Hub. Si aucune vulnérabilité n’est détectée, le pipeline se poursuit sans problème.

Notre pipeline applicatif présente les étapes, du commit et de la compilation de l’application à l’analyse des dépendances, à la création de l’image Docker, à son analyse et à son envoi vers Docker Hub

Créons maintenant ce pipeline pour de vrai !

1. Créez un compte Codefresh et un compte Snyk.io.

2. Ajoutez un dépôt dans Codefresh.

Tableau de bord des dépôts Codefresh affichant les filtres Tous, Privés et Publics, ainsi qu’un panneau Ajouter un nouveau dépôt.

Pour cette démonstration, nous allons utiliser le dépôt https://github.com/snyk-playground/codefresh-pipeline-snyk-app-docker-scan.

Écran de sélection du dépôt indiquant l’étape 1 sur 4, le dépôt snyk-playground/code et la branche master sélectionnée pour la première compilation

3. Sélectionnez ensuite Start from template comme méthode de compilation.

Écran de configuration de Codefresh présentant trois options de méthode de compilation du dépôt : Codefresh.yml, Dockerfile et modèle, avec Dockerfile sélectionné.

Nous utilisons ici une application NodeJS. Sélectionnons-la, puis cliquons sur Suivant.

IDE Java affichant une trace de pile du débogueur et le code source de la méthode getSubQuery, avec un panneau d’inspection des variables ouvert.

Pour l’instant, nous allons utiliser le modèle standard. N’hésitez pas à l’adapter à vos besoins.

Aperçu de la configuration montrant un Dockerfile modifiable avec la configuration de Node.js, l’installation des dépendances, la copie de l’application et le bouton Create

Très bien, notre nouveau dépôt est ajouté. Passons maintenant à la définition du pipeline.

Interface de développement Java comparant deux fichiers Hello.java, avec les différences dans la méthode main et l’historique Git affiché en dessous

4. Créez le pipeline du dépôt en cliquant sur Create pipeline.

Commençons par définir quelques variables d’environnement requises. Veillons à chiffrer tous les secrets. Ajoutez une variable nommée « SNYK_TOKEN ».

Écran de configuration du pipeline affichant les variables d’environnement PORT=8080 et une variable SNYK_TOKEN chiffrée.

Vous trouverez sa valeur sur https://app.snyk.io/account.

Page des paramètres du compte affichant un champ de jeton API masqué et le bouton Afficher mis en évidence

Pendant que vous y êtes, ajoutez une autre variable nommée SNYK_ORG, dont la valeur correspond à la dernière partie de votre URL https://app.snyk.io/org/. Dans mon cas, il s’agit de aarlaud-snyk-demo

URL du navigateur affichant app.snyk.io/org/aarlaud-snyk-demo/

Voilà pour Snyk.

Nous avons maintenant besoin de quelques variables d’environnement supplémentaires pour récupérer l’image depuis le registre Codefresh et publier l’image finale sur Docker Hub.

Pour que Codefresh puisse accéder à notre registre d’images privé, ajoutez les variables suivantes (consultez https://codefresh.io/docs/docs/docker-registries/codefresh-registry/#generate-cfcr-login-token pour plus de détails) :

  • CF_USER_NAME - mon nom d’utilisateur Codefresh (par exemple, aarlaud dans mon cas)

  • CFCR_ACCOUNT - dans mon cas, il s’agit du même nom que mon nom d’utilisateur : aarlaud

  • CFCR_LOGIN_TOKEN - générez un jeton sur https://g.codefresh.io/user/settings et chiffrez-le !

Pour l’intégration Docker Hub, nous allons enregistrer le nom de l’image que nous voulons publier sur Docker Hub dans la variable suivante :

IMAGE_NAME - par exemple, dans mon cas : aarlaudsnyk/trainingapp

Votre ensemble de variables devrait ressembler à ceci :

Panneau des paramètres des variables d’environnement affichant les variables configurées pour le port, Snyk, Cloud Foundry et le nom de l’image, certaines valeurs étant chiffrées

Enfin, nous devons configurer Docker dans la section Integrations de Codefresh :

Écran des paramètres d’intégration affichant les options Git, Docker Registry et Kubernetes avec des boutons Configurer ; la section Integrations est mise en évidence dans la barre latérale.

Vous devez disposer d’un compte Docker Hub (https://hub.docker.com/). Créez-en un si ce n’est pas déjà fait, puis configurez l’intégration du registre Docker :

Vue Snyk du rapport de vulnérabilités présentant les problèmes liés aux dépendances, les packages et les correctifs disponibles dans un tableau

Très bien, nous sommes prêts à continuer ! Si vous consultez vos déclencheurs, vous verrez que chaque commit lancera une compilation. Comme nous avons créé ce pipeline à partir de la branche master, seuls les commits sur master déclencheront la compilation. C’est suffisant pour le moment, et il est facile de modifier ou de dupliquer le pipeline pour d’autres branches et environnements.

Interface des déclencheurs affichant un déclencheur Git pour le dépôt snyk-playground/codefresh-pipeline-snyk-app-do...

En examinant le workflow, nous reconnaissons le modèle Docker vu précédemment. À terme, il serait peut-être préférable de le déplacer dans un Dockerfile.

Formulaire de configuration du workflow affichant un Dockerfile de modèle Codefresh pour Node.js, avec le nom de l’image et les commandes Docker.

Essayons maintenant de lancer une compilation pour vérifier que tout fonctionne comme prévu avant d’aller plus loin.

Boîte de dialogue permettant de sélectionner la branche principale et le pipeline avant de créer codefresh-pipeline-snyk-app-docker-scan, avec le bouton Build mis en évidence

Vous verrez la compilation démarrer :

Tableau de bord CVSS de Snyk affichant un score élevé de 8,2 et des détails sur les vulnérabilités de NVD et Red Hat, notamment un impact élevé sur l’intégrité et la disponibilité.

Et voilà, mon application est compilée.

Éditeur de code affichant une configuration de mise en page JSON avec un élément UIImage sélectionné et ses propriétés de positionnement.

Codefresh place automatiquement cette image dans votre registre Docker privé associé à votre compte Codefresh. Dans la section Images, je vois l’image Docker que je viens de créer :

Tableau de bord des images affichant un filtre par étiquette et un enregistrement d’image de dépôt avec les colonnes branche, commit, date, étiquette et SHA

Avant de publier simplement cette image sur Docker Hub, je veux également m’assurer qu’elle ne contient aucune vulnérabilité de sécurité.

5. Revenons au pipeline et ajoutons une commande snyk test pour vérifier si les dépendances présentent des vulnérabilités de sécurité.

Nous allons d’abord installer Snyk, puis l’exécuter avec des commandes très simples, configurées pour faire échouer le pipeline en cas de problème de gravité élevée. Pour l’instant, je ne veux pas bloquer la compilation pour des problèmes de gravité faible ou moyenne, le temps de mieux maîtriser mon workflow.

> npm install -g snyk
> snyk test --severity-threshold=high
Section sur les tests unitaires montrant les commandes du terminal pour installer Snyk globalement et exécuter les tests avec un seuil de gravité élevé.

Cliquez sur Enregistrer, puis relancez la compilation. Vous verrez une étape d’extraction dans le pipeline, intitulée Running Unit Tests. Elle échouera probablement en raison de certains problèmes. Nous les corrigerons plus tard. Analysons maintenant l’image Docker elle-même pour détecter les problèmes liés au système d’exploitation de mon application.

Lorsque Codefresh compile l’application, il publie l’image dans notre registre privé, puis la récupère pour exécuter les tests unitaires. Nous allons répéter cette opération pour lancer un deuxième test Snyk, cette fois sur l’image Docker.

Pour ce faire, nous utiliserons une composition Codefresh. Consultez la documentation pour plus de détails. Nous allons toutefois passer en mode YAML pour disposer de davantage de possibilités.

Bouton bascule avec les options BASIC et YAML, YAML étant sélectionné

En mode YAML, commençons par ajouter ces trois lignes juste après « version: ‘1.0’ » : stages:

-scan
-promote

Cette modification est purement cosmétique : elle crée une section en forme de compartiment dans l’interface. Modifions légèrement la section RunningUnitTests existante pour utiliser la section SnykAppScan. Outre le changement de titre, nous avons ajouté une section stage pour placer cette étape dans le bon compartiment de l’interface. Nous transmettons également les variables d’environnement plus directement et simplifions quelques éléments.

SnykAppScan:
title: Snyk Test Application Dependencies
stage: scan
image: '${{BuildingDockerImage}}'
working_directory: IMAGE_WORK_DIR
environment:
- SNYK_TOKEN=${{SNYK_TOKEN}}
- SNYK_ORG=${{SNYK_ORG}}
commands:
- npm install -g snyk
- snyk test --severity-threshold=high
on_success:
metadata:
set:
- '${{BuildingDockerImage.imageId}}':
- CF_QUALITY: true
on_fail:
metadata:
set:
- '${{BuildingDockerImage.imageId}}':
- CF_QUALITY: false

Ajoutons maintenant une section SnykScanImage, cette fois pour analyser notre image Docker. Le stage est également scan : il se trouve donc dans le même compartiment que l’étape d’analyse des dépendances de l’application. Comme l’indique la documentation sur les compositions, vous pouvez exécuter plusieurs services pour lancer vos tests.

Dans notre cas, BuildingDockerImage correspond à l’image produite lors de l’étape de compilation. Nous voulons tester cette image de l’extérieur. Nous composons donc notre test avec un service d’analyse qui exécute une autre image que j’ai créée précédemment : aarlaudsnyk/snyk-container-scan-docker. Cette image rassemble simplement les éléments nécessaires à Snyk pour tester une image Docker. Vous trouverez le code source ici :

SnykScanImage:
title: Snyk Test Docker OS Dependencies
stage: scan
type: composition
composition:
version: '2'
services:
targetimage:
image: ${{BuildingDockerImage}} # Must be the Docker build step name
command: sh -c "exit 0"
labels:
build.image.id: ${{CF_BUILD_ID}} # Provides a lookup for the composition
composition_candidates:
scan_service:
image: aarlaudsnyk/snyk-container-scan-docker
command: python snyk-cli.py "${{IMAGE_NAME}}:${{CF_BRANCH_TAG_NORMALIZED}}"
environment:
- SNYK_TOKEN=${{SNYK_TOKEN}}
- SNYK_ORG=${{SNYK_ORG}}
- CFCR_ACCOUNT=${{CFCR_ACCOUNT}}
- CF_USER_NAME=${{CF_USER_NAME}}
- CFCR_LOGIN_TOKEN=${{CFCR_LOGIN_TOKEN}}
depends_on:
- targetimage
volumes: # Volumes required to run DIND
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker:/var/lib/docker
add_flow_volume_to_composition: true
on_success: # Execute only once the step succeeded
metadata: # Declare the metadata attribute
set: # Specify the set operation
- ${{BuildingDockerImage.imageId}}: # Select any number of target images
- SECURITY_SCAN: true

on_fail: # Execute only once the step failed
metadata: # Declare the metadata attribute
set: # Specify the set operation
- ${{BuildingDockerImage.imageId}}: # Select any number of target images
- SECURITY_SCAN: false

La partie intéressante du fichier YAML ci-dessus est la suivante :

image: aarlaudsnyk/snyk-container-scan-docker
command: python snyk-cli.py "${{IMAGE_NAME}}:${{CF_BRANCH_TAG_NORMALIZED}}"

Nous utilisons cette image pour exécuter une commande Python qui fait principalement deux choses :

  • Récupérer l’image et la tester localement

  • Exécuter « snyk test --docker »

Cette image est conçue pour récupérer l’image depuis le registre Codefresh si les variables d’environnement suivantes sont définies :

  • CFCR_ACCOUNT

  • CF_USER_NAME

  • CFCR_LOGIN_TOKEN

Cela nous permet de tester l’image qui vient d’être créée. Sinon, l’image sera récupérée par défaut depuis Docker Hub.

Enfin, ajoutons à la fin la publication sur le registre Docker Hub, afin de publier effectivement cette image si les tests réussissent :

PushingToDockerRegistry:
title: Pushing to Docker Registry
stage: promote
type: push
candidate: '${{BuildingDockerImage}}'
tag: '${{CF_BRANCH_TAG_NORMALIZED}}'
registry: aarlaudsnyk

Rien de compliqué : Codefresh facilite la publication sur Docker Hub, à condition que l’intégration ait été configurée (voir plus haut). Notez que le stage promote permet de distinguer cette étape des tests d’analyse.

Le tout devrait ressembler à ceci :

version: '1.0'
stages:
- scan
- promote
steps:
BuildingDockerImage:
title: Building Docker Image
type: build
image_name: ${{IMAGE_NAME}}
working_directory: ./
tag: '${{CF_BRANCH_TAG_NORMALIZED}}'
dockerfile:
content: |-
FROM node:8.0-alpine AS builder
WORKDIR /app
COPY package.json /app
# Creating tar of productions dependencies
RUN npm install --production && cp -rp ./node_modules /tmp/node_modules
# Installing all dependencies
RUN npm install
# Copying application code
COPY . /app
SnykAppScan:
title: Snyk Test Application Dependencies
stage: scan
image: '${{BuildingDockerImage}}'
working_directory: IMAGE_WORK_DIR
environment:
- SNYK_TOKEN=${{SNYK_TOKEN}}
- SNYK_ORG=${{SNYK_ORG}}
commands:
- npm install -g snyk
- snyk test --severity-threshold=high
on_success:
metadata:
set:
- '${{BuildingDockerImage.imageId}}':
- CF_QUALITY: true
on_fail:
metadata:
set:
- '${{BuildingDockerImage.imageId}}':
- CF_QUALITY: false

SnykScanImage:
title: Snyk Test Docker OS Dependencies
stage: scan
type: composition
composition:
version: '2'
services:
targetimage:
image: ${{BuildingDockerImage}} # Must be the Docker build step name
command: sh -c "exit 0"
labels:
build.image.id: ${{CF_BUILD_ID}} # Provides a lookup for the composition
composition_candidates:
scan_service:
image: aarlaudsnyk/snyk-container-scan-docker
command: python snyk-cli.py "${{IMAGE_NAME}}:${{CF_BRANCH_TAG_NORMALIZED}}"
environment:
- SNYK_TOKEN=${{SNYK_TOKEN}}
- SNYK_ORG=${{SNYK_ORG}}
- CFCR_ACCOUNT=${{CFCR_ACCOUNT}}
- CF_USER_NAME=${{CF_USER_NAME}}
- CFCR_LOGIN_TOKEN=${{CFCR_LOGIN_TOKEN}}
depends_on:
- targetimage
volumes: # Volumes required to run DIND
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker:/var/lib/docker
add_flow_volume_to_composition: true
on_success: # Execute only once the step succeeded
metadata: # Declare the metadata attribute
set: # Specify the set operation
- ${{BuildingDockerImage.imageId}}: # Select any number of target images
- SECURITY_SCAN: true

on_fail: # Execute only once the step failed
metadata: # Declare the metadata attribute
set: # Specify the set operation
- ${{BuildingDockerImage.imageId}}: # Select any number of target images
- SECURITY_SCAN: false

PushingToDockerRegistry:
title: Pushing to Docker Registry
stage: promote
type: push
candidate: '${{BuildingDockerImage}}'
tag: '${{CF_BRANCH_TAG_NORMALIZED}}'
registry: aarlaudsnyk

6. Essayons de lancer une compilation pour obtenir une première référence. Notre organisation semble en très bon état :

IDE Angular affichant un fichier de test app.component.spec.ts, l’explorateur de projet et le panneau d’accueil Terminal+ pour un projet Angular 2 en TypeScript.

Après un instant, nous obtenons ceci :

Pipeline de build Codefresh affichant l’échec d’une analyse des dépendances de l’application par Snyk et la sortie du terminal signalant un chemin vulnérable.

Oh là là, notre application présente quelques problèmes. Le pipeline s’est arrêté en toute sécurité pour éviter de livrer un produit comportant des problèmes de sécurité. Corrigeons-les en suivant les étapes de correction indiquées dans le résultat. Il suffit de mettre à niveau le package qs vers la version 6.0.4 dans package.json.

Relançons la compilation.

Tableau de bord du pipeline CI affichant les étapes par défaut, d’analyse et de promotion, avec les tests de dépendances Snyk terminés et aucun chemin vulnérable détecté.

La vulnérabilité de qs est corrigée, super ! Mais il y a maintenant un problème avec les dépendances du système d’exploitation dans notre image Docker.

Éditeur XML affichant une facture avec les détails de facturation et de livraison, les lignes de produits, les totaux, les commentaires et un panneau de plan flottant.

Les recommandations de correction indiquent qu’une mise à niveau de l’image serait une bonne solution (consultez la section Docker sur snyk.io/docs). Passons donc à node:10-alpine et réessayons.

Capture d’écran montrant le code source PlantUML à côté de la disposition mémoire générée et des diagrammes de cas d’utilisation.

Enregistrer => Compiler => Faire des pompes pendant la compilation !

Pipeline Codefresh terminé montrant le clonage du dépôt, la création d’une image Docker, les analyses des dépendances par Snyk et l’envoi vers un registre Docker

Super ! Nous avons maintenant une référence propre et un pipeline entièrement fonctionnel qui livre notre application et notre conteneur sur Docker Hub.

Nous pouvons maintenant reprendre le codage. Veillons à exécuter snyk test sur nos modifications avant de les fusionner et/ou à les tester avec l’intégration GitHub PR de Snyk. Les modifications seront ensuite livrées automatiquement. Et en bonus, voici la dernière nouveauté !

Utilisez snyk monitor pour surveiller vos dépendances au fil du temps. Personne n’a envie de surveiller ses projets en permanence. En exécutant snyk monitor, Snyk nous avertira automatiquement si une nouvelle vulnérabilité est divulguée pour l’une des dépendances du projet ou de l’image Docker. Il suffit d’ajouter snyk monitor après la section snyk test.

Éditeur de configuration YAML affichant YAML inline sélectionné, un bouton Importer depuis un fichier et la commande « snyk monitor » mise en évidence.

L’URL de l’instantané de surveillance apparaîtra ensuite dans le résultat :

Sortie du terminal affichant l’URL d’un instantané de surveillance de l’application et des notifications concernant de nouvelles vulnérabilités dans les dépendances.

L’étape Docker s’exécutera automatiquement si snyk test réussit (c’est-à-dire si aucun problème connu n’est détecté). Des liens vers les instantanés de surveillance sont également fournis.

Sortie du terminal montrant Snyk surveillant une application de formation et informant les utilisateurs de la divulgation de nouvelles vulnérabilités dans les dépendances

Vous pouvez également consulter les projets surveillés dans l’interface Snyk de votre organisation Snyk :

Tableau de bord Snyk Projects affichant deux dépôts avec le nombre de vulnérabilités et des menus déroulants « Tester chaque jour »

Consultez le pipeline Codefresh en cliquant sur le badge dans le dépôt (https://github.com/snyk-playground/codefresh-pipeline-snyk-app-docker-scan).

Et voilà, c’est tout ! Restez en sécurité !

Lancez-vous dans les compétitions Capture The Flag

Apprenez à résoudre des défis Capture The Flag en regardant à la demande notre atelier virtuel d’initiation.

Publié dans:

Lire la suite

feature insights context
Blog

Les attaques autonomes sont déjà là. La défense doit suivre leur rythme.

Les attaquants autonomes réduisent la fenêtre de défense. Découvrez comment la découverte, la correction, la validation et la prévention continues peuvent aider les équipes de sécurité à suivre le rythme.

Blog

Evo ADS : la gouvernance des comportements des agents est disponible : maîtrisez l’utilisation de MCP

La gouvernance des comportements des agents Evo ADS est désormais disponible, avec MCP Governance en première étape. Découvrez, approuvez, surveillez, consignez et bloquez l’utilisation des serveurs MCP par les principaux agents de programmation IA.

illustration hero ai
Blog

Qu’est-ce que l’AppSec agentique ?

Découvrez comment l’AppSec agentique s’appuie sur des agents IA ancrés dans la réalité, aux missions délimitées et vérifiés de manière indépendante pour gérer le cycle de sécurité des applications.