Isoler les conteneurs avec un namespace utilisateur
Les namespaces Linux fournissent une isolation pour les processus en cours d'exécution, limitant leur accès aux ressources système sans que le processus en cours d'exécution soit conscient des limitations. Pour plus d'informations sur les namespaces Linux, voir Namespaces Linux.
Le meilleur moyen de prévenir les attaques d'escalade de privilèges depuis l'intérieur d'un conteneur est
de configurer les applications de votre conteneur pour qu'elles s'exécutent en tant qu'utilisateurs non privilégiés. Pour
les conteneurs dont les processus doivent s'exécuter en tant qu'utilisateur root
dans le conteneur, vous
pouvez remapper cet utilisateur vers un utilisateur moins privilégié sur l'hôte Docker. L'utilisateur mappé
se voit attribuer une plage d'UIDs qui fonctionnent dans le namespace comme des
UIDs normaux de 0 à 65536, mais n'ont aucun privilège sur la machine hôte elle-même.
À propos du remappage et des IDs d'utilisateur et de groupe subordonnés
Le remappage lui-même est géré par deux fichiers : /etc/subuid
et /etc/subgid
.
Chaque fichier fonctionne de la même manière, mais l'un concerne la plage d'ID utilisateur, et
l'autre la plage d'ID de groupe. Considérez l'entrée suivante dans /etc/subuid
:
testuser:231072:65536
Cela signifie que testuser
se voit attribuer une plage d'ID utilisateur subordonné de 231072
et les 65536 entiers suivants en séquence. L'UID 231072
est mappé dans le
namespace (dans le conteneur, dans ce cas) comme UID 0
(root
). L'UID 231073
est mappé comme UID 1
, et ainsi de suite. Si un processus tente d'escalader les privilèges
en dehors du namespace, le processus s'exécute comme un UID de nombre élevé non privilégié
sur l'hôte, qui ne mappe même pas vers un utilisateur réel. Cela signifie que le processus
n'a aucun privilège sur le système hôte du tout.
NoteIl est possible d'attribuer plusieurs plages subordonnées pour un utilisateur ou groupe donné en ajoutant plusieurs mappages non chevauchants pour le même utilisateur ou groupe dans les fichiers
/etc/subuid
ou/etc/subgid
. Dans ce cas, Docker n'utilise que les cinq premiers mappages, conformément à la limitation du noyau de seulement cinq entrées dans/proc/self/uid_map
et/proc/self/gid_map
.
Lorsque vous configurez Docker pour utiliser la fonctionnalité userns-remap
, vous pouvez optionnellement
spécifier un utilisateur et/ou groupe existant, ou vous pouvez spécifier default
. Si vous
spécifiez default
, un utilisateur et groupe dockremap
est créé et utilisé à cette fin.
WarningCertaines distributions n'ajoutent pas automatiquement le nouveau groupe aux fichiers
/etc/subuid
et/etc/subgid
. Si c'est le cas, vous devrez peut-être modifier manuellement ces fichiers et attribuer des plages non chevauchantes. Cette étape est couverte dans Prérequis.
Il est très important que les plages ne se chevauchent pas, afin qu'un processus ne puisse pas obtenir l'accès dans un namespace différent. Sur la plupart des distributions Linux, les utilitaires système gèrent les plages pour vous lorsque vous ajoutez ou supprimez des utilisateurs.
Ce remappage est transparent pour le conteneur, mais introduit une certaine complexité de configuration dans les situations où le conteneur a besoin d'accéder aux ressources sur l'hôte Docker, telles que les montages de liaison dans des zones du système de fichiers que l'utilisateur système ne peut pas écrire. Du point de vue de la sécurité, il est préférable d'éviter ces situations.
Prérequis
-
Les plages UID et GID subordonnées doivent être associées à un utilisateur existant, même si l'association est un détail d'implémentation. L'utilisateur possède les répertoires de stockage namespacés sous
/var/lib/docker/
. Si vous ne voulez pas utiliser un utilisateur existant, Docker peut en créer un pour vous et l'utiliser. Si vous voulez utiliser un nom d'utilisateur ou ID utilisateur existant, il doit déjà exister. Typiquement, cela signifie que les entrées pertinentes doivent être dans/etc/passwd
et/etc/group
, mais si vous utilisez un back-end d'authentification différent, cette exigence peut se traduire différemment.Pour vérifier cela, utilisez la commande
id
:$ id testuser uid=1001(testuser) gid=1001(testuser) groups=1001(testuser)
-
La façon dont le remappage de namespace est géré sur l'hôte utilise deux fichiers,
/etc/subuid
et/etc/subgid
. Ces fichiers sont typiquement gérés automatiquement lorsque vous ajoutez ou supprimez des utilisateurs ou groupes, mais sur certaines distributions, vous devrez peut-être gérer ces fichiers manuellement.Chaque fichier contient trois champs : le nom d'utilisateur ou ID de l'utilisateur, suivi d'un UID ou GID de début (qui est traité comme UID ou GID 0 dans le namespace) et un nombre maximum d'UIDs ou GIDs disponibles pour l'utilisateur. Par exemple, étant donné l'entrée suivante :
testuser:231072:65536
Cela signifie que les processus namespacés utilisateur démarrés par
testuser
sont possédés par l'UID hôte231072
(qui ressemble à l'UID0
à l'intérieur du namespace) jusqu'à 296607 (231072 + 65536 - 1). Ces plages ne devraient pas se chevaucher, pour s'assurer que les processus namespacés ne peuvent pas accéder aux namespaces les uns des autres.Après avoir ajouté votre utilisateur, vérifiez
/etc/subuid
et/etc/subgid
pour voir si votre utilisateur a une entrée dans chacun. Sinon, vous devez l'ajouter, en faisant attention à éviter le chevauchement.Si vous voulez utiliser l'utilisateur
dockremap
créé automatiquement par Docker, vérifiez l'entréedockremap
dans ces fichiers après avoir configuré et redémarré Docker. -
S'il y a des emplacements sur l'hôte Docker où l'utilisateur non privilégié doit écrire, ajustez les permissions de ces emplacements en conséquence. Ceci est également vrai si vous voulez utiliser l'utilisateur
dockremap
créé automatiquement par Docker, mais vous ne pouvez pas modifier les permissions jusqu'après avoir configuré et redémarré Docker. -
L'activation de
userns-remap
masque effectivement les couches d'image et de conteneur existantes, ainsi que d'autres objets Docker dans/var/lib/docker/
. C'est parce que Docker doit ajuster la propriété de ces ressources et les stocke en fait dans un sous-répertoire dans/var/lib/docker/
. Il est préférable d'activer cette fonctionnalité sur une nouvelle installation Docker plutôt que sur une existante.Dans la même ligne, si vous désactivez
userns-remap
vous ne pouvez pas accéder à aucune des ressources créées pendant qu'elle était activée. -
Vérifiez les limitations sur les namespaces utilisateur pour vous assurer que votre cas d'usage est possible.
Activer userns-remap sur le démon
Vous pouvez démarrer dockerd
avec le flag --userns-remap
ou suivre cette
procédure pour configurer le démon en utilisant le fichier de configuration daemon.json
.
La méthode daemon.json
est recommandée. Si vous utilisez le flag, utilisez la
commande suivante comme modèle :
$ dockerd --userns-remap="testuser:testuser"
-
Modifiez
/etc/docker/daemon.json
. En supposant que le fichier était précédemment vide, l' entrée suivante activeuserns-remap
en utilisant un utilisateur et groupe appelétestuser
. Vous pouvez adresser l'utilisateur et le groupe par ID ou nom. Vous n'avez besoin de spécifier le nom ou ID de groupe que s'il est différent du nom ou ID utilisateur. Si vous fournissez à la fois le nom ou ID utilisateur et groupe, séparez-les par un caractère deux-points (:
). Les formats suivants fonctionnent tous pour la valeur, en supposant que l'UID et GID de
testusersont
1001` :testuser
testuser:testuser
1001
1001:1001
testuser:1001
1001:testuser
{ "userns-remap": "testuser" }
NotePour utiliser l'utilisateur
dockremap
et laisser Docker le créer pour vous, définissez la valeur àdefault
plutôt quetestuser
.Sauvegardez le fichier et redémarrez Docker.
-
Si vous utilisez l'utilisateur
dockremap
, vérifiez que Docker l'a créé en utilisant la commandeid
.$ id dockremap uid=112(dockremap) gid=116(dockremap) groups=116(dockremap)
Vérifiez que l'entrée a été ajoutée à
/etc/subuid
et/etc/subgid
:$ grep dockremap /etc/subuid dockremap:231072:65536 $ grep dockremap /etc/subgid dockremap:231072:65536
Si ces entrées ne sont pas présentes, modifiez les fichiers en tant qu'utilisateur
root
et attribuez un UID et GID de départ qui est le plus élevé attribué plus le décalage (dans ce cas,65536
). Faites attention à ne pas permettre de chevauchement dans les plages. -
Vérifiez que les images précédentes ne sont pas disponibles en utilisant la commande
docker image ls
. La sortie devrait être vide. -
Démarrez un conteneur à partir de l'image
hello-world
.$ docker run hello-world
-
Vérifiez qu'un répertoire namespacé existe dans
/var/lib/docker/
nommé avec l'UID et GID de l'utilisateur namespacé, possédé par cet UID et GID, et non lisible par le groupe ou le monde. Certains des sous-répertoires sont encore possédés parroot
et ont des permissions différentes.$ sudo ls -ld /var/lib/docker/231072.231072/ drwx------ 11 231072 231072 11 Jun 21 21:19 /var/lib/docker/231072.231072/ $ sudo ls -l /var/lib/docker/231072.231072/ total 14 drwx------ 5 231072 231072 5 Jun 21 21:19 aufs drwx------ 3 231072 231072 3 Jun 21 21:21 containers drwx------ 3 root root 3 Jun 21 21:19 image drwxr-x--- 3 root root 3 Jun 21 21:19 network drwx------ 4 root root 4 Jun 21 21:19 plugins drwx------ 2 root root 2 Jun 21 21:19 swarm drwx------ 2 231072 231072 2 Jun 21 21:21 tmp drwx------ 2 root root 2 Jun 21 21:19 trust drwx------ 2 231072 231072 3 Jun 21 21:19 volumes
Votre liste de répertoires peut avoir quelques différences, surtout si vous utilisez un pilote de stockage de conteneur différent de
aufs
.Les répertoires qui sont possédés par l'utilisateur remappé sont utilisés à la place des mêmes répertoires directement sous
/var/lib/docker/
et les versions inutilisées (comme/var/lib/docker/tmp/
dans l'exemple ici) peuvent être supprimées. Docker ne les utilise pas tant queuserns-remap
est activé.
Désactiver le remappage de namespace pour un conteneur
Si vous activez les namespaces utilisateur sur le démon, tous les conteneurs sont démarrés avec les namespaces utilisateur activés par défaut. Dans certaines situations, comme les conteneurs privilégiés, vous pourriez avoir besoin de désactiver les namespaces utilisateur pour un conteneur spécifique. Voir limitations connues des namespaces utilisateur pour certaines de ces limitations.
Pour désactiver les namespaces utilisateur pour un conteneur spécifique, ajoutez le flag --userns=host
à la commande docker container create
, docker container run
, ou docker container exec
.
Il y a un effet de bord lors de l'utilisation de ce flag : le remappage utilisateur ne sera pas activé pour ce conteneur mais, parce que les couches (image) en lecture seule sont partagées entre les conteneurs, la propriété du système de fichiers du conteneur sera toujours remappée.
Ce que cela signifie est que tout le système de fichiers du conteneur appartiendra à l'utilisateur spécifié dans la configuration de démon --userns-remap
(231072
dans l'exemple ci-dessus). Cela peut conduire à un comportement inattendu des programmes à l'intérieur du conteneur. Par exemple sudo
(qui vérifie que ses binaires appartiennent à l'utilisateur 0
) ou les binaires avec un flag setuid
.
Limitations connues des namespaces utilisateur
Les fonctionnalités Docker standard suivantes sont incompatibles avec l'exécution d'un démon Docker avec les namespaces utilisateur activés :
- Partage des namespaces PID ou NET avec l'hôte (
--pid=host
ou--network=host
). - Pilotes externes (volume ou stockage) qui ne sont pas conscients ou incapables d'utiliser les mappages utilisateur du démon.
- Utilisation du flag de mode
--privileged
surdocker run
sans aussi spécifier--userns=host
.
Les namespaces utilisateur sont une fonctionnalité avancée et nécessitent une coordination avec d'autres capacités. Par exemple, si des volumes sont montés depuis l'hôte, la propriété des fichiers doit être pré-arrangée si vous avez besoin d'un accès en lecture ou écriture au contenu du volume.
Bien que l'utilisateur root à l'intérieur d'un processus de conteneur namespacé utilisateur ait beaucoup des
privilèges attendus du superutilisateur dans le conteneur, le noyau Linux
impose des restrictions basées sur la connaissance interne que c'est un processus namespacé
utilisateur. Une restriction notable est l'incapacité d'utiliser la commande mknod
.
La permission est refusée pour la création de périphérique dans le conteneur lorsqu'il est exécuté par
l'utilisateur root
.