Installation sécurisée de Jeedom avec Docker

Image for post
Image for post

C’est la deuxième fois cette année que la carte SD de mon installation de Jeedom sur Raspberry Pi rend l’âme. Heureusement, mes sauvegardes sont en sécurité sur Google Drive.

Mais plutôt que de racheter une énième carte SD, ou de la remplacer par un disque externe, j’ai décidé de me passer de Raspberry Pi et d’installer Jeedom sur mon serveur. Aprés tout, il dispose déjà d’un disque et cela me permettra de recycler mon Raspberry Pi pour autre chose.

Il est aussi tout à fait possible d’installer Jeedom dans un Docker sur Raspberry Pi, les avantages sont réels.

La documentation officielle au sujet de l’installation de Jeedom avec Docker est vraiment succincte, mais surtout incomplète et peu recommandable car elle préconise de lancer le conteneur en mode privilégié, ce qui est inacceptable d’un point de vue sécurité.

Les conteneurs privilégiés ont virtuellement les mêmes droits d’accès à la machine hôte que n’importe quel processus root s’exécutant sur l’hôte. Si un seul conteneur privilégié est compromis, alors l’hôte et l’intégralité de vos conteneurs sont aussi compromis.

Au delà de cet aspect sécuritaire, la documentation n’explique pas comment attacher votre RFXCom ou votre Z-Stick Gen5 (pour n’en citer que deux) ou s’assurer que le conteneur se lance à chaque redémarrage de votre machine.

Pré-Requis

Mon serveur tourne sous Ubuntu 18.04, donc les commandes ci-dessous devraient fonctionner sous n’importe quelle distribution dérivée de Debian.

L’installation de docker sur une distribution Debian est très simple :

$ sudo apt install docker docker.io

Une fois docker installé, il est possible d’ajouter le groupe docker à votre utilisateur afin de ne pas avoir à faire usage de sudo avec la commande docker:

$ sudo usermod -aG docker $USER 

Afin que le changement ci-dessus soit effectif, il est nécessaire de se déconnecter puis de se reconnecter de sa session.

Assurez-vous ensuite que le service docker est bien activé au démarrage (et lancé):

$ sudo systemctl enable docker
$ sudo systemctl start docker

Installation de la base de donnée

Jeedom nécessite une base de donnée pour fonctionner, et nous allons aussi utiliser un conteneur pour cela.

La documentation officielle utilise mysql, mais je recommande mariadb qui est 100% compatible mais surtout un logiciel libre.

Le conteneur à besoin d’un emplacement sur votre machine pour stocker la base de donnée et sa configuration. Disons /opt/jeedom/mysql :

$ sudo mkdir -p /opt/jeedom/mysql

La création de notre conteneur nommé jeedom-mysql est simple. N’oubliez pas de remplacer your-sql-password par le mot de passe de votre choix:

$ docker run --name jeedom-mysql -v /opt/jeedom/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=your-sql-password -e MYSQL_USER=jeedom -e MYSQL_PASSWORD=your-sql-password --detach --publish 3306:3306 --restart always mariadb:10.1

L’utilisateur jeedom est crée automatiquement. L’option --restart always permettra au conteneur de se relancer à chaque redémarrage du système. L’option --publish expose le port 3306 du conteneur sur le port 3306 de l’hôte.

Identification des périphériques USB

Avant d’installer Jeedom, il vous faut identifier les périphériques USB que vous souhaitez utiliser avec Jeedom. Branchez votre périphérique, et surveillez la sortie de dmesg :

$ dmesg | tail 
[68373.364295] usb 1-1.3: new full-speed USB device number 5 using xhci_hcd
[68373.465281] usb 1-1.3: New USB device found, idVendor=0658, idProduct=0200
[68373.465287] usb 1-1.3: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[68373.465977] cdc_acm 1-1.3:1.0: ttyACM1: USB ACM device

Sur l’exemple ci-dessus, l’on peut voir que mon Z-Stick Gen5 est associé au périphérique /dev/ttyACM1. Attention, le nom de ce périphérique n’est pas stable et peut changer car il dépend de l’ordre de détection lors du démarrage. Heureusement, sur ma distribution du moins, udev crée aussi un lien symbolique stable (et supposé unique) à partir des informations exposés par le périphérique :

$ ls -l /dev/serial/by-id
lrwxrwxrwx 1 root root 13 Jan 3 08:51 usb-0658_0200-if00 -> ../../ttyACM1

Nous retiendrons donc le lien symbolique /dev/serial/by-id/usb-0658_0200-if00 au lieu de /dev/ttyACM1 dans une variable d’environnement pour la suite:

$ GEN5=/dev/serial/by-id/usb-0658_0200-if00

Si vous ne savez pas si udev a crée des liens symboliques pour votre périphérique, vous pouvez aussi exécuter la commande suivante pour faire une recherche :

$ find /dev -exec ls -ald {} ';' | grep ttyACM1
crw-rw---- 1 root dialout 166, 1 Jan 3 08:51 /dev/ttyACM1
lrwxrwxrwx 1 root root 13 Jan 3 08:51 /dev/serial/by-path/pci-0000:00:14.0-usb-0:1.3:1.0 -> ../../ttyACM1
lrwxrwxrwx 1 root root 13 Jan 3 08:51 /dev/serial/by-id/usb-0658_0200-if00 -> ../../ttyACM1
lrwxrwxrwx 1 root root 10 Jan 3 08:51 /dev/char/166:1 -> ../ttyACM1

Procédant de la même façon pour notre RFXCom :

$ dmesg | tail
...
[69329.753861] usb 1-1.1: New USB device found, idVendor=0403, idProduct=6001
[69329.753867] usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[69329.753871] usb 1-1.1: Product: RFXtrx433
[69329.753875] usb 1-1.1: Manufacturer: RFXCOM
[69329.753879] usb 1-1.1: SerialNumber: 08WFE3F9
[69329.756114] ftdi_sio 1-1.1:1.0: FTDI USB Serial Device converter detected
[69329.756207] usb 1-1.1: Detected FT232RL
[69329.756841] usb 1-1.1: FTDI USB Serial Device converter now attached to ttyUSB0
$ ls -l /dev/serial/by-id
...
lrwxrwxrwx 1 root root 13 Jan 3 09:07 usb-RFXCOM_RFXtrx433_08WFE3F9-if00-port0 -> ../../ttyUSB0

Nous retiendrons donc le lien symbolique /dev/serial/by-id/usb-RFXCOM_RFXtrx433_08WFE3F9-if00-port0 au lieu de /dev/ttyUSB0 dans une variable d’environnement pour la suite :

$ RFXCOM=/dev/serial/by-id/usb-RFXCOM_RFXtrx433_08WFE3F9-if00-port0

Installation de Jeedom

Avant de procéder à l’installation, un petit mot important sur le mode réseau d’un conteneur : par défaut, l’interface réseau d’un conteneur est distincte de celle de l’hôte et dispose de son propre sous-réseau (habituellement 172.17.0.0/16), c’est le mode bridge. Cela signifie que votre conteneur n’est pas sur le réseau hôte et certains plugins peuvent ne pas fonctionner s’ils doivent communiquer avec des périphériques présents sur le réseau hôte : mDns et Bonjour sont deux exemples de protocole ne pouvant traverser les sous-réseaux.

Pour remedier à cela, il est possible de faire en sorte que le conteneur utilise l’interface réseau de l’hôte afin d’être sur le même réseau. Si vous êtes confortable avec cela, alors le mode host est fait pour vous.

L’espace de stockage d’un conteneur Docker étant difficilement accessible et surtout lié au cycle de vie de ce dernier, il est préférable que le répertoire d’installation de Jeedom /var/www/html soit hébergé sur la machine hôte à l’emplacement de votre choix. Disons /opt/jeedom/html :

$ sudo mkdir -p /opt/jeedom/html

Ci-dessous, la commande vous permettant de créer votre conteneur en mode host. N’oubliez pas de remplacer your-root-password par le mot de passe de votre choix :

$ docker create --net host --name jeedom-server -v /opt/jeedom/html:/var/www/html -e ROOT_PASSWORD=your-root-password -e APACHE_PORT=9080 -e SSH_PORT=9022 -e MODE_HOST=1 --device $RFXCOM:/dev/ttyUSB0 --device $GEN5:/dev/ttyACM0 --restart always jeedom/jeedom:master

