Sécuriser la connexion MQTT dans Rhasspy

Encryption TLS

Nous avons donc protégé l’accès à notre serveur MQTT, mais tout le trafic MQTT qui passe sur le réseau reste en clair. C’est à dire que si on mettait en place ce qu’on appelle un sniffer, on pourrait lire les données qui transitent par MQTT.

On va donc faire en sorte que tout ce qui transite au travers de MQTT soit encrypté. Pour cela, on va devoir mettre en place ce qu’on appelle une autorité de certification. Et grâce à elle, on va pouvoir générer un certificat et des clés de chiffrement que l’on utilisera pour sécuriser la connexion MQTT.

Autorité de certification

cd /etc
sudo mkdir certs
cd certs
sudo mkdir ca
cd ca

Maintenant qu’on a créé le répertoire, on va créer notre certificat.

sudo openssl req -new -x509 -days 3650 -extensions v3_ca -keyout ca.key -out ca.crt

Et on en arrive là

pi@rasp-test:/etc/certs/ca $ sudo openssl req -new -x509 -days 3650 -extensions v3_ca -keyout ca.key -out ca.crt
Generating a RSA private key
.....................................+++++
..+++++
writing new private key to 'ca.key'
Enter PEM pass phrase:

Il nous demande donc d’entrer un mot de passe. Ce mot de passe, il faudra très précieusement le mettre de côté car c’est ce qui nous permettra de signer ensuite les certificats.

Ensuite, il va te demander quelques informations. Il faudra là aussi faire attention à ce que tu entres. Il y a 2 éléments sensibles. Le premier, c’est “Organization Unit”. Ce champ nous permettra de mettre le rôle associé au certificat. Le second, c’est le champ “Common name”. Il faudra soit mettre le hostname soit son adresse IP. Donc si l’IP n’est pas fixe, préfère le hostname. Il ne faut pas que 2 certificats aient les mêmes informations, sinon, ça va foirer.

Country Name (2 letter code) [AU]:FR
State or Province Name (full name) [Some-State]:PARIS
Locality Name (eg, city) []:PARIS
Organization Name (eg, company) [Internet Widgits Pty Ltd]:COXPROD
Organizational Unit Name (eg, section) []:ca
Common Name (e.g. server FQDN or YOUR name) []:rasp-test
Email Address []:cedcox@nomail.com

Une fois fini, si tu listes les fichiers, tu devrais trouver ces fichiers

pi@rasp-test:/etc/certs/ca $ ls
ca.crt  ca.key
pi@rasp-test:/etc/certs/ca $

Nous allons sécuriser ces 2 fichiers critiques

sudo chmod 600 ca.*

Certificat et clés pour notre serveur MQTT

Maintenant que nous avons notre autorité de certification, nous allons créer notre certificat pour notre serveur ainsi que la paire de clé nécessaire au chiffrement.

Commençons par créer un répertoire pour notre serveur MQTT

cd /etc/certs
sudo mkdir mosquitto
cd mosquitto

Ensuite, on crée la clé privée.

sudo openssl genrsa -out mosquitto.key 2048

voilà ce que ça donne :

pi@rasp-test:/etc/certs/mosquitto $ sudo openssl genrsa -out mosquitto.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
.................+++++
.....................................................................................+++++
e is 65537 (0x010001)
pi@rasp-test:/etc/certs/mosquitto $ ls
mosquitto.key
pi@rasp-test:/etc/certs/mosquitto $

Faisons maintenant une demande de signature

sudo openssl req -out mosquitto.csr -key mosquitto.key -new

Comme tout à l’heure, il va falloir entrer quelques informations. Là aussi, il faudra bien faire attention aux 2 champs “Organization Name” et “Common name”. Par contre, ne rentre pas de “challenge password”. Tapes juste sur “Entrée”

Country Name (2 letter code) [AU]:FR
State or Province Name (full name) [Some-State]:PARIS
Locality Name (eg, city) []:PARIS
Organization Name (eg, company) [Internet Widgits Pty Ltd]:COXPROD
Organizational Unit Name (eg, section) []:mosquitto
Common Name (e.g. server FQDN or YOUR name) []:rasp-test
Email Address []:cedcox@nomail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Si on liste les fichiers, en plus de notre clé privée, il y a désormais notre demande de signature (fichier .csr).

