Debian-facile

Bienvenue sur Debian-Facile, site d'aide pour les nouveaux utilisateurs de Debian.

Vous n'êtes pas identifié(e).


L'icône rouge permet de télécharger chaque page du wiki visitée au format PDF et la grise au format ODT → ODT PDF Export

Utilisation de LXC en mode utilisateur non-privilégié

  • Objet : Utiliser LXC sans être root, et lancer des instances non-root
  • Niveau requis :
  • Commentaires : Des conteneurs sécurisés.
  • Suivi :
    • Création par captnfab 09/12/2015
    • Testé par captnfab le 09/12/2015
  • Commentaires sur le forum : ici 1)

Nota :

Contributeurs, les FIXME sont là pour vous aider, supprimez-les une fois le problème corrigé ou le champ rempli !

Introduction

Si vos conteneurs LXC doivent contenir des serveurs sensibles aux attaques, vous ne voudriez pas qu'un serveur compromis compromette tout le reste du système. Ne pas donner les privilèges super-utilisateur au conteneur permet de limiter ce risque.

Installation

Les outils de gestion lxc :

apt-get install lxc cgmanager uidmap

D'autres outils normalement présents par défaut :

apt-get install libpam-systemd cgroup-bin bridge-utils

Et des outils de débuggage :

apt-get install less

Préparation

Nous allons créer un conteneur Test, qui appartiendra à l'utilisateur lxcuser-test, et accèdera au réseau via le pont lxcbr0. Cette opération sera à répéter pour chaque utilisateur devant pouvoir créer un ou plusieurs conteneurs. C'est la seule partie du tutoriel qui doit nécessairement être effectuée en root.

Création et configuration de l'utilisateur

Création de l'utilisateur

adduser --disabled-password lxcuser-test

L'option --disabled-password n'est pas obligatoire, elle permet simplement de s'assurer que la connexion par mot de passe est impossible via ssh.

Comme vous devrez vous connecter à cet utilisateur via ssh, je vous conseille de créer dès maintenant une paire de clefs via ssh-keygen, et de rajouter la clef publique aux clefs autorisées pour cet utilisateur.

Identification d'une plage d'uid/gid libre

cat /etc/subuid

Exemple :

nm-openvpn:100000:65536
pulse:165536:65536
mpd:231072:65536
geoclue:296608:65536
systemd-timesync:362144:65536
systemd-network:427680:65536
systemd-resolve:493216:65536
systemd-bus-proxy:558752:65536

Chaque ligne du fichier commence par un nom d'utilisateur, suivi par un numéro d'uid et d'un nombre d'uid. Par exemple, ici, il faut comprendre que les uid 100000 à 165535 sont des sous-uid dépendant de l'utilisateur nm-openvpn. Voir le man

man subuid

Dans notre exemple, le premier uid de libre est le 558752+65536=624288, donc notre utilisateur utilisera la plage d'uuid 624288 à 689823 (624288+65535). Nous faisons ensuite la même opération pour les gid, en consultant /etc/subgid. Dans notre exemple, on considèrera que le fichier /etc/subgid est identique au fichier /etc/subuid, ce qui est en général le cas.

Affectation des sous-{u,g}id à l'utilisateur

Nous allouons alors les sous-uid et sous-gid à l'utilisateur test via la commande (à modifier en fonction de vos propres /etc/sub{u,g}id !) :

usermod lxcuser-test --add-subuids 624288-689823 --add-subgids 624288-689823

Création et configuration de l'accès au pont réseau

Création du pont

brctl addbr lxcbr0

(Penser à automatiser sa création, par exemple via le fichier /e/n/interfaces ou via Network-Manager)

Accès

On autorise l'utilisateur lxcuser-test à connecter une interface ethernet virtuelle au port (vous pouvez augmenter ce nombre selon vos besoins, fichier à créer) :

/etc/lxc/lxc-usernet
lxcuser-test veth lxcbr0 1

Configuration cgroups

Ceci n'est pas nécessaire sous Ubuntu, qui intègre des patchs spéciaux pour que ça marche d'entrée de jeu (mais cause des problèmes dans d'autres situations, comme par exemple l'utilisation d'un noyau RT.)

Créons les fichiers suivants :

/usr/local/etc/lxc-cgroups-users
# Liste des utilisateurs pouvant lancer des lxc
LXCUSERS="lxcuser-test"
/usr/local/sbin/prepare-lxc-cgroups
#!/bin/bash
 
source /usr/local/etc/lxc-cgroups-users
 
echo 1 > /sys/fs/cgroup/cpuset/cgroup.clone_children
echo 1 > /proc/sys/kernel/unprivileged_userns_clone
 
for u in $LXCUSERS
do
  cgm create all $u
  cgm chown all $u $(id -u $u) $(id -g $u)
done
/etc/systemd/system/lxc-cgroups.service
[Unit]
Description=Préparation cgroups pour lxc
After=local-fs.target cgmanager.service
Requires=cgmanager.service
 
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/prepare-lxc-cgroups
 
[Install]
WantedBy=multi-user.target
chmod a+x /usr/local/sbin/prepare-lxc-cgroups
systemctl enable /etc/systemd/system/lxc-cgroups.service
systemctl start lxc-cgroups

Création du conteneur

Il existe plusieurs méthodes pour installer une Debian/Ubuntu/Whatever dans un dossier. L'ennui est que la plupart requiert les droits super-utilisateurs pour lancer debootstrap. Ceci-dit, cette opération n'est a priori à faire qu'une fois, et l'alternative n'est pas forcément réjouissante. Nous présentons les deux possibilités les plus intéressantes.

Méthode template download

Le code à faire en tant qu'utilisateur est à faire en tant que lxcuser-test.

Configuration des options par défaut

Dans le dossier ~lxcuser-test/.config/lxc/ (probablement à créer), créer un fichier default.conf contenant la configuration suivante :

~lxcuser-test/.config/lxc/default.conf
lxc.network.type = veth
lxc.network.link = lxcbr0
lxc.network.flags = up
# À compléter pour définir une adresse mac
#lxc.network.hwaddr = 00:16:3e:xx:xx:xx
lxc.id_map = u 0 624288 65536
lxc.id_map = g 0 624288 65536

Remplacer 624288 sur les deux dernières lignes par les valeurs du premier sous-uid/gid alloué à l'utilisateur.

lxc-create -t download -n test -- -d debian

Méthode root + chown

mkdir -p ~/.local/share/lxc
lxc-create -t debian -n test -- -d debian
mv /var/lib/lxc/test ~lxcuser-test/.local/share/lxc/
chown lxcuser-test: ~lxcuser-test/.local/share/lxc/test{,/config,/fstab}
find ~lxcuser-test/.local/share/lxc/test/rootfs/ -exec sh -c 'chown $(echo $(stat -c %u "{}")+624288 | bc):$(echo $(stat -c %g "{}")+624288 | bc) "{}"' \;

En remplaçant 624288 par les numéro initiaux des plages de sous-uid/gid respectifs de votre user.

Configuration du conteneur

Le fichier de configuration ~/.local/share/lxc/test/config doit ressembler à ça :

~/.local/share/lxc/test/config
# For additional config options, please look at lxc.container.conf(5)
 
# Distribution configuration
lxc.include = /usr/share/lxc/config/debian.common.conf
lxc.include = /usr/share/lxc/config/debian.userns.conf
lxc.arch = x86_64
 
lxc.autodev = 0
 
# Container specific configuration
lxc.id_map = u 0 624288 65536
lxc.id_map = g 0 624288 65536
lxc.rootfs = /home/lxcuser-test/.local/share/lxc/test/rootfs
#lxc.mount = /home/lxcuser-test/.local/share/lxc/test/fstab
lxc.utsname = test
 
# Network configuration
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = lxcbr0
#lxc.network.hwaddr = 00:16:3e:xx:xx:xx

Si vous avez utilisé la méthode « root » pour créer le conteneur, il vous faudra compléter votre fichier.

  • Vérifier les lxc.id_map et le include de debian.userns.conf.
  • Les chemins lxc.rootfs et éventuellement lxc.mount doivent être les bons (si vous avez déplacé le dossier du conteneur dans votre home…)
  • Les options lxc.network.* doivent être cohérentes avec ce qui a été indiqué dans /etc/lxc/lxc-usernet :
lxcuser-test veth lxcbr0 1

Les droits des dossiers doivent ressembler à cela :

ls -lhd /home{,/lxcuser-test{,/.local{,/share{,/lxc{,/test}}}}}
drwxr-xr-x 5 root    root    4,0K déc.  17 00:07 /home
drwxr-xr-x 3 lxcuser lxcuser 4,0K déc.  17 00:56 /home/lxcuser-test
drwxr-xr-x 3 lxcuser lxcuser 4,0K déc.  17 00:56 /home/lxcuser-test/.local
drwxr-xr-x 3 lxcuser lxcuser 4,0K déc.  19 13:49 /home/lxcuser-test/.local/share
drwxr-xr-x 3 lxcuser lxcuser 4,0K déc.  19 13:53 /home/lxcuser-test/.local/share/lxc
drwxrwx--x 3 lxcuser lxcuser 4,0K déc.  19 13:51 /home/lxcuser-test/.local/share/lxc/test

(Le o+x est le point crucial ici.)

ls -lh /home/lxcuser-test/.local/share/lxc/test
total 8,0K
-rw-r--r--  1 lxcuser lxcuser  488 déc.  19 13:51 config
-rw-r--r--  1 lxcuser lxcuser    0 déc.  19 13:51 fstab
drwxr-xr-x 22 624288 624288   4,0K déc.  19 13:51 rootfs

(Vérifier les propriétaires suivant ses propres sous-uid/sous-gid.)

Utilisation du conteneur

Ne vous loguez pas en tant que lxcuser-test via su ou sudo, la suite ne fonctionnera pas. Vous devez impérativement vous connecter via ssh ou directement sur un getty. En effet, cgm et lxc-start s'appuient sur les sessions PAM, qui ne sont pas créées via su ou sudo…

cgm movepid all $USER $$
lxc-start -n test -d

Attention, la première commande peut renvoyer une erreur tout en fonctionnant correctement, donc ne pas utiliser &&.

FAQ / Problèmes rencontrés

Messages d'erreur rencontrés en lançant les différentes commandes du tuto, ou encore journalctl -xe

  • lxc_container: Failed to chown /dev/pts/X, lxc_start - start.c:lxc_init:445 - Failed to shift tty into container

Vérifier que le paquet uidmap est bien installé Vérifier que /proc/sys/kernel/unprivileged_userns_clone et /sys/fs/cgroup/cpuset/cgroup.clone_children sont bien à 1

  • lxc_container: failed to clone (0x20000011): Operation not permitted

Vérifier que le fichier de config ~lxcuser-test/.local/share/lxc/test/config contient bien des mappings de sous-uid/sous-gid corrects (exemple) :

lxc.id_map = u 0 820896 65536
lxc.id_map = g 0 820896 65536
  • pam_unix(sudo:auth): conversation failed ou pam_unix(sudo:auth): auth could not identify password for [lxcuser-test] ou lxc-start: Permission denied - failed to create directory '/run/user/1000/lxc/'

Vérifier que l'on s'est bien connecté en tant que lxcuser-test via PAM (par exemple via ssh et non-pas par su/sudo)

  • ERROR lxc_cgfs - Permission denied - Could not create cgroup '/test' in '/sys/fs/cgroup/perf_event'., lxc_container: cgfs.c: lxc_cgroupfs_create: 956 Permission denied - Could not create cgroup '/lxc' in '/sys/fs/cgroup/cpuset'.

Vérifier que nous ne sommes pas à la racine dans les cgroups listés dans /proc/self/cgroup Exemple de config problématique :

8:perf_event:/
7:blkio:/
…
1:name=systemd:/user.slice/user-1001.slice/session-42.scope

Vous devriez plutôt obtenir quelque chose comme

8:perf_event:/lxcuser1/
7:blkio:/lxcuser1/
…
1:name=systemd:/user.slice/user-1001.slice/session-42.scope

Ce problème survient quand libpam-systemd (qui ajoute automatiquement les nouvelles connexions aux bons cgroups) n'est pas installé, où quand les cgroups users ne sont pas créés dans les différents contrôleurs, ce qui est le comportement par défaut sous Debian, mais pas sous Ubuntu. Reportez-vous à la partie du tuto sur les cgroups si vous avez des soucis.

  • lxc_container: cgmanager.c: lxc_cgmanager_enter: 698 call to cgmanager_move_pid_sync failed: invalid request

Muh ? Visiblement, problème avec une version cgmanager trop récente (stretch/sid et non jessie)

  • Quota reached, lxc_start - failed to create the configured network

Vérifier que le mode de connexion renseigné dans /etc/lxc/lxc-usernet existe bien, et que c'est bien celui indiqué dans ~lxcuser-test/.local/share/lxc/test/config.

  • Vérifier que tous les dossiers parents du dossier rootfs sont bien exécutables par Others (ou au moins par le min de la plage de sous-uid correspondante).
  • Vérifier que le fichier ~lxcuser-test/.local/share/lxc/test/config contient bien la ligne lxc.autodev = 0
  • lxc_container: No such file or directory - failed to get real path for '/var/lib/lxc/test/rootfs

Vérifier que le path du rootfs indiqué dans ~lxcuser-test/.local/share/lxc/test/config est bien celui contenant le rootfs du conteneur, donc a priori ~lxcuser-test/.local/share/lxc/test/rootfs

  • lxc_container: Error setting devices.deny to a for test ou lxc_container: failed to setup the devices cgroup for 'test'

Vérifier que le fichier ~lxcuser-test/.local/share/lxc/test/config contient bien la ligne

lxc.include = /usr/share/lxc/config/debian.userns.conf

Sources

1) N'hésitez pas à y faire part de vos remarques, succès, améliorations ou échecs !
doc/autres/vm/lxc/mode-utilisateur.txt · Dernière modification: 03/11/2016 15:33 par bendia

Pied de page des forums

Propulsé par FluxBB