LXC

LXC est l'acronyme de l'anglicisme LinuX Containers, est un système de virtualisation, utilisant l'isolation comme méthode de cloisonnement au niveau du système d'exploitation. Il est utilisé pour faire fonctionner des environnements Linux isolés les uns des autres dans des conteneurs partageant le même noyau. Le conteneur apporte une virtualisation de l'environnement d'exécution (processeur, mémoire vive, réseau, système de fichier…) et non pas de la machine. Pour cette raison, on parle de « conteneur » et non de « machine virtuelle ». Veillez à ne pas confondre LXC et LXD, en effet, LXD est une surcouche logicielle à LXC. LXD est développé par Canonical pour simplifier la manipulation de vos conteneurs.


Attention, bien que vos processus soient isolés de votre machine hôte, via ce procédé, votre container LXC nécessitera d'utiliser sudo pour être fonctionnel. Si vous avez une faille de sécurité dans votre container, une escalade des privilèges peut être intenté sur votre container, pour accéder à votre machine hôte. L'utilisation de sudo pourrait donc compromettre votre système hôte !.

Pour créer un container avec pour nom1) container_xenial, pour la distribution2) Ubuntu, sous la release3) Xenial, ayant une architecture4) amd64, nous utiliserons cette commande :

sudo lxc-create -t download -n container_xenial -- -d ubuntu -r xenial -a amd64
(...)
Download complete
Copy /var/cache/lxc/container_xenial/rootfs-amd64 to /var/lib/lxc/container_xenial/rootfs ... 
Copying rootfs to /var/lib/lxc/container_xenial/rootfs ...
Generating locales (this might take a while)...
  fr_FR.UTF-8... done
Generation complete.
Creating SSH2 RSA key; this may take some time ...
2048 SHA256:oZjCPZs+eRqXx2y3WCX3sNR+fnxQypD1887jGnQ0jD8 root@home (RSA)
Creating SSH2 DSA key; this may take some time ...
1024 SHA256:fCNCpbXq4Z7KYZ0Xdztu9ti+u4rijgWg/nZ46M0A3HY root@home (DSA)
Creating SSH2 ECDSA key; this may take some time ...
256 SHA256:AT1ceBEITRDgga9czOlupGrRUT7T1DKl3PD0k9ZXlyU root@home (ECDSA)
Creating SSH2 ED25519 key; this may take some time ...
256 SHA256:BPcu2IHpyQoHIvpjIgzPMgaGDrz1TAaUlUnLrwznGXs root@home (ED25519)
invoke-rc.d: could not determine current runlevel
invoke-rc.d: policy-rc.d denied execution of start.
 
Current default time zone: 'Etc/UTC'
Local time is now:      Sun Jul 22 09:54:56 UTC 2018.
Universal Time is now:  Sun Jul 22 09:54:56 UTC 2018.
 
 
##
# The default user is 'ubuntu' with password 'ubuntu'!
# Use the 'sudo' command to run tasks as root in the container.
##

Pour lister notre container fraîchement créé on utilisera :

sudo lxc-ls --fancy
beaver@home:~$ sudo lxc-ls --fancy
     NAME         STATE  AUTOSTART GROUPS IPV4      IPV6 
container_xenial STOPPED     0       -   10.0.3.58   -
 
beaver@home:~$ cat /etc/lxc/default.conf 
lxc.network.type = veth
lxc.network.link = lxcbr0
lxc.network.flags = up
lxc.network.hwaddr = 00:16:3e:xx:xx:xx
 
beaver@home:~$ dpkg -l bridge-utils
Souhait=inconnU/Installé/suppRimé/Purgé/H=à garder
| État=Non/Installé/fichier-Config/dépaqUeté/échec-conFig/H=semi-installé/W=attend-traitement-déclenchements
|/ Err?=(aucune)/besoin Réinstallation (État,Err: majuscule=mauvais)
||/ Nom                                     Version                  Architecture             Description
+++-=======================================-========================-========================-===================================================================================
ii  bridge-utils                            1.5-9ubuntu1             amd64                    Utilities for configuring the Linux Ethernet bridge
Sous Ubuntu, on notera une attribution automatique d'IP privée5) à notre container portant le nom de container_xenial. Cela est dû à l'installation du package bridge-utils, qui est noté comme une dépendance logicielle à lxc. Le fichier /etc/lxc/default.conf est automatiquement renseigné, pour utiliser comme interface lxbr0.