pi@rasp-test:/etc/certs/mosquitto $ ls
mosquitto.csr  mosquitto.key
pi@rasp-test:/etc/certs/mosquitto $

On soumet notre fichier de signature à l’autorité de certification

sudo openssl x509 -req -in mosquitto.csr -CA ../ca/ca.crt -CAkey ../ca/ca.key -CAcreateserial -out mosquitto.crt -days 3650

Une fois lancée, cette commande va te demander le mot de passe que tu as entré lorsque tu as généré ton autorité de certification

Signature ok
subject=C = FR, ST = PARIS, L = PARIS, O = COXPROD, OU = mosquitto, CN = rasp-test, emailAddress = cedcox@nomail.com
Getting CA Private Key
Enter pass phrase for ../ca/ca.key:

Si tu listes les fichiers, tu dois désormais avoir on fichier .crt qui est le certificat

pi@rasp-test:/etc/certs/mosquitto $ ls
mosquitto.crt  mosquitto.csr  mosquitto.key
pi@rasp-test:/etc/certs/mqtt $

Et on sécurise nos fichiers

sudo chmod 600 mosquitto*

Certificat et clés pour Rhasspy

Maintenant que nous avons un certificat pour notre serveur MQTT, il faudra générer un certificat pour chaque client MQTT, donc pour Rhasspy.

On commence donc par créer le répertoire qui va accueillir nos fichiers

cd /etc/certs
sudo mkdir rhasspy
cd rhasspy

On crée la clé privée

sudo openssl genrsa -out rhasspy.key 2048

Faisons maintenant une demande de signature

sudo openssl req -out rhasspy.csr -key rhasspy.key -new

On soumet notre demande de signature à l’autorité de certification

sudo openssl x509 -req -in rhasspy.csr -CA ../ca/ca.crt -CAkey ../ca/ca.key -CAcreateserial -out rhasspy.crt -days 3650

Comme pour mosquitto, on fait attention aux 2 champs critiques. Si notre client MQTT (Rhasspy) est sur un autre raspberry, on met le hostname de cet autre raspberry !

Country Name (2 letter code) [AU]:FR
State or Province Name (full name) [Some-State]:PARIS
Locality Name (eg, city) []:PARIS
Organization Name (eg, company) [Internet Widgits Pty Ltd]:COXPROD
Organizational Unit Name (eg, section) []:rhasspy
Common Name (e.g. server FQDN or YOUR name) []:rasp-test
Email Address []:cedcox@nomail.com

On fait signer par l’autorité de certification

sudo openssl x509 -req -in rhasspy.csr -CA ../ca/ca.crt -CAkey ../ca/ca.key -CAcreateserial -out rhasspy.crt -days 3650

On sécurise nos fichiers

sudo chmod 600 rhasspy*

N’oublie pas que tu devras générer ces fichiers pour chaque client qui devra se connecter au serveur MQTT comme nodered par exemple.

Configuration de mosquitto

On va déjà rappatrier les fichiers dans le répertoire de mosquitto

