10 meilleures pratiques pour sécuriser les images Docker. 2e partie

Une traduction de l'article a été préparée spécialement pour les étudiants du cours Linux Security .


Lire la première partie


5. Ne laissez pas de données sensibles dans les images Docker


Parfois, lors de la création d'une application à l'intérieur d'une image Docker, vous avez besoin de données sensibles comme une clé SSH privée pour extraire le code d'un référentiel privé ou des jetons pour installer des packages fermés. Si vous les copiez dans un conteneur Docker intermédiaire, ils sont mis en cache dans la couche à laquelle ils ont été ajoutés, même si vous les supprimez ultérieurement. Ces jetons et clés doivent être stockés en dehors du Dockerfile .

Utiliser des builds en plusieurs étapes


À l'aide de la prise en charge de Docker pour les générations à plusieurs étapes, manipulez les secrets dans la couche centrale de l'image, qui est ensuite supprimée afin qu'aucune donnée sensible n'atteigne la génération finale. Utilisez le code suivant pour ajouter des données secrètes au middleware:

 FROM: ubuntu as intermediate WORKDIR /app COPY secret/key /tmp/ RUN scp -i /tmp/key build@acme/files . FROM ubuntu WORKDIR /app COPY --from=intermediate /app . 

Utiliser les commandes Docker Secrets


Utilisez la fonction alpha dans Docker pour gérer les données sensibles afin de monter des fichiers sensibles sans les mettre en cache:

 # syntax = docker/dockerfile:1.0-experimental FROM alpine # shows secret from default secret location RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecre # shows secret from custom secret location RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar 

Vous pouvez en savoir plus sur la gestion des données sensibles sur le site Web de Docker.

Méfiez-vous de la copie récursive


Vous devez également faire attention à la copie des fichiers dans l'image créée. Par exemple, la commande suivante copie récursivement l'intégralité du dossier de contexte d'assembly dans une image Docker, ce qui peut également entraîner la copie de fichiers sensibles:

 COPY . . 

S'il y a des fichiers sensibles dans votre dossier, supprimez-les ou utilisez .dockerignore pour les ignorer:

 private.key appsettings.json 

6. Utilisez des étiquettes fixes pour l'immunité


Chaque image Docker peut avoir plusieurs balises qui représentent des variations des mêmes images. La balise la plus courante est la latest , représentant la dernière version d'une image. Les balises d'image ne sont pas immuables et un auteur d'image peut publier plusieurs fois la même balise.

Cela signifie que l'image de base de votre fichier Docker peut changer d'une génération à l'autre. Cela peut entraîner un comportement inattendu en raison des modifications apportées à l'image de base.

Il existe plusieurs façons de résoudre ce problème:

  • Préférez la balise la plus spécifique disponible. Si l'image a plusieurs balises, telles que :8 et :8.0.1 ou même :8.0.1-alpine , préférez cette dernière, car c'est le lien le plus spécifique vers l'image. Évitez d'utiliser les balises les plus courantes, telles que les dernières. Lorsque vous épinglez une balise spécifique, gardez à l'esprit qu'elle peut éventuellement être supprimée.
  • Pour résoudre le problème selon lequel une balise d'image spécifique devient inaccessible et devient une limite d'affichage des annonces pour les groupes qui en dépendent, envisagez de démarrer un miroir local de cette image dans le registre ou le compte sous votre propre contrôle. Il est important de prendre en compte les coûts de maintenance nécessaires à cette approche, car cela signifie que vous devez gérer le registre. Il est recommandé de répliquer l'image que vous souhaitez utiliser dans votre registre pour vous assurer que l'image que vous utilisez ne change pas.
  • Soyez extrêmement précis! Au lieu de tirer la balise, tirez l'image à l'aide d'un lien SHA256 spécifique vers l'image Docker, ce qui garantit que vous obtenez la même image pour chaque demande. Cependant, notez que l'utilisation d'un lien SHA256 peut présenter le risque suivant: si l'image change, le hachage peut ne plus fonctionner.

7. Utilisez COPY au lieu d'ADD