Pour démarrer notre container portant le nom de container_xenial nous utiliserons :

sudo lxc-start -n container_xenial

On vérifie l'état de notre container :

beaver@home:~$ sudo lxc-ls --fancy
  NAME            STATE  AUTOSTART GROUPS IPV4      IPV6 
container_xenial RUNNING   0        -   10.0.3.58    -  

Accéder à son container LXC (root)

Méthode SSH (root)

Deux solutions s'offrent maintenant à nous pour accéder à notre container, nous pouvons utiliser la commande lxc-console, ou bien, nous pouvons utiliser la commande ssh :

##
# The default user is 'ubuntu' with password 'ubuntu'!
# Use the 'sudo' command to run tasks as root in the container.
##
beaver@home:~$ ssh ubuntu@10.0.3.58 
ubuntu@10.0.3.58 password: mot de passe **ubuntu** par défaut.
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-130-generic x86_64)
 
 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
Last login: Sun Jul 22 12:07:48 2018
ubuntu@container_xenial:~$ 

Méthode lxc-console (root)

Deux solutions s'offrent maintenant à nous pour accéder à notre container, nous pouvons utiliser la commande ssh, ou bien, nous pouvons utiliser la commande lxc-console :

##
# The default user is 'ubuntu' with password 'ubuntu'!
# Use the 'sudo' command to run tasks as root in the container.
##
beaver@home:~$ sudo lxc-console -n container_xenial
[sudo] Mot de passe de beaver : 
Connected to tty 1
Type <Ctrl+a q> to exit the console, <Ctrl+a Ctrl+a> to enter Ctrl+a itself
container_xenial login : ubuntu
Mot de passe : ubuntu par défaut
Dernière connexion : dimanche 22 juillet 2018 à 12:20:18 UTC de 10.0.3.1 sur pts/4
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-130-generic x86_64)
 
 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
ubuntu@container_xenial:~$ 

Conclusion : Vous voilà maintenant en possession d'un container LXC Ubuntu 16.04 ayant pour nom container_xenial !.

Le chemin absolu de votre container container_xenial se trouve dans :

/var/lib/lxc/container_xenial/rootfs

La configuration de votre container container_xenial se trouve dans :

/var/lib/lxc/container_xenial/config

Et non dans :

/etc/lxc/default.conf

Destruction de votre container LXC (root)

Rien de plus simple, vous devez déjà stopper votre container container_xenial :

sudo lxc-stop -n container_xenial

Et ensuite, nous passons à la destruction :

sudo lxc-destroy -n container_xenial

Pour pouvoir utiliser LXC sans sudo, et donc par conséquent, minimiser le risque qu'un attaquant arrive à avoir accès à votre hôte système à cause de l'utilisation de sudo, nous allons déjà récupérer le subgid ainsi que le subguid de notre utilisateur courant :

cat /etc/sub{g,u}id | grep $USER

Retournera :

beaver:100000:65536
beaver:100000:65536

Veillez de garder en tête ces deux lignes, maintenant, nous allons devoir stopper les services lxcfs.service, lxc-net.service, lxc.service :

sudo systemctl stop lxc*.service

Veuillez maintenant créer dans le dossier caché .config/ un dossier portant le nom lxc :

mkdir -p ~/.config/lxc

Puis nous créons un fichier default.conf :

touch ~/.config/lxc/default.conf

Veuillez maintenant éditer le fichier ~/.config/lxc/default.conf, et y ajouter ces lignes :

lxc.network.type = veth
lxc.network.link = lxcbr0
lxc.network.flags = up
lxc.network.hwaddr = 00:16:xx:xx:xx:xx ## À modifier par une adresse MAC fictive !.
lxc.id_map = u 0 100000 65536 ## À modifier par votre propre subguid !.
lxc.id_map = g 0 100000 65536 ## À modifier par votre propre subgid !.

Ou bien dans un terminal :

echo -e 'lxc.network.type = veth\nlxc.network.link = lxcbr0\nlxc.network.flags = up\nlxc.network.hwaddr = 00:16:xx:xx:xx:xx ## À modifier par une adresse MAC fictive !.\nlxc.id_map = u 0 100000 65536 ## À modifier par votre propre subguid !.\nlxc.id_map = g 0 100000 65536 ## À modifier par votre propre subgid !.' | tee --append ~/.config/lxc/default.conf

