BT

Diffuser les Connaissances et l'Innovation dans le Développement Logiciel d'Entreprise

Contribuez

Sujets

Sélectionner votre région

Accueil InfoQ Articles Docker Est-Il Suffisamment Sécurisé ? Conseils Pour Des Images Et Des Conteneurs Sécurisés

Docker Est-Il Suffisamment Sécurisé ? Conseils Pour Des Images Et Des Conteneurs Sécurisés

Points Clés

  • La sécurité de Docker dépend de la façon dont vous l'utilisez : il est trop simpliste de demander « Est-ce sécurisé ? » alors que la sécurité consiste à l'adapter à votre cas d'utilisation.
  • Vous devez avoir une compréhension approfondie de la différence entre l'image Docker et l'exécution du conteneur Docker et les priorités de sécurité distinctes pour chacun.
  • Travailler avec Docker devrait impliquer le principe du moindre privilège : des autorisations minimales accordées tout en obtenant des fonctionnalités.
  • Vous pouvez réduire les autorisations dont disposent vos images Docker en évitant que les images ne s'exécutent en tant qu'utilisateur root, en réduisant l'accès aux fichiers binaires et en n'incluant que les fichiers binaires absolument nécessaires au moment de l'exécution, voire en revenant en arrière et en supprimant ceux utilisés lors de la construction.
  • Pour l'exécution du conteneur, assurez-vous que vos conteneurs sont isolés de l'hôte, ajustez le profil de sécurité par défaut en fonction de votre projet et assurez-vous d'utiliser des implémentations plus récentes telles que containerd et CRI-O pour réduire les binaires.

Docker est une plate-forme que la plupart des développeurs connaissent désormais. Il facilite la création, le déploiement et l'exécution de vos applications dans des packages appelés conteneurs. Les dépendances requises sont "packagées" et exécutées en tant que processus sur le système d'exploitation hôte, plutôt que le système d'exploitation soit dupliqué pour chaque charge de travail comme avec les machines virtuelles. Cela évite les petites différences de configuration entre les machines.

Depuis que Docker a rendu cette approche populaire, beaucoup d'entre nous parlent de conteneurs Docker et d'images Docker. En fait, les images et les conteneurs n'ont pas besoin d'être 'Docker' mais ils peuvent être basés sur un framework similaire.

À mesure que la programmation cloud native gagne en popularité, Docker et une approche de style Docker augmentent également. Cloud-native est un terme avec un certain nombre de définitions, mais cela signifie en grande partie exécuter une application, très probablement avec une architecture de microservices, sur une infrastructure cloud. Il utilise des outils d'automatisation, ainsi que les ressources et les fonctionnalités des fournisseurs cloud. Un outil de conteneurisation comme Docker est souvent utile avec ce style de programmation, car le contenu et la configuration du conteneur créent un environnement reproductible quel que soit le système sous-jacent.

Si vous utilisez Docker, vous voudrez également savoir s'il est suffisamment sécurisé pour votre application. Comme avec de nombreux systèmes, vous ne pouvez pas répondre à la question "Docker Est-il Suffisamment Sécurisé ?" par un simple oui ou non. Il est possible d'utiliser Docker de manière sécurisée mais vous devez prendre certaines mesures en considération.

Dans cet article, nous explorerons les considérations de sécurité les plus importantes autour de Docker.

Docker vs Images Docker

Pour aborder la sécurité de Docker, nous devons comprendre la différence entre Docker qui exécute les images dans un conteneur et les images Docker elles-mêmes. Ce sont deux choses différentes.

Vous démarrez un conteneur à partir d'une image Docker. Une image Docker est une structure en couches dans laquelle vous définissez le processus à exécuter et les fichiers nécessaires à son exécution. Par exemple, si vous êtes un développeur Jakarta EE, il peut s'agir de l'installation du serveur Jakarta EE et de votre application.

Docker Hub est un référentiel où vous pouvez stocker et partager vos images Docker. Vous pouvez utiliser ces images pour démarrer un conteneur directement à partir d'elles, ou vous pouvez étendre ces images, les personnaliser selon vos besoins et les utiliser à la place. La façon dont vous personnalisez votre image, en choisissant les fichiers binaires à inclure et leurs autorisations, a un impact sur la sécurité de votre application.

Vous avez alors le programme qui exécute réellement votre conteneur. Il dispose d'un processus démon (un processus d'arrière-plan qui n'est pas sous le contrôle direct de l'utilisateur) qui héberge des images, des conteneurs, des réseaux et des volumes de stockage. Il peut s'agir de Docker Engine ou d'une autre implémentation. Il est responsable de l'exécution de votre processus de manière isolée. La façon dont vous gérez vos conteneurs a également un impact sur la sécurité.

