# LXC - Doc Technique
Groupe : xxx / xxx
## I - Définition
#### La virtualisation
La virtualisation est une technologie utilisable dans le but de créer des représentations virtuelles de serveurs, de stockage, de réseaux et d'autres machines physiques.
#### La conteneurisation
La conteneurisation consiste à rassembler le code du logiciel et tous ses composants, bibliothèques, frameworks et autres dépendances, de manière à les isoler dans leur propre conteneur.
#### LXC
LXC ou encore LinuX Containers, est un système de virtualisation. Il est utilisé pour faire fonctionner des environnements Linux isolés les uns des autres dans des conteneurs partageant le même noyau.
#### LoadBalancing
Le LoadBalancing désigne le processus de répartition d'un ensemble de tâches sur un ensemble de ressources, dans le but d'en rendre le traitement global plus efficace.
#### RoundRobin
Le RoundRobin est un algorithme qui permet d'utiliser chaque serveur à tour de rôle dans un ordre défini.
## II - Pré-requis
- Un ordinateur ou une machine virtuelle sous Ubuntu 22.02
- Un compte administrateur ou root
- Un accès à internet
#### Schéma réseau de l'architecture souhaitée :

## III - Installation
Mettre à jour la machine
```bash
sudo apt update && sudo apt full-upgrade
```
Installer LXC et LXD
```bash
sudo apt install lxc
snap install lxd
lxd init
```
## IV - Fonctionnalités
#### A - Vérifier la configuration de LXC
Afficher la configuration de LXC
```bash
lxc-checkconfig
```
#### B - Afficher la liste des conteneurs
Lister l'ensemble des conteners
```bash
lxc-ls -1 -f
```
Lister uniquement les conteneurs à l'arrêt
```bash
lxc-ls --stopped
```
Lister uniquement les conteneurs en cours d'execution
```bash
lxc-ls --running
```
#### C - Créer un conteneur
Créer un conteneur depuis un image en ligne
```bash
lxc-create -t download -n CONTAINER_NAME
```
Créer un conteneur depuis un image en ligne depuis un serveur spécifique
```bash
lxc-create -t download -n CONTAINER_NAME -- --keyserver keyserver.ubuntu.com
```
Créer un conteneur Debian immédiatement depuis un image en ligne
```bash
lxc-create -t download -n CONTAINER_NAME -- -d debian -r bullseye -a amd64
```
#### D - Gérer un containeur
Démarrer un conteneur
```bash
lxc-start -n CONTAINER_NAME
```
Arrêter un conteneur
```bash
lxc-stop -n CONTAINER_NAME
```
Supprimer un conteneur
```bash
lxc-destroy -n CONTAINER_NAME
Accéder à un container
```bash
lxc-attach -n container1
lxc-attach -n container2 --clear-env env HOME=/root USER=root TERM=xterm -- bash
```
Créer un réseau virtuelle
```bash
lxc network create NETWORK_NAME
```
Disable DHCP service
```bash
systemctl list-units | grep network
systemctl disable systemd-networkd
```
Ajouter notre container à notre réseau et attribuer une ip statique
```bash
ip -o -4 a show NETWORK_NAME | awk '{print $4}'
nano /var/lib/lxc/container2/config
```
Modifier/Ajouter la configuration suivante (selon votre réseau)
```bash
# Change network interface
lxc.net.0.link = dmz
# Change network ip configuration
lxc.net.0.ipv4.address = 192.168.56.121/24
lxc.net.0.ipv4.gateway = 192.168.56.104
```
## V - Fonctionnement
### A - Création des réseaux
1) Pour mettre en place l'architecture réseau, nous allons commencer par créer nos 2 réseaux virtuelles (dmz1 et dmz2). Nous utiliserons pour cela une commande LXD pour simplifier leur création.
```bash
lxc network create dmz1
lxc network create dmz2
```
2) Pour la suite des opérations nous aurons besoin de connaître le réseau et la passerelle de chacun de nos réseaux. Nous utiliserons la commande suivante pour récupérer la passerelle de chacun des réseaux.
```bash
# Afficher l'adresse IP du réseau 'dmz1'
ip -o -4 a show dmz1 | awk '{print $4}' | cut -d/ -f1
# Afficher l'adresse IP du réseau 'dmz2'
ip -o -4 a show dmz2 | awk '{print $4}' | cut -d/ -f1
```
Dans notre cas, l'adresse IP des passerelle réseau est :
dmz1 : 10.1.0.1
dmz2 : 10.2.0.1
### B - Création des conteneurs
Maintenant que nous avons créer nos réseaux, nous allons pouvoir créer nos différentes machines. Nous recommencerons dons toutes ces étapes pour nos 4 conteneurs selon la configuration ci-dessous :
| Nom | IP DMZ1 | IP DMZ2 | IP lxcbr0 (WAN) |
| ------------- | --------- | --------- | ----------------------- |
| server1 | 10.1.0.10 | 10.2.0.10 | |
| server2 | 10.1.0.20 | 10.2.0.20 | |
| serverProxy | 10.1.0.30 | | dynamique (par défault) |
| serverBackup | | 10.2.0.40 | |
1) Pour créer nos conteneurs nous utiliserons une image Debian, nous utiliserons donc la commande suivante en remplaçant $NAME par le nom de la machine à créer.
```bash
lxc-create -t download -n $NAME -- -d debian -r bullseye -a amd64
```
2) Une fois créer, avant de démarrer nos conteneurs, il va falloir modifier leur configuration pour leur attribuer leurs réseaux et leurs adresses IPs.
Nous allons donc modifier le fichier suivant:
```bash
nano /var/lib/lxc/$NAME/config
```
3) Dans ce fichier nous modifirons/ajouterons les ligne suivante pour configurer une IP statique dans le bon réseau : (En remplacant les adresses et le lien par ceux correspondant à la première interface)
```bash
lxc.net.0.link = dmz1
lxc.net.0.ipv4.address = 10.1.0.10/24
lxc.net.0.ipv4.gateway = 10.1.0.1
```
4) Dans le cas d'une seconde interface, il faudra ajouter le bloc suivant. (En remplacant les adresses et le lien par ceux correspondant à la deuxième interface)
Le champ `hwaddr` correspond à l'adresse MAC, ce dernier peut être aléatoire mais doit être unique pour chaque interface du réseau.
```bash
lxc.net.1.type = veth
lxc.net.1.link = dmz2
lxc.net.1.flags = up
lxc.net.1.hwaddr = 00:16:3e:aa:aa:aa
lxc.net.1.ipv4.address = 10.2.0.10/24
```
5) Maintenant que le réseau est configurer, nous allons désormais pouvoir démarrer nos conteneurs avec la commande suivante :
```bash
lxc-start -n $NAME
```
6) Bien que nous ayons configurer le réseau de manière statique, la machine à quand même récupéré une adresse dynamique. Pour corriger cela, nous allons donc devoir désactiver le service `systemd-networkd` avec la commande suivante :
```bash
lxc-attach -n $hostname -- bash -c 'systemctl disable systemd-networkd'
```
7) Pour apppliquer le changement, il sera nécessaire de redémarrer la machine.
```bash
lxc-stop -r -n $NAME
```
8) Maintenant notre machine devrait possèder les bonnes adresses réseaux. Néanmoins comme nous avons désactiver le service `systemd-networkd`, la résolution DNS ne fonctionne plus en l'état. Il va donc falloir ajouter une ligne au fichier `/etc/resolv.conf` pour ajouter un nouveau serveur DNS.
```bash
echo nameserver 8.8.8.8 >> /etc/resolv.conf
```
9) La dernière étape de l'installation de notre conteneur sera de la mettre a jour avec les commandes `apt-get update` et `apt-get full-upgrade`.
```bash
lxc-attach -n $NAME -- apt-get update
lxc-attach -n $NAME -- apt-get full-upgrade
```
### C - Configuration des serveurs web
Maintenant que toutes nos machines sont opérationnelles, nous allons passer à leur configuration.
1) Pour nos deux serveur web, nous installerons un serveur apache ainsi que les différentes applications transervales.
```bash
lxc-attach -n server1 -- apt-get install apache2 libapache2-mod-php php mariadb-server
lxc-attach -n server2 -- apt-get install apache2 libapache2-mod-php php mariadb-server
```
2) Nous pouvons vérifier le bon fonctionnement du serveur web avec la commande `curl` :
```
curl 10.1.0.10
curl 10.1.0.20
```

### D - Configuration du reverse proxy
1) Pour ce qui est de notre serveur reverse proxy, nous installerons un serveur haproxy qui occupera également la fonction d'équilibreur de charge
```bash
lxc-attach -n serverProxy -- apt-get install haproxy
```
2) Pour mettre en place notre reverse proxy, nous allons devoir éditer son fichier de configuration
```bash
nano /etc/haproxy/haproxy.cfg
```
3) Dans ce fichier nous ajouterons les lignes ci-dessous.
Nous avons d'un coté la configuration d'une page de logs pour suivre l'état du proxy en temps réél sur le port 8404.
De l'autre nous avons la configuration de notre équilibrage de charge en mode RoundRobin sur le port 80.
```yaml
frontend stats
mode http
bind *:8080
stats enable
stats hide-version
stats refresh 10s
stats uri /stats
stats auth admin:passwd123
stats admin if LOCALHOST
frontend frontweb
bind *:80
mode http
default_backend backweb
backend backweb
balance roundrobin
server server1 10.1.0.10:80 check
server server2 10.2.0.20:80 check
```
4) Après avoir modifier la configuration d'haproxy il est nécessaire de rédémarrer le service pour appliquer les modifications.
```bash
lxc-attach -n serverProxy -- systemctl restart haproxy
```
5) Nous allons désormais vérifier la configuration du haproxy, pour cela nous allons modifier le contenu des deux fichiers webs pour vérifier le load balancing
```bash
lxc-attach -n server1 -- bash -c "echo server1 > /var/www/html/index.html"
lxc-attach -n server2 -- bash -c "echo server2 > /var/www/html/index.html"
curl 10.1.0.30 # x4
```

6) Nous allons également vérifier le fonctionnement de notre page de statistiques en essayant à accéder à la page `/stats` de notre proxy.

7) En utilisant les identifiants rentrées dans la configuration (admin:passwd123), nous pouvons accédez à notre page. Sur cette page nous voyons retrouvons l'état de nos serveurs ainsi que le nombre de requête envoyé sur chaque serveur.

### E - Mise en place de la synchronisation des fichiers
1) Nous allons désormais mettre en place la synchronisation des différents serveurs web depuis notre backup. Nous utiliserons pour cela la commande `scp`. La première chose à faire sera donc d'installer un serveur SSH sur nos serveurs web.
```bash
lxc-attach -n server1 -- apt-get install openssh-server
lxc-attach -n server2 -- apt-get install openssh-server
```
2) Pour réaliser notre connexion SSH automatiquement, nous aurons besoin d'une paire de clés. Nous utiliserons donc le module `ssh-keygen` pour les créer. Nous créerons également au préalable le dossier `.ssh` qui contiendra notre clé car ce dernier n'existe pas par défaut.
```bash
lxc-attach -n serverBackup -- mkdir -m700 /root/.ssh
lxc-attach -n serverBackup -- ssh-keygen -t rsa -b 4096 -f /root/.ssh/id_rsa -N "" -q
```
3) Maintenant que nous avons nos clés, nous allons pouvoir ajouté la clé publique à chacun de nos serveurs web. Nous créerons également au préalable le dossier `.ssh` sur chacun des serveurs car ces derniers n'existent pas par défaut. Enfin nous attribuerons les droits 600 sur le fichier pour que celui puisse fonctionner correctement.
(La deuxième commande peut paraître un peu longue mais elle permet d'éviter de nombreuses étapes intermédiaires)
```bash
lxc-attach -n $NAME -- mkdir -m700 /root/.ssh
lxc-attach -n $NAME -- bash -c "echo $(lxc-attach -n serverBackup -- cat /root/.ssh/id_rsa.pub) >> /root/.ssh/authorized_keys"
lxc-attach -n $NAME -- chmod 600 /root/.ssh/authorized_keys
```
4) Maintenant que nous avons configurer la communication entre les machines, nous allons récupérer, nous récupérer le contenue d'un des sites web, qu'il pourra ensuite partager.
```bash
lxc-attach -n serverBackup -- bash -c "scp -o StrictHostKeyChecking=accept-new -pqr root@10.2.0.10:/var/www/html /root/html"
```
<br/>
5) Pour executer notre commande de synchronisation périodiquement, nous allons utiliser le module `cron`. Nous allons donc l'installer.
```bash
lxc-attach -n serverBackup -- apt-get install cron
```
6) Pour ajouter une nouvelle instruction cron, il faut exectuer la commande ci dessous. Cette dernière ouvre le fichier de configuration
```bash
crontab -e
```
7) Pour executer la synchronisation des deux serveurs toutes les 5 minutes, nous ajouterons les deux lignes suivantes à la fin du fichier.
```crontab
*/5 * * * * scp -o StrictHostKeyChecking=accept-new -pqr /root/html/index.html root@10.2.0.10:/var/www/html/index.html
*/5 * * * * scp -o StrictHostKeyChecking=accept-new -pqr /root/html/index.html root@10.2.0.20:/var/www/html/index.html
```
8) Pour verifier le bon fonctionnement, nous pouvons attendre 5 minutes et regarder de nouveau le contenu renvoyé par le serveur proxy. Le contenue devrait normalement être identique.

### F - Configuration du service Fail2Ban
1) Tout d'abord installer fail2ban sur votre serveur proxy.
```bash
apt install fail2ban
```
2) Rendez-vous ensuite dans le fichier défauts de configuration fail2ban.
```bash
vim /etc/fail2ban/jail.conf
```
3) Modifier ensuite le fichier en rajoutant ces quelques lignes. Tout d'abord descender un peu dans le fichier jusqu'à trouver la ligne "backend" et modifiez-la comme-ci dessous. Cela permettra de résoudre les problèmes de démarrage lié aux logs.
```bash
backend = systemd
```
4) Remonter ensuite dans le fichier jusqu'à trouver la ligne "bantime" et modifiez-la comme-ci dessous pour appliquer un banissement d'ip d'une semaine.
```bash
bantime = 604800
```
5) Si l'on regarde un peu plus bas nous pouvons remarquer la ligne "maxretry" laisser la par défaut elle permettra de bannir une ip au bout de 5 essaie échoué de tentative de connexion.
```bash
maxretry = 5
```
6) Votre service fail2ban est désormais opérationnel.
## VI - Scripts
```bash
#!/bin/bash
#### #### #### CONFIGURE NETWORK #### #### ####
echo -n "Configure network : "
# Create network
if [ -z $(ip -o -4 a | awk '/dmz1/ {print $2}') ]; then
lxc network create dmz1 1>/dev/null
fi
if [ -z $(ip -o -4 a | awk '/dmz2/ {print $2}') ]; then
lxc network create dmz2 1>/dev/null
fi
echo "OK"
#### #### #### CONFIGURE CONTAINER #### #### ####
echo -n "Configure container : "
# Get the gateway and network of network dmz
GATEWAY=$(ip -o -4 a show dmz1 | awk '{print $4}' | cut -d/ -f1)
NETWORK=$(echo $GATEWAY | cut -d. -f1,2,3)
GATEWAY2=$(ip -o -4 a show dmz2 | awk '{print $4}' | cut -d/ -f1)
NETWORK2=$(echo $GATEWAY2 | cut -d. -f1,2,3)
for i in server1:10:dmz1:$NETWORK:$GATEWAY:dmz2:$NETWORK2 server2:20:dmz1:$NETWORK:$GATEWAY:dmz2:$NETWORK2 serverProxy:30:dmz1:$NETWORK:$GATEWAY serverBackup:40:dmz2:$NETWORK2:$GATEWAY2
do
IFS=: read hostname hostIp int net gw int2 net2 <<< "${i}"
# Create container
lxc-create -t download -n $hostname -- -d debian -r bullseye -a amd64 1>/dev/null
# Place the containers in the DMZ and assign them a static IP address to the servers
sed -i "s/lxc.net.0.link = .*/lxc.net.0.link = $int/" "/var/lib/lxc/$hostname/config"
echo "lxc.net.0.ipv4.address = $net.$hostIp/24" >> "/var/lib/lxc/$hostname/config"
echo "lxc.net.0.ipv4.gateway = $gw" >> "/var/lib/lxc/$hostname/config"
# Add a second network if needed
if [ ! -z $int2 ]; then
echo "
lxc.net.1.type = veth
lxc.net.1.link = $int2
lxc.net.1.flags = up
lxc.net.1.hwaddr = 00:16:3e$(od -txC -An -N3 /dev/random|tr \ :)
lxc.net.1.ipv4.address = $net2.$hostIp/24
" >> "/var/lib/lxc/$hostname/config"
fi
# Start container
lxc-start -n $hostname && lxc-wait -n $hostname -s RUNNING
sleep .5
# Disable the DHCP service and restart the machine to recover the static ip
lxc-attach -n $hostname -- bash -c 'systemctl disable systemd-networkd 2>/dev/null'
lxc-stop -r -n $hostname && lxc-wait -n $hostname -s RUNNING
sleep .5
# Enable DNS resolution
lxc-attach -n $hostname -- bash -c 'echo nameserver 8.8.8.8 >> /etc/resolv.conf'
# Update container
lxc-attach -n $hostname -- bash -c "sed -i 's/# fr_FR.UTF-8 UTF-8/fr_FR.UTF-8 UTF-8/' /etc/locale.gen && locale-gen fr_FR.UTF-8 >/dev/null && update-locale LANG=fr_FR.UTF-8"
lxc-attach -n $hostname -- bash -c 'apt-get update 1>/dev/null && apt-get full-upgrade -y 1>/dev/null'
echo -n "."
done
echo "OK"
#### #### #### CONFIGURE WEB SERVER #### #### ####
echo -n "Configure web server : "
# Install the Apache web servers
lxc-attach -n server1 -- bash -c 'apt-get install apache2 libapache2-mod-php php mariadb-server -y 1>/dev/null 2>/dev/null'
lxc-attach -n server2 -- bash -c 'apt-get install apache2 libapache2-mod-php php mariadb-server -y 1>/dev/null 2>/dev/null'
echo "OK"
#### #### CONFIGURE REVERSE PROXY SERVER #### ####
echo -n "Configure reverse proxy server : "
# Install the haproxy server
lxc-attach -n serverProxy -- bash -c 'apt-get install haproxy -y 1>/dev/null 2>/dev/null'
# Configure haproxy to do load balancing in roundrobin mode, also add a stats page, on port 8404, to track proxy status
lxc-attach -n serverProxy -- bash -c "echo \"
frontend stats
mode http
bind *:8404
stats enable
stats hide-version
stats refresh 10s
stats uri /stats
stats auth admin:password
stats admin if LOCALHOST
frontend frontendserver
bind *:80
mode http
default_backend backendserver
backend backendserver
balance roundrobin
server server1 $NETWORK.10:80 check
server server2 $NETWORK.20:80 check
\" >> /etc/haproxy/haproxy.cfg"
# Restart haproxy to apply the configuration
lxc-attach -n serverProxy -- systemctl restart haproxy
echo "OK"
#### #### ## CONFIGURE WEB FILES SYNC ## #### ####
echo -n "Configure web files sync : "
# Generate an RSA key pair for our master web server
lxc-attach -n serverBackup -- mkdir -m700 /root/.ssh
lxc-attach -n serverBackup -- ssh-keygen -t rsa -b 4096 -f /root/.ssh/id_rsa -N "" -q
for i in server1:10 server2:20;
do
IFS=: read hostname hostIp <<< "${i}"
# Install an openssh server on the machine retrieving the data
lxc-attach -n $hostname -- bash -c 'apt-get install -y openssh-server 1>/dev/null 2>/dev/null'
# Send our previously generated public key to the listening server
lxc-attach -n $hostname -- bash -c "mkdir -m700 /root/.ssh 2>/dev/null"
lxc-attach -n $hostname -- bash -c "echo $(lxc-attach -n serverBackup -- cat /root/.ssh/id_rsa.pub) >> /root/.ssh/authorized_keys && chmod 600 /root/.ssh/authorized_keys"
# Get a unique configuration from a web server
lxc-attach -n serverBackup -- bash -c "scp -pqr root@$NETWORK2.$hostIp:/var/www/html /root/html >> /dev/null"
# Install cron to run commands periodically
lxc-attach -n serverBackup -- bash -c 'apt-get install cron -y 1>/dev/null 2>/dev/null'
# Add a cron line to perform a synchronization to the listening server every 5 minutes
lxc-attach -n serverBackup -- bash -c "(crontab -l 2>/dev/null; echo \"*/5 * * * * scp -pqr /root/html root@$NETWORK2.$hostIp:/var/www/html >> /dev/null\") | crontab -"
done
echo "OK"
```