Maintenant, nous modifions le fichier lxc-usernet dans /etc/lxc, et on y insère ça :

nom_de_votre_utilisateur_hôte veth lxcbr0 2

Ou bien dans un terminal:

echo $USER veth lxcbr0 2 | sudo tee --append /etc/lxc/lxc-usernet

Créons maintenant l'emplacement où on va recevoir nos containers LXC, et attribuons y les bonnes permissions :

mkdir -p ~/.local ~/.local/share
chmod -R a+rx ~/.local

Nous devons maintenant créer un fichier 80-lxc-userns.conf dans /etc/sysctl.d/, pour se faire, dans un terminal :

sudo touch /etc/sysctl.d/80-lxc-userns.conf

Ensuite, nous ajoutons à notre fichier 80-lxc-userns.conf :

kernel.unprivileged_userns_clone=1

Ou bien dans un terminal :

echo 'kernel.unprivileged_userns_clone=1' | sudo tee --append /etc/sysctl.d/80-lxc-userns.conf

Ensuite, vous risquez d'avoir ce type d'erreur au démarrage de votre container :

lxc-start: start.c: print_top_failing_dir: 102 Permission denied - could not access /home/$USER.  Please grant it 'x' access, or add an ACL for the container root.
lxc-start: sync.c: __sync_wait: 51 invalid sequence number 1. expected 2
lxc-start: start.c: __lxc_start: 1172 failed to spawn 'nom_de_votre_container'

Pour y remédier :

chmod a+x /home/$USER/

À ce stade, il est préférable de redémarrer votre machine pour être certain, que les modifications apportées soient effectives :

sudo reboot

Essayons maintenant, après avoir redémarré notre machine, de créer un container unprivileged :

lxc-create -t download -n container_unprivileged -- -d ubuntu -r xenial -a amd64

Retournera :

beaver@home:~$ lxc-create -t download -n container_unprivileged -- -d ubuntu -r xenial -a amd64
Using image from local cache
Unpacking the rootfs
 
---
You just created an Ubuntu xenial amd64 (20180722_07:42) container.
 
To enable SSH, run: apt install openssh-server
No default root or user password are set by LXC.

Pour lister notre container récemment créé, veuillez ouvrir un terminal avec pour contenu :

lxc-ls --fancy
beaver@home:~$ lxc-ls --fancy
NAME                   STATE   AUTOSTART GROUPS IPV4      IPV6 
container_unprivileged STOPPED 0         -      10.0.3.42 - 

Vous noterez qu'il y'a ni mot de passe attribué, ni rien, impossible donc de se connecter à notre container container_unprivileged ni via la méthode ssh, ni via la méthode lxc-console. Voici un moyen pour attribuer un mot de passe à l'utilisateur ubuntu. Nous allons déjà démarrer notre container fraîchement installé :

lxc-start -n container_unprivileged

Ensuite, nous exécutons cette commande :

lxc-attach -n container_unprivileged

Ensuite :

root@container_unprivileged:/# passwd ubuntu
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully

À ce stade, vous allez pouvoir utiliser la commande passwd ubuntu et ainsi, définir le mot de passe que vous voulez à votre utilisateur ubuntu ! ;-).

Le chemin absolu de votre container container_unprivileged se trouve dans :

/home/$USER/.local/lxc/container_unprivileged/rootfs

Et non plus dans :

/var/lib/lxc/container_name/rootfs

La configuration de votre container container_unprivileged se trouve dans :

/home/$USER/.local/lxc/container_unprivileged/config

Et non plus dans :

/var/lib/lxc/container_name/config

La configuration de votre LXC unprivileged se trouve dans :

/home/$USER/.config/lxc/default.conf

Et non plus dans :

/etc/lxc/default.conf

Accéder à son container LXC (unprivileged)

Méthode lxc-console (unprivileged)

Une solution s'offre maintenant à nous pour accéder à notre container, la commande lxc-console. Nous devons d'abord démarrer notre container :

lxc-start -n container_unprivileged

Puis ensuite :

lxc-console -n container_unprivileged
beaver@home:~$ lxc-console -n container_unprivileged
Connected to tty 1
Type <Ctrl+a q> to exit the console, <Ctrl+a Ctrl+a> to enter Ctrl+a itself
container_unprivileged login : ubuntu
Mot de passe : mot de passe qu on a pu définir toute à l heure.
Dernière connexion : dimanche 22 juillet 2018 à 12:20:18 UTC de 10.0.3.1 sur pts/4
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-130-generic x86_64)
 
 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
