Notion de propriétaire des fichiers dans un conteneur Docker

Vue d’ensemble

Dans ce tutoriel, nous allons étudier la propriété des fichiers et des dossiers montés dans un conteneur Docker. Plus particulièrement, nous verrons comment la notion de propriété des fichiers change lorsque nous montons des fichiers de l’hôte vers le conteneur.

Différence entre les permissions des fichiers de l’hôte et ceux du conteneur

Prenons l’exemple du problème en montant un dossier composé de fichiers et de répertoires dans un conteneur Docker. Tout d’abord, nous allons créer un répertoire qui servira de point de montage sur l’hôte :

$ mkdir repertoire-a-monter

Ensuite, nous allons créer des fichiers et des répertoires et les placer dans le dossier repertoire-a-monter. Enfin, nous exécuterons la commande suivante pour obtenir leurs informations de propriété :

$ ls -l repertoire-a-monter 
total 4
drwxrwxr-x 2 yagnilabs yagnilabs 4096 Dec 27 08:48 repertoire-interne
-rw-rw-r-- 1 yagnilabs yagnilabs    0 Dec 27 08:48 log1.txt
-rw-rw-r-- 1 yagnilabs yagnilabs    0 Dec 27 08:48 log2.txt

Du point de vue de l’hôte, nous pouvons voir que chaque fichier et dossier du repertoire-a-monter appartient à l’utilisateur yagnilabs, qui est l’utilisateur qui a créé ces fichiers et dossiers.

Ensuite, nous démarrons un conteneur Docker exécutant l’image Ubuntu, en montant le dossier repertoire-a-monter dans le chemin /opt/mount :

$ sudo docker run -it -v /home/yagnilabs/repertoire-a-monter:/opt/mount ubuntu:latest sh

À l’intérieur du conteneur, nous pouvons vérifier les informations relatives au titulaire des fichiers et des dossiers montés à l’aide de la même commande :

# ls -l /opt/mount
total 4
drwxrwxr-x    2 1000     1000          4096 Dec 27 07:48 repertoire-interne
-rw-rw-r--    1 1000     1000             0 Dec 27 07:48 log1.txt
-rw-rw-r--    1 1000     1000             0 Dec 27 07:48 log2.txt

Curieusement, le propriétaire des mêmes fichiers et dossiers est maintenant l’utilisateur 1000 au lieu de yagnilabs comme dans l’hôte.

Comprendre le fonctionnement de l’ID utilisateur sous Linux

Sous Linux, tous les utilisateurs ont un identifiant (uid) associé. Par exemple, l’utilisateur root a un uid de 0. Pour vérifier l’uid d’un utilisateur, nous pouvons exécuter la commande :

id -u yagnilabs
1000

Lorsque Linux stocke les informations relatives au propriétaire des fichiers et des répertoires, il stocke l’uid de l’utilisateur en interne.

Pour afficher le nom d’utilisateur lorsque nous invoquons la commande ls -l, une recherche est effectuée dans le fichier /etc/passwd pour faire correspondre l’uid à un nom d’utilisateur. De même, lorsque nous changeons le propriétaire des fichiers à l’aide de chown, la commande consulte le /etc/passwd pour obtenir l’uid d’un identifiant donné. Il est intéressant de noter que, puisque le nom d’utilisateur est redondant du point de vue de la propriété des fichiers, nous pouvons changer le propriétaire des fichiers en uid qui n’est possédé par aucun utilisateur dans le fichier /etc/passwd.

Par exemple, on pourrait chown le fichier à uid 9585, qui n’appartient à aucun utilisateur du système :

$ id -nu 9585
id: ‘9585’: no such user
$ sudo chown 9585:9585 repertoire-a-monter
$ ls -l
total 4
drwxrwxr-x 3 9585 9585 4096 Dec 27 08:48 repertoire-a-monter

Au contraire, changer des fichiers ou des dossiers en utilisant des noms d’utilisateurs inexistants ne va pas fonctionner. C’est parce que le nom d’utilisateur ne correspondra à aucun uid valide, empêchant ainsi Linux de définir les bits de permissions sur les fichiers :

$ sudo chown blob:blob repertoire-a-monter
chown: invalid user: ‘blob:blob’

Pour expliquer la différence entre les fichiers montés, nous devons simplement admettre que le conteneur Docker maintient une copie indépendante de /etc/passwd. En d’autres termes, l’uid 1000 sur l’hôte ne se traduit pas par le même nom d’utilisateur dans le conteneur. En fait, le nom d’utilisateur qui existe sur l’hôte n’existe pas dans le conteneur Docker, à moins qu’il ne soit explicitement créé. C’est pourquoi nous voyons les fichiers comme appartenant à uid 1000 au lieu de yagnilabs parce que yagnilabs n’existe pas dans le /etc/passwd du conteneur.

Solution de contournement

Une façon simple de résoudre ce problème est de s’assurer que le même utilisateur apparaît également dans le fichier /etc/passwd du conteneur avec le même uid.

Créer un utilisateur avec le même UID dans un conteneur

Depuis le conteneur, on peut créer un utilisateur avec un uid spécifique en utilisant la commande useradd avec le paramètre -u. Par exemple, à l’intérieur du conteneur, nous pouvons créer un utilisateur yagnilabs avec l’uid 1000.

# useradd yagnilabs -u 1000

Une fois que nous avons créé l’utilisateur, les fichiers et dossiers montés afficheront yagnilabs comme propriétaire :

# ls -l /opt/mount
total 4
drwxrwxr-x    2 yagnilabs     yagnilabs          4096 Dec 27 07:48 repertoire-interne
-rw-rw-r--    1 yagnilabs     yagnilabs             0 Dec 27 07:48 log1.txt
-rw-rw-r--    1 yagnilabs     yagnilabs             0 Dec 27 07:48 log2.txt

L’inconvénient de cette solution est qu’au moment de la création du conteneur, nous devrons exécuter à nouveau la commande.

Personnaliser l’image avec Dockerfile

Nous pouvons placer le script dans un Dockerfile et l’intégrer à l’image elle-même. Par exemple, nous pourrions mettre la commande qui crée l’utilisateur yagnilabs avec l’uid 1000 dans le Dockerfile :

FROM ubuntu:latest

RUN useradd yagnilabs -u 1000

Nous pouvonNous pouvons également paramétrer la valeur uid à l’aide d’une variable d’environnement en utilisant la directive ARG Dockerfile. Au moment de la construction, nous transmettrons la valeur en utilisant le paramètre -build-arg. Il suffit pour cela de changer la valeur 1000 par une variable d’environnement :

FROM ubuntu:latest

ARG HOST_UID

RUN useradd yagnilabs -u $HOST_UID

En utilisant la directive ARG, nous pouvons définir une variable qui sera transmise lors de la génération de l’image. Ensuite, nous pouvons exécuter la commande docker build en spécifiant le paramètre -build-arg :

sudo docker build --build-arg HOST_UID=$(id -u) --tag ubuntu-custom:latest .

La commande id -u renvoie simplement l’uid de l’utilisateur actuel, puis la valeur est définie dans l’argument de build HOST_UID.

Résumé

Dans ce tutoriel, nous avons abordé rapidement la question de la propriété des fichiers montés. En particulier, nous avons vu comment les fichiers qui sont montés verront leur propriétaire modifié. Ensuite, nous avons expliqué la relation de correspondance entre le nom d’utilisateur et l’uid à travers le fichier /etc/passwd. Enfin, nous avons montré des solutions de contournement pour résoudre cette différence.

Laisser un commentaire