Renforcement basique de l'hôte
L'hôte hébergeant les containers doit respecter la procédure de renforcement liée à son système d'exploitation:
- GNU/Linux : TODO
- Windows : TODO
- Mac : TODO
Règles supplémentaires liées à Docker
L'utilisation du service Docker implique des règles de sécurité supplémentaires liées à son usage en particulier.
Partition /var/lib/docker dédiée
La partition /var/lib/docker est amenée à contenir les volumes, images, et autres fichiers générés par Docker. Ils est recommandé de le mettre sur une partition dédiée.
Si ce répertoire n'est pas positionné dans une partition dédiée et qu'il est lié au point de montage "/", il est possible que Docker sature complêtement l'espace disponible et qu'il puisse rendre l'hôte inutilisable. Une image intentionnellement "vérolée", ou non, pourrait volontairement se mettre à occuper tout l’espace disponible du système hôte. De plus, le demain Docker pourrait de lui meme saturé l'espace à forcer d'exécuter des commandes telles que "docker pull".
Il est possible de modifier la valeur de l'attribut "data-root" dans la configuration du démon Docker (/etc/docker/daemon.json). Néanmoins, il est plutôt recommandé de monter /var/lib/docker directement depuis le fichier /etc/fstab.
Configuration particulière d'auditd
Le service auditd doit être en mesure de contrôler les éléments suivants :
Fichier | Type |
---|---|
/usr/bin/docker | Écriture / Changement d'attribut |
/var/lib/docker | Écriture / Changement d'attribut |
/etc/docker | Écriture / Changement d'attribut |
/usr/lib/systemd/system/docker.service | Écriture / Changement d'attribut |
/usr/lib/systemd/system/docker.socket | Écriture / Changement d'attribut |
/etc/default/docker | Écriture / Changement d'attribut |
/usr/bin/docker-containerd | Écriture / Changement d'attribut |
/usr/bin/docker-runc | Écriture / Changement d'attribut |
Renforcement du démon Docker
Désactivation des communications inter-container (ICC)
La communication inter-container permet à des containers d'un même réseau de communiquer entre eux même lorsque l'attribut link n'est pas utilisé. Par conséquent, il est demandé de désactiver cette fonctionnalité afin que seul les containers linkés (liés) puissent communiquer entre eux.
Commandes | Description |
---|---|
$ docker network create --opt com.docker.network.bridge.enable_icc=false NetworkName | Crée un réseau nommé NetworkName avec l'ICC désactivé. |
$ echo "DOCKER_OPTS="–icc=false" >> /etc/default/docker | Désactive les communications ICC sur l'ensemble du service Docker. |
Il est aussi possible d'ajouter l'attribut "icc" à "false" dans la configuration du démon docker (/etc/docker/daemon.json).
Récupération des journaux de chaque container
À l'instar des machines physiques, les journaux de tout les containers de production doivent être archiver sur un serveur centralisé (eg: Elasticsearch, graylog). Il faut s'assurer que logs capturés sont au minimum au niveau INFO. La centralisation des journaux d'evenements peut se faire via le fichier de configuration du démon Docker (/etc/docker/daemon.json) avec les éléments suivants :
{
"log-driver": "syslog",
"log-opts": { "syslog-address": "udp://1.2.3.4:1111" }
}
Test via l'outil Docker-Bench-Security
L'outil Docker-Bench-Security permet de tester si l'environnement d'exécution Docker est déployé en respectant l'état de l'art. Chaque point avec un état [Warn] doit être traité avant la mise en production du serveur.
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 /usr/lib/systemd:/usr/lib/systemd \
-v /etc:/etc --label docker_bench_security \
docker/docker-bench-security
Le point 2.11 semble complexe à corriger et peut être écarté.
Désactivation des registres obsolètes
Il est demandé de désactiver l'utilisation des registres obsolètes (legacy V1) qui n'est aujourd'hui plus considéré comme sécurisé. Cette configuration peut être effectuée depuis le fichier de configuration du démon Docker (/etc/docker/daemon.json) avec les éléments suivants :
{
"disable-legacy-registry": true
}
Forcer l'utilisation d'overlay2
Par défaut le pilote de stockage utilisé par Docker est, aujourd'hui, Overlay2. Mais cela n'a pas toujours été le cas, il s'agissait avant du driver AUFS. Par conséquent, il est recommandé d'explicitement forcer l'utilisation d'Overlay2 afin de se prémunir d'un quelconque rollback au niveau du stockage. Cette configuration peut être effectuée depuis le fichier de configuration du démon Docker (/etc/docker/daemon.json) avec les éléments suivants :
{
"storage-driver": "overlay2"
}
Activation du Live Restore
L'option "Live Restore" permet aux containers de continuer de fonctionner même si le démon s'éteint ou plante. Cette configuration peut être effectuée depuis le fichier de configuration du démon Docker (/etc/docker/daemon.json) avec les éléments suivants :
{
"live-restore": true
}
Utilisation des user namespaces
Par défaut docker map les utilisateurs d'un container aux utilisateurs de l'hôte. Par exemple, si un container fonctionne avec l'utilisateur toto (UID:1000) et que l'hôte à un utilisateur mappé sur le même UID, le container aura alors les mêmes droits. C'est notamment pour ça que l'utilisation du root (UID:0) dans un container est dangereux car il est directement mappé au root du système hôte. Pour se prémunir de ce type de problème, il est possible de remapper un user d'un container à un user de l'hôte de manière fixe à l'aide de l'instruction "userns-remap". Cette configuration peut être effectuée depuis le fichier de configuration du démon Docker (/etc/docker/daemon.json) avec les éléments suivants :
{
"userns-remap": "default"
}
Désactivation du userland-proxy
Le userland proxy permet de gérer les communications intercontainer et container/hôte. Il est recommandé de le désactiver afin que les règles de communications soient uniquement gérées par IPTables. Cette configuration peut être effectuée depuis le fichier de configuration du démon Docker (/etc/docker/daemon.json) avec les éléments suivants :
{
"userland-proxy": false
}
Limitation des images autorisées à se lancer
Il pourra être interessant à termes d'activer l'option "DOCKER_CONTENT_TRUST" afin d'autoriser l'exécution d'image signées et validées. Cette mesure permet d'attenuer la possibilité d'exécuter du code malveillant sur la machine hôte. Cette configuration se fait via le fichier /etc/environment en y ajoutant la ligne suivante :
DOCKER_CONTENT_TRUST=1
Il est à noter que cette sécurité peut être contourner si l'utilisateur à la possibilité de manipuler la commande "docker run". En effet, il est en mesure d'utiliser l'argument "--disable-content-trust" visant à exécuter une image non trustée.
Ajout de l'option no-new-privileges
TODO: https://www.projectatomic.io/blog/2016/03/no-new-privs-docker/ Est-ce que cette option est viable ?
Renforcement des containers
Développement des images
Création d'un utilisateur pour le container
L'utilisation de l'utilisateur root au sein d'un container revient à lui donner les mêmes droits que l'utilisateur root de l'hôte, notamment sur les volumes partagés. Si le noyau de l'hôte contient une vulnérabilité, il est possible pour un utilisateur root de sortir du container très facilement. Lors du développement d'une image, il est par conséquent interdit de lancer les processus en tant qu'utilisateur root ou à l'aide d'un utilisateur ayant l'UID 0. Il est possible de définir l'utilisateur de l'image à l'aide du statement USER dans un fichier Dockerfile.
Cette configuration peut être renforcé par l'utilisation des user namespaces
Ajout d'instructions HEALTHCHECK
Dans un fichier Dockerfile, il est possible de définir des instructions HEALTHCHECK visant à donner les moyens au démons de docker de tester la bonne exécution du container. Par exemple, il est possible d'utiliser ce type de test:
HEALTHCHECK --interval=20s --timeout=3s CMD curl -f http://localhost:8000/ || exit 1
Dans le cas présent, la commande de test s'exécute toutes les 20secondes et vérifie que l'adresse "http://localhost:8000/" est accessible. Si celle-ci ne l'est pas ou si elle met plus de trois secondes à répondre (timeout=3s), alors le container est considéré comme unhealthy.
Identifiants stockés dans l'image
Les identifiants utilisés pour le fonctionnement de l'image ne doivent pas être défini "en dur" dans l'image. En effet, n'importe quel attaquant réussissant à accéder à cette image serait en mesure de récupérer les identifiants stockés dans l'image. Il est demandé d'au moins passer ces paramètre à l'aide de variables d'environnements. Néanmoins cette solution implique que les identifiants changent dès que possible.
Une mesure plus sécurisée consiste à utiliser des coffres forts comme Vault, Crypt, ou Sneaker afin de protéger les mots de passe.
Commandes | Description |
---|---|
$ docker run -e MYSQL_ROOT_PASSWORD=toto mysql:latest | Crée un container à partir de l'image mysql avec une variable d'environnement MYSQL_ROOT_PASSWORD défini à toto. |
Test via l'outil Anchore
todo
Exécution des containers
Validation des images de production
Les images utilisées pour l'exécution de l'environnement de production doivent être validées par l'équipe SSI avant leur mise en production. Ces images ne peuvent pas être validées si elles ne passe pas à minima les tests Anchore (Voir Test via l'outil Anchore).
Limitation des ressources
Par défaut un container n'est pas limité au niveau des ressources de l'hôte. Si un des containers est attaqué ou s'il rencontre une erreur inattendue, il peut se mettre à monopoliser l'ensemble des ressources de l'hôte et entraine un déni de service des autres services de la machine. Il est donc demandé que chaque containers définissent clairement les limitations suivantes avant exécution :
- Mémoire maximum
- Nombre de CPU
Il est possible via ulimits d'ajouter des restriction concernant l'écriture du disque et le nombre de processus autorisés.
Commandes | Description |
---|---|
$ docker run --cpu=2 nginx | Limite le container à 2 vCPU. |
$ docker run --memory=128m nginx | Limite le container à 128Mo de mémoire. |
Volumes partagés en lecture seule
Les volumes permettre de partager des fichiers ou dossiers entre un hôte et un container. Ce lien peut induire l'écrasement de fichier ou l'injection de backdoor sur l'hôte. Il est donc demandé de créer des volumes en lecture seule dès que possible. Les volumes doivent aussi être restreint au minimum possible.
Commandes | Description |
---|---|
$ docker run -v /etc/localtime:/etc/localtime:ro nginx | Partage le fichier /etc/localtime avec le container nginx, mais en lecture uniquement. |
Utilisation de réseaux dédiée
Par défaut les containers peuvent tous communiqués entre eux via le réseau docker interne. Cette pratique permet à un pirate de rebondir entre les containers, même si les ports ne sont pas explicitement ouverts. Il est donc demandé de créer un réseau dédié par container ou groupe d'application. Cette mesure vient en complément du retrait des ICC.
Exposition des ports au strict minimum
Seul les ports nécessaire au fonctionnement de l'applicatif doivent être exposé par le container.
N’utiliser jamais l’option -P (en majuscule), préférez l’option -p (en minuscule) qui permet mapper les ports un par un.
Limitation du nombre de redémarrage
Il est recommandé de limiter les redémarrages du container en cas de plantage à un nombre convenable.
Commandes | Description |
---|---|
docker run -d -restart on-failure:5 nginx | Redémarre le service nginx jusqu'à 5 fois en cas de plantage puis se coupe |
Maintien des containers
Mis à jours des images
Les containers sont à l'origine utilisés pour un fonctionnement à court terme et dans l'idée d'être "jetable". Cette philosophie n'est, aujourd'hui, plus respectée. Par conséquent, il est important de définir une politique de mises à jour régulières des images et des containers.
Mis à jours du sytème
Ça peux paraître évident, mais que ce soit votre système linux, le kernel ou Docker Engine, assurez-vous que votre système soit bien à jour.
Cela passe par les mesures de renforcement détaillé dans le début du document.
Renforcement de Traefik
Désactivation des protocoles SSL/TLS obsolète
TODO: Désactivation de SSLv3, TLS1.1 et des ciphers osbsolète
Désactivation de l'exposition automatique des containers
TODO: Retirer l'exposition automatique des services.
Ressources
- https://www.sans.org/reading-room/whitepapers/auditing/checklist-audit-docker-containers-37437
- https://blog.adminrezo.fr/2018/01/la-securite-avec-docker-et-les-containers-chapitre-final-le-test-ultime/
- https://w3blog.fr/2016/02/23/docker-securite-10-bonnes-pratiques/
- https://github.com/docker/docker-bench-security
- https://www.nearform.com/blog/securing-docker-containers-on-aws/