ubuntu@container_unprivileged:~$ 

Conclusion : Vous voilà maintenant en possession d'un container LXC Ubuntu 16.04, le tout en "mode" unprivileged, ayant pour nom container_unprivileged !. Pour le reste, la syntaxe reste la même, veillez surtout à ne plus utiliser :
sudo lxc-trucmuche

mais juste :

lxc-trucmuche

.

Destruction de votre container LXC (unprivileged)

Rien de plus simple, vous devez déjà stopper votre container container_unprivileged :

lxc-stop -n container_unprivileged

Et ensuite, nous passons à la destruction :

lxc-destroy -n container_unprivileged

Création de votre backup via tar

Il est relativement aisé, de backup un container LXC, pour se faire, veuillez ouvrir un terminal.

Ensuite nous devons déjà stopper notre container LXC :

sudo((Container unprivileged ou non ?)) lxc-stop -n nom_de_mon_container

Ensuite, on se déplacera dans le dossier /var/lib/lxc/nom_de_votre_container/ ou bien, si vous êtes sur un container unprivileged, dans: /home/$USER/.local/lxc/nom_de_votre_container/ :

sudo -i && cd /var/lib/lxc/nom_de_votre_container/

Ou bien :

sudo -i && cd /home/$USER/.local/lxc/nom_de_votre_container/

Ensuite, nous utilisons la commande tar avec son option –numeric-owner, qui est ici très importante. Elle va permettre de garder les uid/gid intactes lors de l'extraction. Nous utilisons aussi l'outil gzip et son option -96), qui vous offrira, une compression maximale.