Considérations de sécurité pour l'image

Les images Docker que vous créez, qui respectent les règles de la spécification Open Container Initiative (OCI), ne fournissent pas nécessairement une sécurité complète prête à l'emploi. Vous pouvez prendre certaines mesures pour vous assurer que ce processus est assez sécurisé dans le conteneur et le système hôte

Le principal problème avec l'exécution de votre processus dans un conteneur est que lorsque l'application est « piratée » par une personne, elle peut accéder via l'hôte sous-jacent et donc poser un grand risque pour de nombreux systèmes.

Lors de l'exécution dans un conteneur, nous devons être plus attentifs aux problèmes de sécurité car un conteneur a des intégrations plus étroites avec l'hôte (comme mentionné ci-dessus, s'exécutant sur le système d'exploitation de l'hôte) qu'une machine virtuelle. Une faille de sécurité est plus grave lorsqu'elle se produit dans un conteneur. En effet, lorsque des applications s'exécutent sur différentes machines physiques, elles sont dans une certaine mesure séparées les unes des autres. Mais lorsqu'il existe une vulnérabilité dans le logiciel du conteneur, il est possible qu'une application/un processus accède à une application dans un autre conteneur - et accède donc à ses vulnérabilités ou l'ouvre à ses propres vulnérabilités.

L'une des précautions que vous devez prendre avec votre application ou votre processus dans le conteneur est qu'il ne doit jamais s'exécuter en tant qu'utilisateur "root". En tant que root, le processus a beaucoup plus d'autorisations et peut donc accéder à plus de processus de ressources de bas niveau. À un moment donné de votre script de conteneur, vous devriez toujours avoir l'indication de l'utilisateur qui exécute le processus principal.

USER myuser

Et idéalement, tous les fichiers binaires de votre processus et de votre application doivent appartenir à root mais n'avoir que des autorisations de lecture et d'exécution par l'utilisateur exécutant votre processus. De cette façon, le processus lui-même est incapable de modifier les binaires et les scripts qui composent votre application dans le conteneur, et donc en cas de violation, des choses moins graves peuvent se produire.

Le scénario ci-dessus est la mise en œuvre du principe du moindre privilège ; forcer le code à s'exécuter avec le niveau d'autorisation le plus bas possible. Lorsque le processus n'a pas la permission, il ne peut pas être abusé. Un autre principe est de réduire la surface d'attaque potentielle. Lorsque votre image ne contient pas de fichiers binaires qui ne sont pas strictement nécessaires, ils peuvent être à l'origine d'une faille de sécurité.

Donc, n'incluez dans l'image que les binaires qui sont absolument nécessaires. Si possible, partez d'une image "scratch" et ajoutez uniquement les fichiers binaires dont vous avez besoin. Ou partez d'une petite image de départ comme les images Alpine. Moins il y a de binaires et d'exécutables présents, moins ils peuvent contribuer à des vulnérabilités de sécurité potentielles.

Une troisième option pour supprimer les parties inutiles de l'image est l'utilisation de la construction multistage, surtout si vous utilisez également l'image elle-même pour construire l'application finale qui doit être exécutée dans le conteneur, toutes les étapes supplémentaires peuvent être effectuées dans une étape (stage) séparée. Cela vous permet uniquement de structurer correctement l'image dans les couches, mais vous permet de supprimer tout ce qui n'est pas nécessaire au moment de l'exécution.

#
# Build stage
#
FROM maven:3.6.0-jdk-11-slim AS build
COPY src /home/app/src
COPY pom.xml /home/app
RUN mvn -f /home/app/pom.xml clean package

#
# Package stage
#
FROM payara/micro:5.2021.10-jdk11
COPY --from=build /home/app/target/hello.war ${DEPLOY_DIR}

La construction multistage ci-dessus montre un exemple de conservation des seuls fichiers et processus requis dans l'image finale. Le code source et l'outil maven ne sont d'aucune utilité dans l'image finale où nous n'avons besoin que du fichier WAR de l'application Web. En ayant deux étapes distinctes, nous ne rendons pas les choses inutiles disponibles au moment de l'exécution. Nous devrions utiliser la même méthodologie autour des processus et des applications, même s'ils font partie de certaines images standard. Si possible, nous devrions partir d'une image de base (from scratch) et n'ajouter que ce qui est vraiment nécessaire.

Considérations de sécurité pour l'exécution du conteneur

La façon dont vous exécutez et avec quel logiciel vous exécutez les images peut également entraîner des failles de sécurité.

Nous avons déjà mentionné que vous ne devez pas utiliser l'utilisateur root pour exécuter votre processus dans le conteneur. Mais lors du démarrage du conteneur, vous pouvez également indiquer qu'il s'exécute de manière privilégiée. Avec ce flag, vous donnez toutes les capacités au conteneur et aussi lève également toutes les limitations imposées par le contrôleur cgroup. Et donc, en cas de problème de sécurité, cela a un impact plus important.

Les conteneurs doivent s'exécuter dans un "bac à sable" afin d'être isolés de l'hôte et des autres conteneurs en cours d'exécution. Cet indicateur privilégié supprime ce bac à sable et ne doit donc jamais être utilisé. Évitez également de définir l'option --net=host car cela peut également affecter le bac à sable. Cela permet au conteneur d'ouvrir des ports à faible numéro, tout comme les processus racine, ce qui affecte potentiellement l'isolement.

Lorsque vous utilisez l'option de réseau host lorsque vous exécutez le conteneur, il n'y aura aucun mappage de port n'est en vigueur et aucune isolation pour le réseau hôte. Le conteneur utilise les mêmes ressources réseau que l'hôte. Les ports de cette plage inférieure sont considérés comme des ports bien connus et ne sont généralement connectés que par des processus de super-utilisateur. Par conséquent, les utilisateurs peuvent être moins attentifs lorsqu'ils se connectent à un tel port. Mais le processus du conteneur a également accès à l'ensemble de la pile réseau et peut effectuer une analyse pour d'autres ports bien connus. Ils ne sont probablement pas accessibles depuis le monde extérieur mais peuvent être interrogés depuis le processus du conteneur puisqu'il utilise le réseau de l'hôte.

Le runtime Docker n'est pas le seul programme qui peut utiliser une image Docker pour démarrer un conteneur. Comme mentionné, Docker était l'outil qui a rendu populaire le travail avec les conteneurs, mais comme il s'agissait de la première implémentation, on a beaucoup appris au fil des ans sur la façon dont un tel environnement d'exécution de conteneur devrait fonctionner. Parallèlement à la définition de l'interface d'exécution du conteneur (Container Runtime Interface ou CRI) au sein de Kubernetes, d'autres implémentations suivant ce CRI avec une implémentation meilleure et plus sécurisée ont vu le jour.

Aujourd'hui, les runtimes containerd et CRI-O peuvent également être utilisés pour exécuter des conteneurs basés sur les images Docker. L'implémentation omet plusieurs fichiers binaires et processus afin qu'ils soient plus légers, plus rapides et plus sécurisés. Par exemple, ils n'incluent pas l'accès SSH dans le conteneur en cours d'exécution par défaut comme le fait dockerd (le nom du processus Docker Runtime). Comme la surface d'attaque est plus petite, moins de problèmes peuvent survenir.

Mais même avec ces nouveaux binaires, les risques de sécurité ne sont toujours pas nuls. Il est donc recommandé d'adapter la sécurité à votre processus. Il existe un profil de sécurité par défaut associé aux conteneurs, mais vous pouvez l'ajuster en utilisant le module de sécurité AppArmor Linux. Vous pouvez définir des fonctionnalités telles que l'accès aux dossiers, l'accès au réseau et l'autorisation (ou non) de lire, d'écrire ou d'exécuter des fichiers. La définition des entrées suivantes dans un fichier AppArmor refuse l'accès en écriture et en listage aux répertoires /etc et /home :

deny /etc/** wl,
deny /home/** wl,

En se basant sur la connaissance de ce que requiert le processus au sein du conteneur, il faut ouvrir uniquement les permissions nécessaires au bon fonctionnement de l'application. Ce profil peut être spécifié lorsque nous exécutons un conteneur

.

docker run <other options> --security-opt apparmor=my_profile <container-image>

En conclusion : un réglage fin pour une sécurité maximale 

Puisque les images Docker et les conteneurs doivent être utilisés dans une grande variété de scénarios, vous devez les régler pour votre cas d'utilisation spécifique. Les principes généraux de la sécurité restent les lignes directrices pour déterminer ce qui est nécessaire pour votre cas.

Le principe du moindre privilège dit que nous devrions donner les permissions minimales possibles tout en réalisant la fonctionnalité, pour éviter les failles de sécurité. Pour la conteneurisation, cela signifie que nous ne devrions pas exécuter le processus principal dans le conteneur avec l'utilisateur root. Nous devrions également utiliser les autorisations appropriées sur les fichiers et restreindre l'accès en utilisant un profil AppArmor spécifique.

Pour réduire la surface d'attaque, nous ne devrions inclure que ce qui est strictement nécessaire à notre cas d'utilisation et, par exemple, utiliser les implémentations plus récentes comme containerd et CRI-O pour exécuter nos conteneurs, car elles incluent moins de binaires et de processus.

 

Au sujet de l’Auteur

Evaluer cet article

Pertinence
Style

Contenu Éducatif

BT