Outils en ligne de commande pour les conteneurs : utiliser Snyk avec Buildah, Podman et Skopeo
9 décembre 2020
0 minutes de lectureÀ mesure que l’écosystème des conteneurs a mûri, les options ne manquent pas, tant pour les logiciels que nous utilisons que pour la façon dont nous les assemblons.
Parmi ces options, on trouve l’association de Buildah, Podman et Skopeo, trois outils en ligne de commande open source issus de l’écosystème RedHat. Comme son nom l’indique, Buildah offre un large éventail de fonctionnalités pour créer des conteneurs et des images conformes à OCI. Podman permet de gérer et d’exécuter des conteneurs OCI, tandis que Skopeo est un outil conçu pour interagir avec les registres de conteneurs.
Dans cet article, nous verrons comment les normes ouvertes permettent à Snyk d’analyser les conteneurs avec toutes ces technologies.
Commençons par Skopeo. Cet outil en ligne de commande permet de transférer des images de conteneurs entre différents dépôts et peut également les enregistrer localement. Skopeo peut générer des images au format d’archive Docker ou OCI, deux formats pris en charge par Snyk pour l’analyse depuis le système de fichiers. Utilisons-le pour télécharger une image depuis Quay.io et l’analyser localement depuis notre système de fichiers :
Comme nous pouvons le constater, cette image utilise une version d’Ubuntu en fin de vie et contient donc plusieurs vulnérabilités qui ne seront pas corrigées. Skopeo nous permet ainsi de télécharger des images depuis n’importe quel registre de conteneurs conforme aux normes, dans des formats pris en charge par Snyk, puis de les analyser localement.
Buildah
Passons maintenant à Buildah. Buildah est un outil en ligne de commande qui crée des images, mais ne les exécute pas : il est donc destiné à être utilisé avec Podman. Il est également conçu pour fonctionner sans accès root, en tirant parti des espaces de noms utilisateur du noyau Linux pour isoler un shell similaire à root, mais disposant uniquement de privilèges utilisateur. Les administrateurs peuvent ainsi permettre aux développeurs de créer et de gérer des images de conteneurs, tout en respectant le principe du moindre privilège dans l’environnement de compilation.
Buildah peut utiliser des Dockerfiles comme Docker, mais permet aussi de développer des conteneurs et des images avec d’autres méthodes, par exemple Bash ou Python. Cela offre davantage de flexibilité et peut faciliter le débogage des compilations de conteneurs. Buildah permet notamment de monter le conteneur intermédiaire pendant la compilation : les scripts peuvent alors vérifier que tout s’est correctement exécuté avant de poursuivre, compiler des logiciels à l’extérieur du conteneur ou même demander des informations à l’utilisateur. Cette méthode offre une alternative aux processus de compilation en plusieurs étapes, parfois complexes, qui se sont imposés comme bonnes pratiques avec Docker.
Voyons un exemple d’utilisation de Buildah.
À noter tout d’abord : avec Buildah, vous pouvez simplement utiliser des Dockerfiles pour créer vos conteneurs si cette méthode vous convient. Prenons ce Dockerfile comme exemple :
Nous utilisons ici l’image CentOS 8 comme base, clonons le code source de GNU Hello, installons quelques prérequis, puis compilons et installons le binaire.
Nous pouvons automatiser cette compilation avec Buildah et l’option bud (build-using-dockerfile) :
Ce n’est clairement pas une bonne pratique, car l’image finale contient à la fois le code source et les prérequis de compilation, et ne respecte pas la plupart des bonnes pratiques pour créer des images sécurisées. Avec Docker, la bonne pratique consisterait ici à utiliser une compilation en plusieurs étapes. Nous pourrions créer un Dockerfile multiétape avec Buildah, mais il est encore plus intéressant d’utiliser les commandes natives de Buildah et d’écrire des scripts. Pour reproduire exactement ce que nous avons fait avec le Dockerfile ci-dessus, nous exécuterions le script suivant :
Buildah nous permet toutefois de monter le conteneur intermédiaire pendant la compilation. Nous pouvons donc compiler le code source sur l’hôte et simplement copier le binaire obtenu dans notre conteneur avant de créer l’image. Nous profitons ainsi des ressources de l’hôte pendant les compilations et pouvons, par exemple, utiliser le gestionnaire de paquets de l’hôte pour installer des paquets dans notre conteneur. Nous n’avons pas non plus besoin d’un accès root pour cela : Buildah prend en charge les espaces de noms utilisateur, qui permettent d’effectuer un montage sans privilèges avec la commande unshare :
Comme le montre l’exemple ci-dessus, après l’exécution de la commande unshare, nous disposons d’un shell root, mais dans un espace de noms utilisateur sans privilèges root complets. Nous pouvons ainsi monter le système de fichiers du conteneur pendant la compilation. Comme il s’agit d’un script Bash, nous pouvons également tirer parti de toutes les fonctionnalités offertes par un langage de programmation : utiliser des conditions, des boucles ou même demander des informations à l’utilisateur pendant le processus.
Podman
Une fois le script exécuté et notre image créée, nous pouvons aussi l’analyser avec Snyk. C’est là que Podman entre en jeu. Podman est un moteur de conteneurs sans démon, conçu pour développer, gérer et exécuter des conteneurs OCI. Buildah et Podman reposant sur des normes ouvertes, Snyk a toujours pu analyser les images créées ou téléchargées avec Podman : il suffit d’utiliser Podman pour enregistrer l’image sur le disque et de l’analyser depuis le système de fichiers. Podman permet d’enregistrer les images au format d’archive Docker standard ou au format d’archive OCI, tous deux pris en charge par Snyk.
Notre image de base étant une image publique disponible sur Dockerhub, nous pourrions aussi simplement lancer cette commande pour l’analyser avec Snyk CLI :
Dans ce cas, Snyk communique directement avec Dockerhub et analyse l’image d’origine.
En revanche, si l’image existe uniquement dans Podman en local ou se trouve dans un dépôt privé sur Dockerhub qui nécessite une connexion, aucune de ces méthodes ne fonctionnera. Essayons, par exemple, d’analyser directement depuis Podman l’image que nous avons créée :
Pour ces cas d’utilisation, Snyk se sert du client Docker local, soit via l’API Registry, soit en utilisant le socket Docker. Comme le système ne contient aucun binaire Docker, Snyk a ici tenté d’utiliser l’API Registry, sans parvenir à se connecter. Par défaut, Snyk ne sait pas que ces images sont présentes localement dans Podman ni comment utiliser Podman pour accéder aux images d’origine.
Heureusement, Podman offre des fonctionnalités de compatibilité simples grâce au paquet podman-docker. Celui-ci fournit un faux binaire Docker, qui est en fait un wrapper shell du binaire Podman, et crée un lien symbolique entre le socket de l’API Podman et l’emplacement par défaut du fichier socket Docker. Par défaut, ce paquet crée un lien symbolique vers /var/run/podman/podman.sock, l’emplacement utilisé lorsque l’API Podman s’exécute avec les privilèges root.
Cela ne fonctionne toujours pas, mais nous obtenons cette fois une erreur différente. Snyk a détecté un binaire nommé docker et tente donc de se connecter à l’emplacement par défaut du socket Docker privilégié. Comme l’API Podman n’est pas encore lancée, la connexion échoue à nouveau.
Comme nous l’avons vu plus tôt, le paquet podman-docker crée un lien symbolique entre /var/run/podman/podman.sock et /var/run/docker.sock, en supposant que l’API Podman sera exécutée avec les privilèges root.
L’un des principaux problèmes du socket Docker est qu’il s’exécute par défaut avec les privilèges root, ce qui représente un risque de sécurité dans certains environnements. Dans la plupart des environnements de développement locaux, nous n’avons pas besoin d’exécuter l’API Podman de cette manière : nous pouvons utiliser un socket sans privilèges à un autre emplacement. Nous pouvons également indiquer cet emplacement à Snyk à l’aide de la variable d’environnement DOCKER_HOST, qui prend en charge les formats d’URL tcp:// et unix://.
Dans un autre shell, lançons l’API Podman avec un socket sans privilèges :
Le processus s’exécutera au premier plan. Vous devrez donc appuyer sur Ctrl-C une fois le test terminé. Définissons maintenant la variable d’environnement DOCKER_HOST :
Enfin, essayons à nouveau d’analyser notre image locale avec Snyk :
Ça fonctionne ! Snyk communique maintenant correctement avec Podman via le socket sans privilèges.
Pour configurer DOCKER_HOST de façon permanente dans votre shell, vous pouvez ajouter la commande export à votre fichier .bashrc afin que le paramètre soit conservé.
Enfin, nous aimerions que toute cette configuration soit automatiquement disponible à chaque connexion. Pour cela, nous pouvons tirer parti des fonctionnalités d’activation par socket de systemd afin de lancer automatiquement notre socket lorsque nous nous connectons et essayons de l’utiliser.
Commençons par configurer le socket :
Puis associons le socket à un service :
Pour finir, rechargeons la configuration de systemd et activons le service !
Conclusion
Voilà : l’analyse d’images avec Snyk CLI fonctionne avec Podman exactement comme avec Docker. Les développeurs peuvent ainsi facilement analyser de façon approfondie les images Docker ou OCI locales dans le cadre de leur workflow, sans avoir besoin de privilèges élevés. Nous avons également vu comment utiliser Skopeo et Buildah avec Snyk, grâce aux normes ouvertes !
Vous n’avez pas encore de compte Snyk ? Inscrivez-vous gratuitement et utilisez Snyk pour analyser vos images de conteneurs et vos dépendances open source.
Lancez-vous dans les challenges Capture The Flag
Apprenez à résoudre des challenges Capture The Flag en regardant à la demande notre atelier virtuel d’initiation.