Introduction
Nous allons dans cet article, essayer de sécuriser aux mieux nos containeurs dans l’environnement OMV. Nos containeurs s’exécutent dans un environnement isolés et sécurisés, mais la configuration par défaut du ‘daemon‘ et des containeurs présentes des faiblesses. Les containeurs et le daemon docker sont entre autres lancés par défaut en tant que root.
Il existe plusieurs outils qui permettent d’identifier les différents problèmes de sécurités et de configurations dans notre environnement Docker et dans nos containeurs. Nous nous concentrerons sur un seul outils qui balaye globalement les principaux problèmes.
Nous utiliserons dans cet article l’outil github.com/docker/docker-bench-security. Pour l’installation je vous renvoi vers le lien officiel précédant.
Préambule
Installation appArmor et auditd
Les applications ‘AppArmor‘ et ‘auditd’ ne sont pas installés par défaut sur OMV. Nous en aurons besoin dans la suite de l’article. Taper les commandes suivantes pour les installer.
sudo apt-get install auditd
L’outil docker-bench-security
L’outil vas effectuer différents tests découpés en 7 sections. Chaque test pourra retourner 4 évaluations différentes représentées par une couleur (PASS, INFO, NOTE et WARN). Au final, il donnera une note sur 100.
Déplacer vous dans le répertoire d’installation de l’outil et lancer le via la commande :
Après le lancement vous verrez apparaitre différents messages comme ceux de la capture suivante. Vous aurez lors de votre premier lancement beaucoup de point qui vont ressortir en rouge. Nous allons essayez de corriger les ‘WARN’ un par un quand cela est possible. Pour les messages de type ‘INFO’, cela dépendra de votre configuration et de votre environnement Docker. La capture montre la section 1 (‘Host Configuration‘) après correction de tous les problèmes.
Section 1 : sécurisation du ‘Host’
- Point 1.1.1 : L’outil préconise d’installer docker dans une partition séparée. A défaut d’une partition dédiée vous pouvez l’installer sur une disque autre que celui du système. Pour ma part j’ai délocalisé l’installation de Docker en dehors du disque système mais je ne lui ai pas dédiée une partition pour son utilisation.
- Point 1.1.2 : Il est conseillé d’avoir un utilisateur dédié pour l’environnement docker. Reportez vous à l’article création d ‘un utilisateur Docker pour le détail
- Point 1.1.3 : Nous avons installé précédemment le logiciel ‘auditd‘. Nous allons le configurer.
Aller dans le répertoire /etc/audit/ et rajouter le contenu suivant à la fin du fichier ‘audit.rules‘.
-w /usr/bin/dockerd -p rwxa -k docker
-w /etc/docker -p rwxa -k docker
-w /etc/default/docker -p rwxa -k docker
-w /etc/docker/daemon.json -p rwxa -k docker
-w /etc/containerd/config.toml -p rwxa -k docker
-w /srv/disk1/docker_varlib -p rwxa -k docker
-w /usr/lib/systemd/system/docker.service -p rwxa -k docker
-w /usr/lib/systemd/system/docker.socket -p rwxa -k docker
-w /usr/bin/containerd -p rwxa -k docker
-w /usr/bin/containerd-shim -p rwxa -k docker
-w /usr/bin/containerd-shim-runc-v1 -p rwxa -k docker
-w /usr/bin/containerd-shim-runc-v2 -p rwxa -k docker
-w /usr/bin/runc -p rwxa -k docker
-w /run/containerd -p rwxa -k docker
Relancer ensuite ‘auditd‘.
Section 2 : sécurisation du ‘daemon’
La configuration du daemon docker se faire via le fichier ‘daemon.json‘ se trouvant dans le répertoire /etc/docker. Il est par défaut vide ou ne contient qu’une seule ligne si vous avez changer le répertoire d’installation de Docker. Voici le contenu de mon fichier :
Copiez la section suivante dans votre fichier. Cela devrait faire disparaitre la majorité des ‘WARN’ de la section 2.
"debug": false,
"icc": false,
"no-new-privileges": true,
"log-driver": "syslog",
"userland-proxy": false,
"iptables": true,
"live-restore": true
Quelques explications s’imposent :
- icc : Permet d’isoler nativement les dockers entre eux aux niveaux du réseau.
- log-driver : Les logs sont gérés par le démon ‘syslogd’
- userland-proxy et iptables : Les connexions au containeur sont gérés par des regles NAT et plus par le processus interne docker-proxy.
- live-restore : Les containeurs continuent de fonctionner après l’arrêt du daemon docker.
On relance le daemon docker pour prendre en compte les modifications :
Section 4 à 7 : configuration des containeurs
La section 3 ne devrait pas vous retourner à priori de ‘WARN’. Elle concerne la configuration du deamon docker au niveau des droits.
Nous allons attaqués la sécurisation du lancement des containeurs. Vous aurez beaucoup de ‘WARN’ qui vous seront retournés. Vous serez tributaire de l’environnement d’OMV et des images Docker. Pour de nombreux containeurs, vous n’aurez pas d’autres choix que de les laisser avec les droits administrateurs.
La sécurisation se fait au niveau de la ‘stack’ du containeur. Prenons comme exemple la pile ‘apache’ qui est compatible avec une sécurité maximum. J’ai mis en gras les modifications effectuées à la pile pour la sécuriser.
Rentrons dans le détails :
- restart : J’ai remplacé les ‘unless-stopped’ par des par ‘on-failure:5’, cela évite le containeur de se relancer à l’infini en cas de problème. Il essayera 5 fois et en cas d’échec stoppera.
- Port : Sans indication d’adresse IP, l’interface d’entrée du containeur écoute toutes les IP 0.0.0.0. Il faut Préfixer l’adresse IP d’entré du containeur par celui de votre NAS.
- pids_limit : Par défaut un containeur peut lancer une infinité de processus. On le limite à 100 par sécurité. Certains containeurs comme ‘swag‘ peuvent dépasser cette limite. Le mettre à 500 dans ce cas.
- mem_limit : Par défaut le containeur peut utiliser toute la mémoire de l’UC. Il faut lui limiter l’accès à la mémoire par sécurité. Vous pouvez voir la consommation en tant réel de tous vos containeurs via la commande ‘sudo docker stats‘. Limiter votre mémoire par containeur en conséquence. Par exemple pour ma configuration :
-
cpu_s : Par défaut un containeur peut prendre 100% de la charge de tous les cœurs du CPU. Ici on lui indique qu’on limite le containeur à un demi cœur. Par exemple si votre CPU à 4 cœurs, le max de cpu_s sera 4.
-
cpu_shares : Ce paramètre sert à prioriser les processus entre eux. La valeur par défaut est 1024. Mettez une valeur < 1024 pour les containeurs qui demande peu d’utilisation CPU et qui ne sont pas prioritaire.
-
user : Indique au containeur de se lancer non plus en tant que root mais seulement avec les droits utilisateurs suivant (UID:GID). Cela devrait être le fonctionnement normal des containeurs mais comme je l’avais indiqué plus haut ce n’est malheureusement pas possible pour beaucoup d’images qui demande d’être lancé en tant que root pour fonctionner correctement. Même en ‘bidouillant’ la config, cela ne passe pas.
-
cap_drop : Par défaut le containeur est lancé avec tous les privilèges (chown, setuid, setgid….). ici on bloque tous les privilèges. Il faut tester au cas par cas et affiner en conséquence. Je vous renvoi à la documentation officiel pour le détails des privilèges.
-
security_opt : Nous avons installé ‘apparmor‘ précédemment qui n’est présent ‘complétement’ dans OMV. Le containeur se lance par défaut avec le profil ‘docker-default’ générique mais je n’ai trouvé aucune trace de se profil de configuration. Je l’ai donc récupéré et mis dans le répertoire de configuration /etc/apparmor.d/. Voici son contenu :
#include <tunables/global> profile docker-default flags=(attach_disconnected,mediate_deleted) { #include <abstractions/base> network, capability, file, umount, deny @{PROC}/{*,**^[0-9*],sys/kernel/shm*} wkx, deny @{PROC}/sysrq-trigger rwklx, deny @{PROC}/mem rwklx, deny @{PROC}/kmem rwklx, deny @{PROC}/kcore rwklx, deny mount, deny /sys/[^f]*/** wklx, deny /sys/f[^s]*/** wklx, deny /sys/fs/[^c]*/** wklx, deny /sys/fs/c[^g]*/** wklx, deny /sys/fs/cg[^r]*/** wklx, deny /sys/firmware/efi/efivars/** rwklx, deny /sys/kernel/security/** rwklx, }
Vous pouvez créer votre propre profil ou essayer d’en trouvez sur Internet (on peut en trouver un pour nginx par exemple), mais cela reste hors cadre de cet article.
Pour voir le statut de tous les profils chargés, taper les commandes suivantes :
sudo aa-status
-
read_only : Permet de mettre en lecture seul les fichiers systèmes du containeur.
-
volumes : dans cet exemple j’ai rajouté une directive pour permettre l’écriture dans /var/run/apache2 qui est bloqué avec la direction ‘read_only’ précédente.
version: "3" services: apache: image: php:apache container_name: apache_yannickinformatik restart: on-failure:5 ports: - 192.168.1.8:8901:80 pids_limit: 100 mem_limit: 100m cpus: 0.5 cpu_shares: 512 user: 1003:100 # A adapter cap_drop: # A adapter - ALL security_opt: - apparmor=docker-default read_only: true # A adapter environment: - PUID=1003 - PGID=100 - TZ=Europe/Paris volumes: - /srv/disk1/docker/apache:/var/www/html:rw - /var/run/apache2
Vous pouvez pour tous vos containeurs rajouter ces directives en adaptant les paramètres mémoire et CPU. Par contre pour les 3 directives avec un commentaire, il faudra essayer tel quel ou en adaptant (voir les directives ‘tmpfs‘ qui peuvent aider) en vérifiant les logs après chaque modification.
En sécurisant aux mieux vos containeurs, vous devriez pouvoir atteindre un score proche des 50 avec le script ‘docker-bench-security‘.