sudo cp -fr /etc/certs/mosquitto/* /etc/mosquitto/certs
sudo cp /etc/certs/ca/ca.crt /etc/mosquitto/certs/
sudo chown -R mosquitto /etc/mosquitto/certs

Ensuite, on édite notre fichier de configuration mosquitto

sudo nano /etc/mosquitto/mosquitto.conf

Et on colle ceci à la fin

## Si on veut autoriser aussi les connexions non chiffrees
listener 1883

## Activation des connexions chifrees par TLS
listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/mosquitto.crt
keyfile /etc/mosquitto/certs/mosquitto.key
tls_version tlsv1.2
require_certificate true

Notre fichier de config est donc divisé en 2 parties.

La première c’est le listener sur le port TCP 1883. On peut si on le souhaite se garder la possibilité d’envoyer des messages MQTT non chiffré par des périphériques qui n’auraient pas la puissance de calcul pour le chiffrement.

La seconde partie c’est la mise en place du listener sur le port 8883. C’est le port utilisé pour le secure-MQTT. Dans cette partie, on y met les chemins vers les certificats nécessaires au chiffrement et à la vérification de signature des certificats clients.

Et on redémarre notre serveur MQTT

sudo systemctl restart mosquitto

Et un petit test de bon fonctionnement. Au préalable, on installe mosquitto-clients s’il n’est pas déjà là.

sudo apt-get install mosquitto-clients

Puis, on essaye de souscrire à notre serveur MQTT en utilisant TLS

sudo mosquitto_sub --cafile /etc/certs/ca/ca.crt \
     -h rasp-test \
     -t "#" -p 8883 -d \
     --cert /etc/certs/rhasspy/rhasspy.crt \
     --key /etc/certs/rhasspy/rhasspy.key  \
     -u rhasspy -P <ton_mot_de_passe_mosquitto>

Et voilà ce que tu devrais obtenir :

Client mosqsub|29427-rasp-test sending CONNECT
Client mosqsub|29427-rasp-test received CONNACK (0)
Client mosqsub|29427-rasp-test sending SUBSCRIBE (Mid: 1, Topic: #, QoS: 0)
Client mosqsub|29427-rasp-test received SUBACK
Subscribed (mid: 1): 0

Si ce n’est pas le cas… recommence à 0 en regénérant les certificats.

Configuration de Rhasspy

On rapatrie les fichiers nécessaires dans le répertoire de Rhasspy

mkdir /home/pi/.config/rhasspy/profiles/fr/certs
sudo cp -fr /etc/certs/rhasspy/* /home/pi/.config/rhasspy/profiles/fr/certs
sudo cp /etc/certs/ca/ca.crt /home/pi/.config/rhasspy/profiles/fr/certs
sudo chown -R pi /home/pi/.config/rhasspy/profiles/fr/certs

Il nous faut maintenant mettre à jour notre profil Rhasspy. Le problème c’est qu’à la date d’ajourd’hui, les champs TLS de l’interface de configuration sont non fonctionnels. Il va donc falloir aller modifier le fichier de configuration manuellement.

cd /home/pi/.config/rhasspy/profiles/fr
nano profile.json

Et là, il faut modifier la partie TLS pour qu’elle corresponde à ce qu’il y a ci-dessous :

    "mqtt": {
        "enabled": "true",
        "host": "rasp-test",
        "password": "ton_mot_de_passe_mqtt",
        "port": "8883",
        "site_id": "master",
        "tls": {
             "ca_certs": "/home/pi/.config/rhasspy/profiles/fr/certs/ca/ca.crt",
             "certfile": "${RHASSPY_PROFILE_DIR}/certs/rhasspy.crt",
             "enabled": true,
             "keyfile": "${RHASSPY_PROFILE_DIR}/certs/rhasspy.key"
        },
        "username": "rhasspy"
    },

Si tu as installé Rhasspy avec Docker, alors remplace cette ligne :

"ca_certs": "/home/pi/.config/rhasspy/profiles/fr/certs/ca/ca.crt",

Par celle-ci :

"ca_certs": "/profiles/fr/certs/ca/ca.crt",

On sauvegarde et on redémarre Rhasspy

sudo systemctl restart rhasspy

2 Comments

  1. Merci pour cet article, c’est exactement ce qu’il me fallait ! Bravo ced pour tes articles, je les utilise beaucoup (je vais d’ailleurs bientôt passer de rhasspy docker à venv grâce à ton article, espérant corriger des difficultés audio)

    Je n’ai pas été jusqu’au chiffrement TLS du MQTT car j’ai un des clients qui n’est pas (encore) compatible.
    Sinon je vous renvoie vers le soft MQTT-Explorer (http://mqtt-explorer.com/). Dispo sur toutes les plateformes, il est compatible TLS et permet facilement de vérifier le bon fonctionnement, mais aussi de visualiser les messages simplement.

    • Bonjour Chris,

      Si tu ajoutes Listener 1883 juste avant la partie Listener 8883, mosquitto gardera aussi le port 1883 en non encrypté d’ouvert (comme à la page 4).
      Ça devrait te permettre de faire un test tout en gardant les clients non compatibles. 🙂
      Après, c’est vrai que je préfère Rhasspy-watch quand il s’agit de regarder uniquement ce qui se passe au niveau MQTT pour Rhasspy. Mais si il y a d’autre chose en plus que Rhasspy sur MQTT, oui mqtt-explorer est sympa !

      Ced

Poster un Commentaire

Votre adresse de messagerie ne sera pas publiée.


*


Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.