Sécurité
Quelques rappels
Un container est un processus qui tourne dans un contexte d'isolation particulier grâce aux namespaces et Cgroups du kernel Linux.
En plus de ces éléments, il est possible de renforcer la sécurité grâce à :
SELinux : Security-Enhanced Linux, abrégé SELinux, est un Linux security module (LSM), qui permet de définir une politique de contrôle d'accès obligatoire aux éléments d'un système issu de Linux.
AppArmor : AppArmor permet à l'administrateur système d'associer à chaque programme un profil de sécurité qui restreint ses accès au système d'exploitation. Il complète le traditionnel modèle d'Unix du contrôle d'accès discrétionnaire (DAC, Discretionary access control) en permettant d'utiliser le contrôle d'accès obligatoire (MAC, Mandatory access control).
Seccomp : Seccomp permet à un processus d'effectuer une transition unidirectionnelle vers un état de sécurité dans lequel il ne peut plus effectuer d'appel système excepté exit(), sigreturn(), read() et write() sur des descripteurs déjà ouverts. Si le processus essaie d'effectuer un autre appel système, le noyau terminera le processus avec le signal SIGKILL ou SIGSYS.
Capabilities : La gestion des capabilities est un mécanisme de sécurité du noyau Linux concourant à assurer un confinement d’exécution des applications s’exécutant sur le système en affinant les possibilités d'appliquer le principe du moindre privilège.
Hardening
Les menaces liées à un container docker sont multiples :
Compromission de l'hôte par un container
- Épuisement des ressources :
on peut imaginer qu'un container lance une fork bomb qui amènerait à consommer l'intégralité des ressources de la machine hôte. Pour se prémunir de ce type de problème il convient de limiter les ressources affectées à un container
- Accès au filesystem de la machine hôte :
il faut faire attention aux volumes qui sont montés. Selon le principe de least privelege (loi de Demeter) il convietn de ne monter que les dossiers nécessaires au fonctionnement du container et autant que possible en read only.
Compromission d'un container par un autre container
- utilisation massive des ressources :
la non limitation des ressources d'un container peut engendrer une indisponibilité de CPU, Ram pour les autres containers. Il faut donc faire attention à limiter l'usage du CPU / Ram via les cgroups.
Corruption de l'image utilisée
Un container est basé sur une image qui contient un root filesystem ainsi qu'une application et ses dépendances. L'image peut contenir des vulnérabilités qu'il convient d'adresser. À défaut de pouvoir, il est important d'assurer que celles-ci sont connues et maîtrisées et qu'elles ne risquent pas d'impacter l'application.
Le but du hardening est de mettre en place un maximum d'éléments de sécurité afin de minimiser la surface d'attaque du container. Le CIS fournit à ce sujet un ensemble de bonnes pratiques à respecter qui concernant les éléments suivants :
- Configuration de la machine hôte
- Configuration du daemon Docker
- Fichiers de configuration du daemon Docker
- Images et Dockerfile
- Environnement d'exécution d'un container
- Opérations
Docker Security Bench
Il s'agit d'un outil basé sur les recommandations du CIS qui couvre l'ensemble des différents domaines et assure donc que les bonnes pratiques autour du déploiement des containers Docker en production soit respectées.
Le code source du logiciel est disponible sur Github, https://github.com/docker/docker-bench-security.
Celui-ci peut s'executer depuis un container docker.
docker run -it --net host --pid host --cap-add audit_control \
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
-v /var/lib:/var/lib \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /etc:/etc --label docker_bench_security \
docker/docker-bench-security
Unable to find image 'docker/docker-bench-security:latest' locally
latest: Pulling from docker/docker-bench-security
cd784148e348: Pull complete
48fe0d48816d: Pull complete
164e5e0f48c5: Pull complete
378ed37ea5ff: Pull complete
Digest: sha256:ddbdf4f86af4405da4a8a7b7cc62bb63bfeb75e85bf22d2ece70c204d7cfabb8
Status: Downloaded newer image for docker/docker-bench-security:latest
# ------------------------------------------------------------------------------
# Docker Bench for Security v1.3.4
#
# Docker, Inc. (c) 2015-
#
# Checks for dozens of common best-practices around deploying Docker containers in production.
# Inspired by the CIS Docker Community Edition Benchmark v1.1.0.
# ------------------------------------------------------------------------------
Initializing Mon Nov 29 17:37:59 UTC 2021
[INFO] 1 - Host Configuration
[WARN] 1.1 - Ensure a separate partition for containers has been created
[NOTE] 1.2 - Ensure the container host has been Hardened
[INFO] 1.3 - Ensure Docker is up to date
[INFO] * Using 20.10.11, verify is it up to date as deemed necessary
[INFO] * Your operating system vendor may provide support and security maintenance for Docker
[INFO] 1.4 - Ensure only trusted users are allowed to control Docker daemon
[INFO] * docker:x:975:whax
[WARN] 1.5 - Ensure auditing is configured for the Docker daemon
[WARN] 1.6 - Ensure auditing is configured for Docker files and directories - /var/lib/docker
[WARN] 1.7 - Ensure auditing is configured for Docker files and directories - /etc/docker
[INFO] 1.8 - Ensure auditing is configured for Docker files and directories - docker.service
[INFO] * File not found
[INFO] 1.9 - Ensure auditing is configured for Docker files and directories - docker.socket
[INFO] * File not found
[INFO] 1.10 - Ensure auditing is configured for Docker files and directories - /etc/default/docker
[INFO] * File not found
[INFO] 1.11 - Ensure auditing is configured for Docker files and directories - /etc/docker/daemon.json
[INFO] * File not found
[INFO] 1.12 - Ensure auditing is configured for Docker files and directories - /usr/bin/docker-containerd
[INFO] * File not found
[INFO] 1.13 - Ensure auditing is configured for Docker files and directories - /usr/bin/docker-runc
[INFO] * File not found
...
[INFO] Checks: 105
[INFO] Score: 15Chaque point défini par le CIS benchmark est analysé permettant de définir une note. Il n'y a rien qui définit ce qu'est une bonne ou une mauvaise note. Toutefois l'ensemble des éléments indiqués comme [WARN] ou [INFO] doivent être adressés en corrélation avec les recommendations du CIS.
Linux Capabilities
Les capabilities sont des primitives présentes dans le kernel Linux qui permettent de sécouper les droits root en plusieurs catégories et de casser la dichotomie root vs non root en augmentant la granularité des droits d'accès dont voici les principales :
- CAP_CHOWN : permet la modification des uid / gid
- CAP_SYS_ADMIN : permet des opérations administratives côté système
- CAP_NET_ADMIN : permet des opérations administratives côté network
- CAP_NET_BIND_SERVICE : permet d'affecter un port privilégié (< 1024) à un processus
Elles peuvent être ajoutées ou supprimées au lancement d'un container.
Lançons un container et essayons d'en changer le hostname.
docker run -it alpine sh
/ # hostname foo
hostname: sethostname: Operation not permittedRéeffectuons la même opération en ajoutant une capabilité
docker run -it --cap-add=SYS_ADMIN alpine sh
/ # hostname foo
/ # hostname
fooLe hostname du container a bien été changé, la capabilité SYS_ADMIN ayant rendu l'opération possible.
On peut également illustrer la possibilité de supprimer une capabilité NET_RAW dès lors que l'on souhaite effectuer un ping de la manière suivante :
docker run alpine ping -c3 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=113 time=12.579 ms
64 bytes from 8.8.8.8: seq=1 ttl=113 time=12.264 ms
64 bytes from 8.8.8.8: seq=2 ttl=113 time=12.172 ms
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 12.172/12.338/12.579 msdocker run --cap-drop=NET_RAW alpine ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
ping: permission denied (are you root?)Linux Security Module
Les modules LSM (AppArmor / SELinux) implémentent le MAC (Mandatory Access Control) qui s'implémente au dessus du DAC (Discretionary Access Control) et renforcent la sécurité en ajoutant des droits d'accès supplémentaires.
AppArmor
Ce module ajoute des droits basés sur le chemin d'accès aux ressources. Dans ce contexte chaque application a son propre profil de sécurité pour limiter ses droits et pour spécifier les dossiers, fichiers ou appareils auxquels elle peut accéder. Il est par défaut présent sur Ubuntu ou encore OpenSuse
Supposons un container avec un profil AppArmor installé :
docker run -ti alpine sh
/ # cat /proc/kcore
cat: can't open '/proc/kcore': Permission deniedRelançons ce même container en désactivant le profil de sécurité :
docker run -ti --security-opt apparmor:unconfined alpine sh
/# cat /proc/kcore
/#Cette fois-ci il n'y a pas d'erreur.
SELinux
Ce module de sécurité s'applique sur le système entier, contrairement à AppArmor en définissant des attributs supplémentaires sur le système de fichiers complet.
Le principe repose sur une combinaison d'objets (fichiers, répertoires, devices, interfaces réseaux etc) auxquels peuvent accéder des sujets (utilisateurs, applications, processus).
Son créateur, Daniel J Walsh, propose un article expliquant en détails son fonctionnement. Il propose d'ailleurs un livre à colorier afin de se familiariser avec le sujet.
Supposons que SELinux soit installé sur la machine hôte et listons les binaires docker
ls -Z /usr/bin/docker*
-rwxr-xr-x. root root system_u:object_r:docker_exec_t:s0 /usr/bin/docker
-rwxr-xr-x. root root system_u:object_r:docker_exec_t:s0 /usr/bin/dockerd
-rwxr-xr-x. root root system_u:object_r:docker_exec_t:s0 /usr/bin/docker-composeL'argument Z permet de lister les attributs rajoutés par le module, le contexte, nommé ici docker_exec_t.
Supposons qu'un serveur Nginx soit installé sur la machine hôte
ls -Z /usr/share/nginx/html/index.html
-rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 index.htmlLe contexte de sécurité est ici représenté par httpd_sys_content_t.
Démarrons un container qui mappe l'intégralité du système sur le container et essayons de modifier l'index de nginx :
docker run -ti -v /:/host alpine sh
echo "test" > /host/usr/share/nginx/html/index.html
sh: can't create /host/usr/share/nginx/html/index.html: Permission deniedSELinux joue bien son rôle et désactive l'accès au fichier en écriture depuis le container.
Pour y remédier il est possible de désactiver le profil :
docker run -ti -v /:/host --security-opt label:disable alpine sh
/ # echo "test" > /usr/share/nginx/html/index.html
/ #Secure Computing Mode
Seccomp opère au niveau des appels système (+ de 300 pour un linux x86-64) : mount, mkdir, ptrace, reboot, etc. Dans ce contexte le profil par défaut pour docker désactiver 44 de ces appels.
Il est toutefois possible de créer un profil custom, fourni au lancement d'un container. Toutefois il est difficile de déterminer les appels systèmes utilisés par un processus. On pourra utiliser strace pour réaliser cette action mais cela nécessitera malgré tout une bonne connaissance du kernel Linux.
Pour pouvoir l'utiliser il est nécessaire que Seccomp soit installé sur la machine hôte.
Il est à noter que certains des appels systèmes sont déjà filtrés au travers des capabilities.
La documentation de Docker explique parfaitement l'usage de seccomp. Dans la majorité des cas le profil par défaut fournir par l'installation de seccomp suffira et sera automatiquement appliqué par Docker.
Scanning de CVE
Comme une image contient de nombreuses librairies et fichiers binaires du système de base (Alpine par exemple) en plus du code applicatif, il est important de scanner celle-ci afin de déterminer si elle contient des CVE (Common Vulnerabilities and Exposures).
Pour scanner on peut utiliser :
- Docker scan
docker scan node:14Après l’exécution de la commande, Docker Scan vous retournera une liste de vulnérabilités, y compris les CVE détectées. Par exemple :
Testing node:14...
✗ Low severity vulnerability found in glibc
Description: CVE-2021-33574
Introduced through: glibc@2.28-10
✗ High severity vulnerability found in openssl
Description: CVE-2021-3449
Introduced through: openssl@1.1.1g-1+deb10u4Les informations fournies incluent :
Le niveau de gravité (Low, Medium, High, Critical)
Le nom et la version du package vulnérable
Le code CVE associé
Une description brève de la vulnérabilité
Des outils tiers comme :
- Anchore-Engine
- Clair fournit par CoreOS
- Docker Security Scanning, payant au delà de 10 scans / mois.
- Trivy (excellent choix dans un contexte de CI, OpenSCAP)
Ces solutions assurent soit un scan des fichiers, soit un scan des binaires à la recherche de signatures connues. Elles sont intégrables dans un pipeline d'intégration continue.
Le nombre de CVE existantes étant nombreuses, il est de bon ton de privilégier les images basées sur Alpine, celles-ci ayant une faible surface d'attaque.
Content Trust
Content Trust est un mécanisme qui permet de s'assurer de l'intégrité d'une image ainsi que de sa provenance. Il utilise Notary un projet open source de Docker qui implémente The Update Framework (TUF) qui permet d'assurer la sécurité des systèmes lors des mises à jour logicielles, notamment en assurant de la chronologie, en vérifiant que les CVE impactants les différents mises à jours.
Content Trust permet à un développeur de signer l'image lors d'un push et à l'utilisateur de vérifier l'intégralité lors du pull. Ainsi, dès lors que la variable d'environnement DOCKER_CONTENT_TRUST est à 1, alors il ne sera plus possible de puller d'images non signées.
Cette signature intervient au moment du tag de l'image.