GZIP=-9 tar --numeric-owner -czvf mon_container.tar.gz ./*

Vous voilà maintenant en possession d'un backup de votre container, passons maintenant à sa restauration.

Restauration de votre backup via tar

Pour une utilisation root

Nous allons devoir stopper les services lxcfs.service, lxc-net.service, lxc.service. Pour se faire, veuillez ouvrir un terminal, avec pour contenu :

sudo -i && systemctl stop lxc*.service

Il vous faudra ensuite créer un dossier portant le nom de votre container.

Pour se faire, veuillez saisir :

mkdir -p /var/lib/lxc/nom_de_votre_container

Nous y attribuons les permissions adéquates :

chmod a+rx /var/lib/lxc/nom_de_votre_container

Ensuite, nous nous déplaçons dans le dossier fraîchement créé :

cd /var/lib/lxc/nom_de_votre_container

Nous passons à l'extraction de notre archive, portant le nom mon_container.tar.gz :

tar --numeric-owner -xzvf mon_container.tar.gz

C'est terminé, il y'a plus qu'à redémarrer lxcfs.service, lxc-net.service, lxc.service :

systemctl start lxc*.service && exit

Et démarrer ensuite votre container :

sudo lxc-start -n nom_de_votre_container

Pour une utilisation unprivileged

Nous aborderons ici, que la restauration de votre backup précédemment créé. Pour la configuration d'un container LXC unprivileged, merci de suivre le chapitre configuration de lxc pour une utilisation unprivileged.

Nous allons devoir stopper les services lxcfs.service, lxc-net.service, lxc.service. Pour se faire, veuillez ouvrir un terminal, avec pour contenu :

sudo systemctl stop lxc*.service

Créons maintenant l'emplacement où on va recevoir notre container LXC, et attribuons y les bonnes permissions :

mkdir -p ~/.local/share/lxc/nom_de_votre_container
chmod a+rx ~/.local/share/lxc/nom_de_votre_container

Passons maintenant à l'extraction de notre archive, portant le nom mon_container.tar.gz :-).

Nous allons déjà nous déplacer dans notre dossier fraîchement créé :

cd ~/.local/share/lxc/nom_de_votre_container

Et ensuite, nous passons à l'extraction de notre archive, portant le nom mon_container.tar.gz :

tar --numeric-owner -xzvf mon_container.tar.gz

C'est terminé, il y'a plus qu'à redémarrer lxcfs.service, lxc-net.service, lxc.service :

sudo systemctl start lxc*.service

Et démarrer ensuite votre container :

lxc-start -n nom_de_votre_container

Méthode lxc-snapshot

Il existe un outil dédié à LXC pour backup votre container, il se prénomme lxc-snapshot.

Il faut tout d'abord, éteindre notre container :

sudo((container unprivileged ou non ?)) lxc-stop -n nom_de_mon_container

Ensuite nous utilisons lxc-snapshot :

sudo((container unprivileged ou non ?)) lxc-snapshot -n nom_de_mon_container
beaver@home:~$ sudo lxc-snapshot -n container_xenial
lxc-snapshot: lxccontainer.c: do_lxcapi_snapshot: 3405 Snapshot of directory-backed container requested.
lxc-snapshot: lxccontainer.c: do_lxcapi_snapshot: 3406 Making a copy-clone.  If you do want snapshots, then
lxc-snapshot: lxccontainer.c: do_lxcapi_snapshot: 3407 please create an aufs or overlayfs clone first, snapshot that
lxc-snapshot: lxccontainer.c: do_lxcapi_snapshot: 3408 and keep the original container pristine.

Pour connaitre le chemin absolu de votre snapshot, vous utiliserez :

sudo((container unprivileged ou non?)) lxc-snapshot -L -n nom_de_mon_container
beaver@home:~$ sudo lxc-snapshot -L -n container_xenial
snap0 (/var/lib/lxc/container_xenial/snaps) 2018:07:28 10:25:48

Pour restaurer un container depuis votre snapshot vous utiliserez :

sudo((container unprivileged ou non?)) lxc-snapshot -r snapX -n nom_de_mon_container

Vous trouverez ici, une esquisse d'un script iptables, pour faire fonctionner votre container LXC. Il est bien entendu à ajouter aux règles que vous avez déjà, et à exécuter depuis votre machine hôte !. Cette esquisse est surtout utile si vous avez un firewall d'actif, sinon, vous devez juste activer le port forwarding7). Nous noterons aussi, que nous pouvons encore être plus restrictif, mais cette configuration semble adéquate pour un profane, et c'est pas péjoratif., ce script est qu'une ébauche.

Nous devons aussi, absolument installer le package dnsmasq-base, qui est, logiquement déjà installé sur votre machine. Et ensuite configurer LXC pour qu'il utilise la technologie bridge.

Veuillez éditer le fichier /etc/default/lxc-net, pour avoir comme résultat final :

USE_LXC_BRIDGE="true"

Nous devons ensuite redémarrer notre service lxc-net :

sudo systemctl restart lxc-net

Pour vérifier que tout est ok :

ip -4 -o a show lxcbr0

Retournera par exemple :

3: lxcbr0    inet 10.0.3.1/24 scope global lxcbr0\       valid_lft forever preferred_lft forever

Et voici le script iptables :

iptables_lxc
#!/bin/bash
## Script by none.
### Merci d'utiliser FIXME au sein du dokuwiki francophone Ubuntu au besoin, ou d'apporter votre contribution sur ce script, ici même.
 
# Nous activons le port forwarding, pour pouvoir communiquer à l'intérieur de notre container.
 
echo 1 > /proc/sys/net/ipv4/ip_forward
 
## Règles iptables
iptables-restore < /etc/iptables.test.rules
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -I INPUT -s 10.8.0.0/24 -i lxcbr0 -p udp --dport 67 -j ACCEPT
iptables -I INPUT -s 10.8.0.0/24 -i lxcbr0 -p tcp --dport 67 -j ACCEPT
iptables -I INPUT -s 10.8.0.0/24 -i lxcbr0 -p udp --dport 53 -j ACCEPT
iptables -I INPUT -s 10.8.0.0/24 -i lxcbr0 -p tcp --dport 53 -j ACCEPT
iptables -I FORWARD -s 10.8.0.0/24 -i lxcbr0 -j ACCEPT
iptables -I FORWARD -s 10.8.0.0/24 -o lxcbr0 -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.0.3.1/24 ! -d 10.0.3.1/24 -j MASQUERADE
iptables -t mangle -A POSTROUTING -o lxcbr0 -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
 
exit 0


Contributeur(s): BeAvEr.


1)
Option -n.
2)
Option -d.
3)
Option -r.
4)
Option -a.
5)
10.0.3.58, dans notre cas.
6)
–best-compression.
7)
echo 1 > /proc/sys/net/ipv4/ip_forward
  • lxc.txt
  • Dernière modification: Le 19/12/2018, 05:11
  • par beaver
  • Actuellement bloqué par: beaver