
Les conteneurs Docker sont la technologie de conteneurisation la plus populaire. Initialement, il était principalement utilisé pour les environnements de développement et de test et, au fil du temps, il est passé à la production. Les conteneurs Docker ont commencé à se reproduire dans l'environnement de production, comme les champignons après la pluie, mais peu de ceux qui utilisent cette technologie ont réfléchi à la façon de publier en toute sécurité les conteneurs Docker.
Sur la base de
OWASP , nous avons préparé une liste de règles, dont la mise en œuvre protégera considérablement votre environnement, basées sur des conteneurs Docker.
Règle 0
La machine hĂ´te et Docker doivent contenir toutes les mises Ă jour actuelles.
Pour se protéger contre les vulnérabilités connues qui conduisent à s'échapper de l'environnement de conteneur vers le système hôte, ce qui entraîne généralement une élévation de privilèges sur le système hôte, l'installation de tous les correctifs pour le système d'exploitation hôte, Docker Engine et Docker Machine est extrêmement importante.
De plus, les conteneurs (contrairement aux machines virtuelles) partagent le noyau avec l'hôte, donc l'exploit du noyau s'exécutant à l'intérieur du conteneur s'exécute directement dans le noyau de l'hôte. Par exemple, un exploit d'escalade de privilèges du noyau (tel que Dirty COW) exécuté dans un conteneur bien isolé entraînera un accès root sur l'hôte.
Règle 1
Ne donnez pas accès au socket du démon Docker
Le service Docker (démon) utilise le socket UNIX /var/run/docker.sock pour les connexions API entrantes.
Le propriétaire de cette ressource doit être l'utilisateur root. Et pas d'autre moyen. La modification des droits d'accès à ce socket équivaut essentiellement à accorder un accès root au système hôte.
De plus, vous ne devez pas tâtonner le socket /var/run/docker.sock avec des conteneurs, où vous pouvez vous en passer, car dans ce cas, compromettre le service dans le conteneur entraînera un contrôle complet sur le système hôte. Si vous avez des conteneurs qui utilisent quelque chose comme ceci:
-v /var/run/docker.sock://var/run/docker.sock
ou pour docker-compose:
volumes: - "/var/run/docker.sock:/var/run/docker.sock"
besoin urgent de changer cela.
Et le dernier - n'écoutez
jamais, n'utilisez
jamais la socket Docker TCP sans la certitude absolue que vous en avez besoin, en particulier sans l'utilisation de méthodes de protection supplémentaires (au moins une autorisation). Par défaut, le socket Docker TCP ouvre un port sur l'interface externe 0.0.0.0:2375 (2376, dans le cas des HTTP) et permet un contrôle total des conteneurs, et avec lui le système hôte potentiel.
Règle 2
Configurer un utilisateur non privilégié à l'intérieur du conteneur
La configuration d'un conteneur pour utiliser un utilisateur non privilégié est le meilleur moyen d'éviter une attaque par élévation de privilèges. Cela peut se faire de différentes manières:
1. En utilisant l'option "-u" de la commande "docker run":
docker run -u 4000 alpine
2. Pendant la construction de l'image:
FROM alpine RUN groupadd -r myuser && useradd -r -g myuser myuser < root-, , > USER myuser
3. Activez la prise en charge de "l'espace de noms utilisateur" (environnement utilisateur) dans le démon Docker:
--userns-remap=default
En savoir plus Ă ce sujet dans la
documentation officielle .
Dans Kubernetes, ce dernier est configuré dans le
contexte de sécurité via l'option runAsNonRoot:
kind: ... apiVersion: ... metadata: name: ... spec: ... containers: - name: ... image: .... securityContext: ... runAsNonRoot: true ...
Règle 3
Limiter les capacités des conteneurs
Sous Linux, à partir du noyau 2.2, il existe un moyen de contrôler les capacités des processus privilégiés appelés
capacités du noyau Linux (pour plus de détails, voir le lien).
Docker utilise par défaut un ensemble prédéfini de ces fonctionnalités du noyau. Et cela vous permet de modifier cet ensemble à l'aide des commandes:
--cap-drop — --cap-add —
Le meilleur paramètre de sécurité consiste à désactiver d'abord toutes les fonctionnalités (--cap-drop all), puis à ne connecter que celles nécessaires. Par exemple, comme ceci:
docker run --cap-drop all --cap-add CHOWN alpine
Et le plus important (!): Évitez d'exécuter des conteneurs avec le drapeau privilégié !!!
Dans Kubernetes, la contrainte de capacités du noyau Linux est configurée dans le contexte de sécurité via l'option de capacités:
kind: ... apiVersion: ... metadata: name: ... spec: ... containers: - name: ... image: .... securityContext: ... capabilities: drop: - all add: - CHOWN ...
Règle 4
Utilisez l'indicateur no-new-privileges
Lors du démarrage d'un conteneur, il est utile d'utiliser l'indicateur --security-opt = no-new-privileges qui empêche l'escalade de privilèges à l'intérieur du conteneur.
Dans Kubernetes, la contrainte de capacités du noyau Linux est configurée dans le contexte de sécurité via l'option allowPrivilegeEscalation:
kind: ... apiVersion: ... metadata: name: ... spec: ... containers: - name: ... image: .... securityContext: ... allowPrivilegeEscalation: false ...
Règle 5
Désactiver la communication entre conteneurs
Par défaut, la communication entre conteneurs est activée dans Docker, ce qui signifie que tous les conteneurs peuvent communiquer entre eux (en utilisant le réseau docker0). Cette fonctionnalité peut être désactivée en exécutant le service Docker avec l'indicateur –icc = false.
Règle 6
Utiliser des modules de sécurité Linux (Module de sécurité Linux - seccomp, AppArmor, SELinux)
Par défaut, Docker utilise déjà des profils pour les modules de sécurité Linux. Par conséquent,
ne désactivez jamais les profils de sécurité! Le maximum que l'on puisse en faire est de resserrer les règles.
Le profil par défaut de seccomp est disponible
ici .
Docker utilise également AppArmor pour la protection, et le moteur Docker lui-même génère un profil par défaut pour AppArmor au démarrage du conteneur. En d'autres termes, au lieu de:
$ docker run --rm -it hello-world
démarre:
$ docker run --rm -it --security-opt apparmor=docker-default hello-world
La
documentation fournit également un exemple de profil AppArmor pour nginx, ce qui est tout à fait possible (nécessaire!) À utiliser:
Règle 7
Limiter les ressources de conteneur
Cette règle est assez simple: afin d'empêcher les conteneurs de dévorer toutes les ressources du serveur lors de la prochaine attaque DoS / DDoS, nous pouvons définir des limites d'utilisation de la mémoire pour chaque conteneur individuellement. Vous pouvez limiter: la quantité de mémoire, le processeur, le nombre de redémarrages du conteneur.
Alors allons-y dans l'ordre.
La mémoireL'option -m ou --memoryQuantité maximale de mémoire qu'un conteneur peut utiliser. La valeur minimale est de 4 m (4 mégaoctets).
Option - échange de mémoireOption pour configurer l'échange (fichier d'échange). Configuré astucieusement:
- Si --memory-swap> 0, l'indicateur –memory doit également être défini. Dans ce cas, memory-swap indique la quantité totale de mémoire disponible pour le conteneur avec swap.
- Un exemple plus simple. Si --memory = "300m" et --memory-swap = "1g", le conteneur peut utiliser 300 Mo de mémoire et 700 Mo de swap (1 g - 300 m).
- Si --memory-swap = 0, le paramètre est ignoré.
- Si --memory-swap a la mĂŞme valeur que --memory, le conteneur n'aura pas de swap.
- Si --memory-swap n'est pas spécifié, mais --memory est spécifié, le nombre de swap sera égal à deux fois la quantité de mémoire spécifiée. Par exemple, si --memory = "300m" et --memory-swap n'est pas défini, le conteneur utilisera 300 Mo de mémoire et 600 Mo de swap.
- Si --memory-swap = -1, le conteneur utilisera tout le swap possible sur le système hôte.
Remarque à l'hôtesse: l' utilitaire gratuit lancé à l'intérieur du conteneur n'affiche pas la valeur réelle du swap disponible pour le conteneur, mais le nombre de swap d'hôte.
Option --oom-kill-disableVous permet d'activer ou de désactiver le tueur OOM (Out of memory).
Attention! Vous pouvez désactiver OOM Killer uniquement avec l'option --memory définie, sinon il peut arriver qu'avec une mémoire insuffisante à l'intérieur du conteneur, le noyau commence à tuer les processus du système hôte.
D'autres options de configuration de la gestion de la mémoire, telles que --memory-swappiness, --memory-reservation et --kernel-memory, sont davantage destinées à optimiser les performances du conteneur.
CPUOption --cpusL'option définit la quantité de ressources processeur disponibles que le conteneur peut utiliser. Par exemple, si nous avons un hôte avec deux processeurs et que nous définissons --cpus = "1.5", le conteneur est garanti d'utiliser un processeur et demi.
Option --cpuset-cpusConfigure l'utilisation de cœurs ou de processeurs spécifiques. La valeur peut être spécifiée avec un trait d'union ou une virgule. Dans le premier cas, la plage de cœurs autorisés sera indiquée, dans le second - cœurs spécifiques.
Nombre de redémarrages du conteneur --restart=on-failure:<number_of_restarts>
Ce paramètre définit le nombre de fois où Docker tentera de redémarrer le conteneur en cas de panne inattendue. Le compteur est réinitialisé si l'état du conteneur est passé à en cours d'exécution.
Il est recommandé de définir un petit nombre positif, par exemple 5, ce qui évitera les redémarrages sans fin d'un service qui ne fonctionne pas.
Règle 8
Utiliser des systèmes de fichiers et des volumes en lecture seule
Si le conteneur ne doit rien écrire quelque part, vous devez utiliser autant que possible le système de fichiers en lecture seule. Cela compliquera considérablement la vie d'un intrus potentiel.
Un exemple de démarrage d'un conteneur avec un système de fichiers en lecture seule:
docker run --read-only alpine
Un exemple de connexion de volume en mode lecture seule:
docker run -v volume-name:/path/in/container:ro alpine
Règle 9
Utiliser des outils d'analyse de sécurité des conteneurs
Des outils doivent être utilisés pour détecter les conteneurs présentant des vulnérabilités connues. Il n'y en a pas encore beaucoup, mais ce sont:
• Gratuit:
• Commercial:
Et pour Kubernetes, il existe des outils pour détecter les erreurs de configuration: