Comment créer des groupes de contrôle utilisateur avec systemd

14

J'utilise des lxcconteneurs non privilégiés dans Arch Linux. Voici les informations de base du système:

[chb@conventiont ~]$ uname -a
Linux conventiont 3.17.4-Chb #1 SMP PREEMPT Fri Nov 28 12:39:54 UTC 2014 x86_64 GNU/Linux

C'est un noyau personnalisé / compilé avec user namespace enabled:

[chb@conventiont ~]$ lxc-checkconfig 
--- Namespaces ---
Namespaces: enabled
Utsname namespace: enabled
Ipc namespace: enabled
Pid namespace: enabled
User namespace: enabled
Network namespace: enabled
Multiple /dev/pts instances: enabled

--- Control groups ---
Cgroup: enabled
Cgroup clone_children flag: enabled
Cgroup device: enabled
Cgroup sched: enabled
Cgroup cpu account: enabled
Cgroup memory controller: enabled
Cgroup cpuset: enabled

--- Misc ---
Veth pair device: enabled
Macvlan: enabled
Vlan: enabled
File capabilities: enabled

Note : Before booting a new kernel, you can check its configuration
usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig

[chb@conventiont ~]$ systemctl --version
systemd 217
+PAM -AUDIT -SELINUX -IMA -APPARMOR +SMACK -SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID -ELFUTILS +KMOD +IDN 

Malheureusement, systemdne joue pas bien avec lxcactuellement. En particulier, la configuration cgroupspour un utilisateur non root ne fonctionne pas bien ou je ne sais pas trop comment faire. lxcdémarre un conteneur en mode non privilégié uniquement lorsqu'il peut créer les groupes de contrôle nécessaires dans /sys/fs/cgroup/XXX/*. Cela n'est cependant pas possible lxccar il systemdmonte la roothiérarchie de groupe de contrôle dans /sys/fs/cgroup/*. Une solution de contournement semble être la suivante:

for d in /sys/fs/cgroup/*; do
        f=$(basename $d)
        echo "looking at $f"
        if [ "$f" = "cpuset" ]; then
                echo 1 | sudo tee -a $d/cgroup.clone_children;
        elif [ "$f" = "memory" ]; then
                echo 1 | sudo tee -a $d/memory.use_hierarchy;
        fi
        sudo mkdir -p $d/$USER
        sudo chown -R $USER $d/$USER
        echo $$ > $d/$USER/tasks
done

Ce code crée les cgrouprépertoires correspondants dans la cgrouphiérarchie pour un utilisateur non privilégié. Cependant, quelque chose que je ne comprends pas se produit. Avant d'exécuter ce qui précède, je verrai ceci:

[chb@conventiont ~]$ cat /proc/self/cgroup 
8:blkio:/
7:net_cls:/
6:freezer:/
5:devices:/
4:memory:/
3:cpu,cpuacct:/
2:cpuset:/
1:name=systemd:/user.slice/user-1000.slice/session-c1.scope

Après avoir exécuté le code susmentionné que je vois dans le shell, je l'ai exécuté:

[chb@conventiont ~]$ cat /proc/self/cgroup 
8:blkio:/chb
7:net_cls:/chb
6:freezer:/chb
5:devices:/chb
4:memory:/chb
3:cpu,cpuacct:/chb
2:cpuset:/chb
1:name=systemd:/chb

Mais dans tout autre shell, je vois toujours:

[chb@conventiont ~]$ cat /proc/self/cgroup 
8:blkio:/
7:net_cls:/
6:freezer:/
5:devices:/
4:memory:/
3:cpu,cpuacct:/
2:cpuset:/
1:name=systemd:/user.slice/user-1000.slice/session-c1.scope

Par conséquent, je peux démarrer mon lxcconteneur non privilégié dans le shell que j'ai exécuté le code mentionné ci-dessus mais pas dans aucun autre.

  1. Quelqu'un peut-il expliquer ce comportement?

  2. Quelqu'un a-t-il trouvé un meilleur moyen de configurer le nécessaire cgroupsavec une version actuelle de systemd( >= 217)?

lord.garbage
la source

Réponses:

13

Une solution meilleure et plus sûre consiste à installer cgmanageret l' exécuter avec systemctl start cgmanager(sur un systemddistro basé). Vous pouvez alors demander à votre rootutilisateur, ou si vous avez des sudodroits sur l'hôte de créer cgroupspour votre utilisateur non privilégié dans tous les contrôleurs avec:

sudo cgm create all $USER
sudo cgm chown all $USER $(id -u $USER) $(id -g $USER)

Une fois qu'ils ont été créés pour votre utilisateur non privilégié, il / elle peut déplacer les processus auxquels il a accès dans le sien cgrouppour chaque contrôleur en utilisant:

cgm movepid all $USER $PPID

Plus sûr, plus rapide et plus fiable que le script shell que j'ai publié.

Solution manuelle:

Pour répondre 1.

for d in /sys/fs/cgroup/*; do
        f=$(basename $d)
        echo "looking at $f"
        if [ "$f" = "cpuset" ]; then
                echo 1 | sudo tee -a $d/cgroup.clone_children;
        elif [ "$f" = "memory" ]; then
                echo 1 | sudo tee -a $d/memory.use_hierarchy;
        fi
        sudo mkdir -p $d/$USER
        sudo chown -R $USER $d/$USER
        echo $$ > $d/$USER/tasks
done

Je ne connaissais pas ce qui se passait exactement quand j'ai écrit ce script , mais la lecture de ce et d' expérimenter un peu m'a aidé à comprendre ce qui se passe. Ce que je fais essentiellement dans ce script est de créer une nouvelle cgroupsession pour le courant, userce que j'ai déjà dit ci-dessus. Lorsque j'exécute ces commandes dans le courant shellou les exécute dans un script et que je les évalue dans le courant shellet non dans un subshell(via . scriptLe .est important pour que cela fonctionne!), C'est que je n'ouvre pas simplement une nouvelle session pour usermais ajoutez le shell actuel en tant que processus qui s'exécute dans ce nouveau groupe de contrôle. Je peux obtenir le même effet en exécutant le script dans un sous-shell, puis descendre dans la cgrouphiérarchie dans le chb subcgroupet utiliserecho $$ > taskspour ajouter le shell courant à chaque membre du chb cgroup hierarchy.

Par conséquent, lorsque je cours lxcdans ce shell actuel, mon conteneur devient également membre de tous les chb subcgroups dont le courant shellest membre. C'est-à-dire que mon containerhérite du cgroupstatut de mon shell. Cela explique également pourquoi il ne fonctionne dans aucun autre shell qui ne fait pas partie de l'actuel chb subcgroups.

Je passe toujours 2.. Nous devrons probablement attendre une systemdmise à jour ou d'autres Kerneldéveloppements pour systemdadopter un comportement cohérent, mais je préfère quand même la configuration manuelle car elle vous oblige à comprendre ce que vous faites.

lord.garbage
la source
ne pouvez-vous pas simplement monter le répertoire cgroups ailleurs (question honnête) ? l'année dernière, il y avait beaucoup de controverse à propos des cgroups linux et de systemd lorsque le responsable des cgroups a apparemment décidé de donner à systemd par son nom et à d'autres applications similaires sans nom l' autorité sur la gestion des cgroups dans l'espace utilisateur. Je ne sais pas comment tout cela s'est avéré, mais je sais qu'il était assez difficile de savoir si un utilisateur pouvait le faire il y a un an.
mikeserv
Je pourrais probablement le faire, mais je devrais empêcher systemd de monter le répertoire racine de cgroup en premier lieu. Chaque fois que je me connecte à ma machine, systemd montera la hiérarchie racine du groupe racine sous / sys / fs / cgroup et ajoute un groupe utilisateur uniquement sous la partie systemd du groupe racine (vous pouvez le voir ci-dessus). La différence entre les distributions basées sur systemd et les distributions non basées sur systemd avant de passer est que, par exemple, dans Ubuntu, la gestion des groupes de contrôle n'est pas entre les mains du démon init.
lord.garbage
Il est plutôt géré par un programme comme par exemple cgmanager. Ou vous pouvez le faire à la main comme suggéré dans le lien vers kernel.org que j'ai posté ci-dessus. Actuellement, je n'ai pas une compréhension suffisamment approfondie de la gestion des groupes de contrôle systemd pour la manipuler plus profondément que maintenant. Mais j'espère que cela va bientôt changer.
lord.garbage
1
Certes, je me souviens que vous aviez déclaré cela dans un commentaire à une réponse que j'avais donnée il y a longtemps. Je vais me renseigner ...
lord.garbage
1
L'astuce est essentiellement: sudo systemctl start cgmanager && sudo cgm create all $USER && sudo cgm chown all $USER $(id -u) $(id -g) && sudo cgm movepid all $USER $PPID. La dernière commande doit être exécutée dans le shell actuel afin de l'ajouter au nouveau groupe de contrôle pour $USER.
lord.garbage
0

En fait, dans archlinux, cela ne fonctionnera pas avec, par exemple, un utilisateur non privilégié (recommandé lorsque vous utilisez des conteneurs lxc privés). c'est à dire que cet utilisateur n'a pas sudo :)

Au lieu de cela, définissez le groupe dans /etc/cgconfig.conf, activez cgconfig, cgrules (libcgroup dans AUR), ajoutez également des cgrules, fait .. priv. l'utilisateur aura également les mêmes droits.

Dans systemd 218 (je ne sais pas quand, mais il semble que l'on doive ajouter deux autres conditions car elles ne sont pas définies lors de la création de la manière cgconfig):

cat /etc/cgconfig.conf

group lxcadmin {
perm {
    task {
        uid = lxcadmin;
        gid = lxcadmin;
    }
    admin {
        uid = lxcadmin;
        gid = lxcadmin;
    }
}
cpu { }
memory { memory.use_hierarchy = 1; }  
blkio { }
cpuacct { }
cpuset { 
    cgroup.clone_children = 1;
    cpuset.mems = 0;
    cpuset.cpus = 0-3; 
}
devices { }
freezer { }
hugetlb { }
net_cls { }
}

cat /etc/cgrules.conf
lxcadmin        *       lxcadmin/

En supposant que l'espace de noms est compilé dans le noyau.

Ceci est un modèle, les processeurs peuvent être fonction du nombre de cœurs que vous avez, mem peut être défini sur une valeur réelle, etc., etc.

EDIT 2: Enfin, dans systemd, si vous souhaitez utiliser le démarrage automatique avec un tel utilisateur non privilégié, vous pouvez faire:

cp /usr/lib/systemd/system/lxc{,admin}\@.service, puis ajoutez User = lxcadmin

et l'activer pour le conteneur de lxcadmin appelé lolz systemctl activer lxcadmin @ lolz.

Malina Salina
la source
Merci @Anthon, je ne pourrai jamais obtenir le bon formatage du code dans ces sites Web, x
Malina Salina
Je vous remercie. Désolé pour la réponse tardive. Votre premier point, « En fait , dans ArchLinux, cela ne fonctionnera pas avec par exemple un utilisateur non privilégié (recommandé lors de l' utilisation unpriv. Conteneurs LXC). À savoir que l' utilisateur ne dispose pas des :) sudo » ne résiste pas que vous avez seulement besoin de votre rootadministrateur créer et chownvous dans tous les cgroupcontrôleurs. C'est parfaitement bien et sécurisé. movepidpeut être fait sans rootdroits et donc, le privé. l'utilisateur n'a besoin d'aucun sudodroit. (Btw, libcgroupn'est plus censé être utilisé. RHEL et d'autres l'ont déprécié.)
lord.garbage
@Brauner. Comment démarrez-vous automatiquement au démarrage, les conteneurs de votre utilisateur non privilégié alors? En fait, vos solutions répertoriées ne fonctionnaient (et impliquaient) qu'un utilisateur sudo. La mienne non. Vous avez demandé comment y remédier. Quoi qu'il en soit, il y a juste eu une mise à jour et cgconfig ne démarre plus, car les tranches utilisateur.sont ajoutées automatiquement, avant les paramètres de cgconfig, semble-t-il. Ceux-ci ne disposent d'aucune autorisation utilisateur (peut-être un bogue de régression, j'examine maintenant). Je n'ai pas dit que c'était la meilleure solution. C'était la / une solution à votre demande. :) Mais mes conteneurs ne démarrent pas au démarrage maintenant, grrr.
Malina Salina
La raison pour laquelle j'ai répertorié systemctl enable lxcadmin @ container était que root pouvait décider d'exécuter un conteneur privé au démarrage. Si l'utilisateur l'utilise lui-même dans --user (land), il ne démarre que lorsqu'il se connecte, ce qui n'est pas très utile pour un serveur. Et une note sur votre commentaire. chowning un utilisateur dans tous les contrôleurs, permet à cet utilisateur de commencer à déplacer les pid dans l'espace hôte, je crois, ce qui est un risque pour la sécurité.
Malina Salina
Euh, c'est apparemment ce que vous faisiez avec votre méthode initialement répertoriée, je suppose, mais regardez cela, même si c'est le paquet ubuntu systemd bugs.launchpad.net/ubuntu/+source/systemd/+bug/1413927 Mais quelque chose a été mis à jour dans les derniers jours changent la logique .. J'essaie de la retrouver.
Malina Salina
0

J'ai donc rencontré le même problème en essayant de faire fonctionner les conteneurs sans privilèges LXC sur CentOS 7. Je ne voulais pas l'utiliser cgmanagerparce que je n'aime pas introduire de services supplémentaires s'ils ne sont pas absolument nécessaires. Ce que j'ai fini par faire à la place, c'est patcher systemd en utilisant certains patchs du paquet ubuntu et un patch personnalisé pour étendre la liste des contrôleurs cgroup. J'ai les sources nécessaires pour créer un RPM sur mon compte GitHub à https://github.com/CtrlC-Root/rpmdist . J'ai également des versions corrigées de shadow-utils (pour les subuids et subgids) et pam (pour loginuid). Après avoir installé ces RPM et configuré un utilisateur pour exécuter des conteneurs sans privilèges (attribuer des sous-uid et des subgids, allouer des paires de veth dans lxc-usernet, créer .config / lxc / default.conf, etc.), je peux très bien exécuter des conteneurs sans privilèges LXC.

EDIT: Une autre raison pour laquelle je ne voulais pas utiliser cgmanager est parce que je ne voulais pas que mes utilisateurs réguliers aient à utiliser sudo du tout. Les utilisateurs réguliers devraient pouvoir se connecter et tout devrait "fonctionner" dès la sortie de la boîte.

ctrlc-root
la source