Voyons comment renforcer et sécuriser Docker pour l’environnement de production.

Bien que Docker ait permis aux développeurs de logiciels et aux ingénieurs DevOps de créer et de déployer rapidement des applications, il s’accompagne également d’une grande surface d’attaque sur laquelle les cyberpirates peuvent s’appuyer.

Nous allons voir comment sécuriser un Docker sur une plateforme Linux à partir des éléments suivants.

  • Défauts de configuration
  • Exécution de code à distance
  • Débordements de mémoire tampon
  • Falsification d’image, etc.

Nous utiliserons les outils suivants, tels que le serveur notarial de Docker pour signer les images et Docker bench security pour vérifier l’hôte, la configuration du démon, etc.

Avant de procéder à la sécurisation, jetons un coup d’œil sur les bases.

Qu’est-ce qu’une technologie de conteneur ?

La technologie des conteneurs permet aux développeurs ou aux ingénieurs DevOps d’empaqueter une application afin qu’elle puisse fonctionner avec des dépendances isolées des autres processus.

Il existe un certain nombre de technologies de conteneurs sur le marché, comme Apache Mesos, lxc et Docker. Bien qu’elles appartiennent à la catégorie des technologies de conteneurs, elles fonctionnent différemment.

Différence entre VM et VE

Un hôte de machine virtuelle est totalement différent d’un hôte d’environnement virtuel. Sur les machines virtuelles, chaque application conteneurisée est accompagnée de son propre ensemble de bibliothèques et de son propre système d’exploitation, tandis que les applications, par défaut, sur un hôte d’environnement virtuel, telles que lxc et Docker, partagent le noyau Linux.

Qu’est-ce que Docker ?

Docker est une technologie de conteneur utilisée par millions pour créer une application web et la déployer d’un environnement de test à un environnement de production.

Le moteur Docker

Le moteur Docker est composé de trois éléments.

  • Un serveur : Ce composant est un processus à long terme ou un démon responsable de la gestion des images et des conteneurs.
  • L’API REST : Cette interface permet au démon Docker et à l’outil client Docker de communiquer.
  • Outil client Docker : L’outil client Docker utilise le composant API REST pour informer le démon Docker de l’exploitation d’une application conteneurisée.

Registre de confiance Docker

Docker Trusted Registry est une solution de stockage d’images proposée par Docker pour les plateformes d’entreprise. Il est différent du docker hub. Alors que le docker hub est hébergé dans le nuage, le docker trusted registry est une solution de stockage sur site pour l‘édition d’entreprise de Docker.

Docker Content Trust

Docker Content Trust permet d’utiliser des signatures de données pour les images envoyées et reçues vers et depuis des registres Docker distants tels que Docker Hub.

Espaces de noms Linux

Les espaces de noms Linux sont une fonctionnalité du noyau Linux qui permet d’isoler une application ou un processus conteneurisé s’exécutant sur un hôte d’environnement virtuel des autres processus.

Groupes de contrôle Linux (Cgroups)

Les groupes de contrôle Linux sont une fonctionnalité du noyau Linux qui vous permet d’allouer des ressources telles que le temps CPU, la bande passante réseau, la mémoire système, etc. aux processus actifs sur un hôte.

Capacités

Sous Linux, il existe une fonction de sécurité dans le sous-système du noyau qui peut être définie ou appliquée pour limiter le processus privilégié tel qu’un processus exécuté par un utilisateur avec l’UID 1. Bien que les processus ou utilisateurs privilégiés puissent contourner les autorisations de contrôle d’accès discrétionnaire, ils ne peuvent pas contourner les règles de capacités.

Concentrons-nous à présent sur la sécurité.

Sécurisation de l’hôte Docker

Dans cette section, nous allons voir comment sécuriser l’hôte où réside Docker.

Analyse du noyau Linux

Avant d’héberger un Docker sur une plateforme Linux, vous devez d’abord inspecter le noyau. Il existe plusieurs outils open-source tels que Lynis et OpenVAS que vous pouvez utiliser pour analyser le noyau Linux.

Copiez ou clonez le projet Lynis depuis Github à l’aide de la commande git clone.

git clone https://github.com/CISOfy/lynis.git

Ensuite, utilisez la commande ci-dessous pour vous rendre dans le répertoire lynis et auditer le système Linux.

cd lynis ; ./lynis audit system

Durcir le noyau Linux