Si vous préferez rester en mode bridge, vous trouverez ci-dessous la commande équivalente (j’ai mis en évidence les différences) :

$ docker create --net bridge --link jeedom-mysql --name jeedom-server -v /opt/jeedom/html:/var/www/html -e ROOT_PASSWORD=your-root-password --device $RFXCOM:/dev/ttyUSB0 --device $GEN5:/dev/ttyACM0 --publish 9080:80 --publish 9022:22 --restart always jeedom/jeedom:master

Contrairement à la documentation officielle, je ne recommande pas l’utilisation de l’option --privileged pour des raisons évidentes de sécurité : donner aux conteneurs un accès sans restrictions à votre machine hôte n’est pas acceptable mais surtout non nécessaire.

De plus, contrairement à l’exemple donné dans la documentation officielle, il est très important de spécifier la version de l’image Docker de Jeedom que vous utilisez (ici master) car, si vous l’omettez, Docker va utiliser le tag latest qui est vieux de plus de 2 ans à l’heure où j’écris ces lignes :

Image for post
Image for post

Afin d’éviter des conflits avec d’autres services déjà présent sur l’hôte, j’ai redirigé le port 80 du conteneur sur le port 9080 de l’hôte, et fait de même pour le port SSH (9022).

L’option --device $RFXCOM:/dev/ttyUSB0 autorise l’accès de votre périphérique RFXCom (précédemment identifié) et lui assigne le périphérique /dev/ttyUSB0 dans le conteneur.

Attention, l’utilisation de l’option --device ne supporte pas l’insertion à chaud : votre périphérique doit être présent au démarrage du conteneur et ne pas être retiré. Le support du hotplug est possible à travers d’autres moyens, mais cela dépasse le cadre de cet article.

L’option --restart always permettra au conteneur de se lancer à chaque redémarrage du système. Vous pouvez désormais lancer votre conteneur et observer la progression de l’installation :

$ docker start jeedom-server && docker logs -f jeedom-server

Configuration de Jeedom

Si l’installation s’est bien passé, ouvrez votre navigateur à l’adresse de votre serveur http://<ip-de-votre-serveur>:9080 et renseignez les informations de la base de donnée.

Pour le nom d’hôte de la base de donnée, utilisez localhost si vous êtes en mode host, sinon utilisez jeedom-mysql pour le mode bridge seulement.

Image for post
Image for post

Une fois votre base de donnée initialisée, avant de poursuivre votre installation, allez dans l’onglet “Réseaux” de la page de configuration et désactivez la gestion du réseau par Jeedom. Assurez-vous que la section “Accès Interne” soit 127.0.0.1:9080 si vous êtes en mode host, sinon 127.0.0.1:80 en mode bridge :

Image for post
Image for post

Votre installation de Jeedom est maintenant opérationnelle. Vos conteneurs sont correctement isolés et seront lancés à chaque redémarrage de votre machine.

La procédure permettant l’accès à distance de votre instance Jeedom via la redirection de ports de votre routeur ne change pas et dépasse le cadre de cet article. Pour la suite vous pouvez suivre la documentation officielle.

Si nécessaire, voici quelques commandes Docker qui pourraient vous être nécessaire :

# Voir le status de vos conteneurs
$ docker ps --all
# Démarrer, redémarrer, arrêter ou supprimer un conteneur
$ docker start <nom-du-conteneur>
$ docker restart <nom-du-conteneur>
$ docker stop <nom-du-conteneur>
$ docker rm <nom-du-conteneur>
# Ouvrir une invite de commande bash dans un conteneur
$ docker exec -it <nom-du-conteneur> bash

Si cet article vous a été utile, n’oubliez pas de l’applaudir en cliquant plusieurs fois sur l’icône ci-dessous. Je vous recommande également de jeter un oeil à son article compagnon : “Vos Sauvegardes Jeedom sur Google Drive”.

Written by

Analog at birth but digital by design. Hardcore Android Developer. Linux devotee. Came back once from /dev/null.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store