Docker fournit deux commandes pour copier des fichiers de l'hôte vers l'image Docker lors de sa création: COPY et ADD . Les commandes sont de nature similaire, mais diffèrent dans leurs fonctionnalités:

  • COPY - copie récursivement les fichiers locaux, indiquant les fichiers ou répertoires source et cible. Avec COPY, vous devez déclarer les emplacements.
  • ADD - copie récursivement des fichiers locaux, crée implicitement un répertoire de destination s'il n'existe pas et accepte les archives comme URL locales ou distantes comme source, qu'il étend ou charge, respectivement, dans le répertoire de destination.
    Bien que les différences entre ADD et COPY ne soient pas aussi fondamentales, elles sont importantes. Soyez conscient d'eux pour éviter les problèmes de sécurité potentiels:
  • Lorsque des URL distantes sont utilisées pour télécharger des données directement vers leur emplacement d'origine, cela peut entraîner des attaques de courtier qui modifient le contenu du fichier téléchargé. De plus, l'origine et l'authenticité des URL distantes doivent être vérifiées davantage. Lorsque vous utilisez COPY, la source des fichiers à télécharger à partir d'URL distantes doit être déclarée via une connexion TLS sécurisée et leur origine doit également être vérifiée.
  • Remarques sur l'espace et les couches d'images: l'utilisation de COPY vous permet de séparer l'ajout de l'archive des emplacements distants et de la décompresser en différentes couches, ce qui optimise le cache des images. Si des fichiers distants sont requis, combinez-les tous en une seule commande RUN, qui télécharge, extrait et purge par la suite, optimisant le fonctionnement sur une seule couche sur plusieurs couches qui seraient nécessaires à l'aide d'ADD.
  • Lorsque des archives locales sont utilisées, ADD les extrait automatiquement dans le répertoire de destination. Bien que cela puisse être acceptable, cela ajoute le risque d'obtenir des bombes zip et des vulnérabilités Zip Slip , qui peuvent ensuite être lancées automatiquement.

8. Utilisez des balises de métadonnées


Les étiquettes d'images fournissent des métadonnées pour les images que vous créez. Cela permet aux utilisateurs de comprendre plus facilement comment utiliser l'image. La balise la plus courante est «mainteneur», qui indique l'adresse e-mail et le nom de la personne qui prend en charge cette image. Ajoutez des métadonnées à l'aide de la commande LABEL suivante:

 LABEL maintainer="me@acme.com" 

En plus des contacts du responsable, ajoutez toutes les métadonnées importantes pour vous. Ces métadonnées peuvent contenir: un hachage de validation, un lien vers l'assembly approprié, l'état de qualité (tous les tests ont-ils été passés?), Le code source, un lien vers l'emplacement du fichier SECURITY.TXT, etc.

Il est recommandé de prendre en charge le fichier SECURITY.TXT (RFC5785), qui pointe vers votre politique de divulgation responsable pour votre schéma d'étiquettes Docker lors de l'ajout de nouveaux, par exemple:

 LABEL securitytxt="https://www.example.com/.well-known/security.txt" 

Voir plus d'informations sur les étiquettes pour les images Docker:

https://label-schema.org/rc1/

9. Utilisez l'assemblage en plusieurs étapes pour des images petites et sûres


Lorsque vous créez une application à l'aide du Dockerfile , de nombreux artefacts sont créés qui ne sont requis qu'au moment de la génération. Il peut s'agir d'outils de développement et de bibliothèques nécessaires à la compilation, ou de dépendances nécessaires pour exécuter des tests unitaires, des fichiers temporaires, des secrets, etc.

Le stockage de ces artefacts dans une image de base pouvant être utilisée en production entraîne une augmentation de la taille de l'image Docker, ce qui peut considérablement affecter le temps de téléchargement et également augmenter la surface d'attaque, ce qui entraînera l'installation de plus de packages. Il en va de même pour l'image Docker que vous utilisez - vous aurez peut-être besoin d'une image Docker spécifique pour créer, mais pas pour exécuter votre code d'application.

Golang en est un excellent exemple. Pour créer une application Golang, vous avez besoin d'un compilateur Go. Le compilateur crée un fichier exécutable qui s'exécute sur n'importe quel système d'exploitation, sans dépendances, y compris des images propres.

C'est une bonne raison pour laquelle Docker a la capacité de construire par étapes. Cette fonction vous permet d'utiliser plusieurs images temporaires pendant le processus d'assemblage, en enregistrant uniquement la dernière image avec les informations que vous y avez copiées. Vous avez donc deux images:

  • La première image est de très grande taille, associée à de nombreuses dépendances utilisées pour créer l'application et exécuter les tests.
  • La deuxième image est très légère en termes de taille et de nombre de bibliothèques, ne contenant que des copies des artefacts nécessaires pour exécuter l'application en production.

10. Utilisez le linter


Utilisez le linter pour éviter les erreurs courantes et établir les meilleures pratiques que les ingénieurs peuvent suivre automatiquement.

Un tel linter est hadolint . Il analyse le Dockerfile et émet un avertissement en cas d'erreurs non conformes à ses recommandations.



Hadolint devient encore plus puissant lorsqu'il est utilisé dans un environnement de développement intégré (IDE). Par exemple, lors de l'utilisation de hadolint comme extension VSCode, des erreurs de peluchage apparaissent lors de la saisie. Cela aide à écrire les meilleurs fichiers docker plus rapidement.

En savoir plus sur la protection de vos images Docker.

Source: https://habr.com/ru/post/fr482044/


All Articles