Après avoir analysé le noyau Linux à la recherche de vulnérabilités basées sur le système, vous pouvez ajouter une couche supplémentaire de protection au noyau via grsecurity. Il fournit des fonctions de sécurité telles que les suivantes

  • Prévention de l’exploitation des débordements de mémoire tampon
  • prévention de la vulnérabilité de la course /tmp
  • restrictions de /proc qui ne divulguent pas d’informations sur les propriétaires de processus.
  • Prévention de l’exécution de code arbitraire dans le noyau, etc.

Initialement, vous pouvez télécharger gratuitement des correctifs à partir de grsecurity et les appliquer à votre noyau actuel. Mais les correctifs gratuits ne sont plus autorisés.

Installez Docker dans une machine virtuelle

Au lieu d’installer Docker directement sur un hôte Linux, vous pouvez ajouter une couche de protection supplémentaire en l’installant dans une machine virtuelle. Ainsi, même si le noyau de l’hôte présente une vulnérabilité, celle-ci n’affectera pas les conteneurs Docker.

Protection des privilèges root

Par défaut, Docker requiert les privilèges root pour créer et gérer les conteneurs. Un script malveillant peut tirer parti de cette surface d’attaque pour accéder à un superutilisateur sur un hôte Linux et éventuellement accéder à des fichiers/dossiers sensibles, des images, des certificats, etc.

Pour éviter cela, nous pouvons utiliser la commande suivante. Nous pouvons décider d’abandonner des fonctionnalités telles que setgid et setuid afin d’empêcher d’autres programmes ou processus de modifier leur GID en un autre GID, ce qui peut entraîner une escalade des privilèges. Vous pouvez également consulter ici la liste des définitions des capacités Linux.

La commande ci-dessous lance le conteneur apache webserver et supprime les capacités setgid et setuid via --cap-drop afin d’empêcher le conteneur apache de changer son GID et son UID pour un autre UID et un autre GID.

Dans ce contexte, GID et UID se réfèrent respectivement à l'ID du groupe et à l'ID de l'utilisateur.

docker run -d --cap-drop SETGID --cap-drop SETUID apache

Utilisateur Docker

En plus d’empêcher d’autres programmes ou processus, vous pouvez également créer un utilisateur pour gérer les opérations de docker telles que docker run au lieu de les gérer par l’intermédiaire d’un superutilisateur.

Vous pouvez ajouter ou créer un utilisateur Docker en procédant comme suit :

sudo groupadd docker

La commande ci-dessus crée un groupe appelé docker

Ensuite, créez un utilisateur à l’aide de la commande ci-dessous :

sudo useradd mike

Enfin, utilisez la commande ci-dessous pour ajouter un utilisateur mike au groupe docker afin d’administrer les opérations de docker.

sudo usermod -aG docker mike

Gestion des conteneurs à l’aide de Cgroups

Dans un environnement de production, vous pouvez avoir plus d’un conteneur.

Si cgroups n’est pas installé sur votre hôte, vous pouvez utiliser la commande suivante pour l’installer et ensuite vérifier ici (pour Ubuntu) comment le configurer.

sudo apt-get install cgroup-bin cgroup-lite cgroup-tools cgroupfs-mount libcgroup1

Nous pouvons allouer aux conteneurs des ressources CPU limitées via les options --cpu-shares et --cpuset-cpus

L’exemple de commande suivant montre que le processus de conteneur prodnginx est exécuté uniquement sur le premier coeur via --cpuset-cpus et se voit allouer 20 CPU via --cpu-shares tandis que le processus de conteneur proxnginx est exécuté sur les deux premiers cœurs de CPU et se voit également allouer 20 CPU.

docker run -d --name prodnginx --cpuset-cpus=0 --cpu-shares=20 nginx
docker run -d --name testnginx --cpuset-cpus=2 --cpu-shares=20 nginx

Tapez ensuite la commande docker stats pour voir l’utilisation du CPU par les conteneurs prodnginx et testnginx

CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
845bea7263fb prodnginx 57.69% 1.258MiB / 985.2MiB 0.13% 578B / 0B 1.33MB / 0B 
189ba15e8258 testnginx 55.85% 1.25MiB / 985.2MiB 0.13% 578b / 0B 1.33MB / 0B 

C’est une bonne idée de définir des parts de CPU pour un hôte Docker lorsque vous avez plus d’un conteneur en cours d’exécution sur celui-ci.

Gestion des conteneurs avec les espaces de noms

Un espace de noms peut empêcher les conteneurs de fonctionner en tant qu’utilisateurs privilégiés, ce qui peut aider à éviter les attaques par escalade de privilèges.

Nous pouvons activer l’espace de noms dans Docker en utilisant les fichiers /etc/subuid et /etc/subgid comme indiqué ci-dessous.

  • créez un utilisateur à l’aide de la commande adduser
sudo adduser dockremap
  • Configurez un subuid pour l’utilisateur dockremap
sudo sh -c 'echo dockremap:400000:65536 > /etc/subuid'
  • Configurez ensuite un subgid pour l’utilisateur dockremap
sudo sh -c 'echo dockremap:400000:65536 > /etc/subgid'
  • Ouvrez le fichier daemon.json et complétez-le avec le contenu suivant pour associer l’attribut userns-remap à l’utilisateur dockremap
vi /etc/docker/daemon.json
{ 

 "userns-remap" : "dockremap"

}
  • Appuyez sur :wq pour sauvegarder et fermer le fichier daemon.json et enfin redémarrez docker pour activer les espaces de noms sur un hôte docker
sudo /etc/init.d/docker restart

Sécuriser le Daemon Docker

Il est également nécessaire de configurer le démon Docker pour assurer une communication sécurisée entre le client Docker et le démon Docker via TLS.

Utilisez la commande suivante pour ouvrir le fichier daemon.json et copiez et collez le contenu suivant (remplacez l’IP par votre propre IP) comme indiqué ci-dessous

vi daemon.json
{
  "debug" : false,
  "tls" : true,
  "tlscert" : "/var/docker/server.pem",
  "tlskey" : "/var/docker/serverkey.pem",
  "hosts": ["tcp://192.168.16.5:2376"]
}

Sécurisation des composants Docker

Voyons comment utiliser des outils tels que CodeNotary et le serveur notarial pour signer les images afin d’éviter la falsification des images. En outre, il est également nécessaire d’analyser les images pour s’assurer qu’elles ne contiennent pas de vulnérabilités

Nous allons utiliser le serveur notarial de Docker pour signer et vérifier les images et utiliser Anchor Engine pour scanner les images à la recherche de vulnérabilités.

Vérifier les images avec le serveur Notary

Avant de pouvoir utiliser le serveur Notary pour signer les images, nous devons télécharger et installer docker-compose. Nous utiliserons Docker Compose pour mettre en place un serveur notarial.

  • Exécutez la commande ci-dessous pour télécharger la dernière version de Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  • Appliquez les permissions d’exécution à docker-compose comme indiqué ci-dessous
sudo chmod 700 /usr/local/bin/docker-compose
  • Vous pouvez tester si vous avez installé docker-compose avec succès à l’aide de la commande suivante
docker-compose --version
  • Nous pouvons maintenant installer le serveur notarial via docker-compose
git clone https://github.com/theupdateframework/notary.git
  • La commande ci-dessus clone ou copie le serveur notarial à partir du dépôt notarial
  • Démarrez le serveur notarial et le signataire via les commandes ci-dessous :
docker-compose build
docker-compose up -d
  • Copiez ensuite la configuration et les certificats de test dans votre répertoire notarial local à l’aide de la commande suivante
mkdir -p ~/.notary && cp cmd/notary/config.json cmd/notary/root-ca.crt ~/.notary
  • Exécutez maintenant la commande suivante pour connecter le serveur notarial au client Docker
export DOCKER_CONTENT_TRUST=1
export DOCKER_CONTENT_TRUST_SERVER=https://notaryserver:4443
  • Générez une paire de clés de délégation via la commande suivante
docker trust key generate mike --dir ~./docker/trust        
  • Maintenant, créons une cible de nouvelles clés au cas où le référentiel n’existerait pas
docker trust signer add --key ~/.docker/trust/mike.pub mike mikedem0/whalesay
  • Ensuite, vous pouvez signer votre image docker en utilisant la commande docker trust sign. Vous devez extraire l’image docker de docker hub et la re-taguer en utilisant les commandes docker pull et docker tag respectivement.
docker trust sign mikedem0/nginx:latest

Vous pouvez également analyser les images docker pour détecter les vulnérabilités et les défauts de configuration. Vous pouvez vérifier ici comment utiliser Anchor Engine pour rechercher des vulnérabilités et Docker Bench Security pour rechercher des défauts de configuration.

J’espère que ce qui précède vous donne une idée de la sécurité Docker pour l’environnement de production. Vous pouvez également consulter ce cours Udemy sur le piratage et la sécurisation des conteneurs Docker.