RPI MQTT BROKER

De Knowledge base

Broker de message pour objets connectés On se propose de créer un broker complet de message pour objets connectés. Ce ne sera pas un simple broker MQTT style Mosquitto mais aussi un moteur de règles impliquant des chaines d'actions.

On se basera sur les briques de bases :

  • Raspbian
  • Mosquitto
  • Node Red

Installations

Système

Ici rien de plus simple!

On utilise le Raspberry Pi Imager et on sélectionne :

  • Dans les OS Raspberry alternatifs celui sans Desktop. (RASPBERRY PI OS LITE (32 BITS))
  • La carte SD du raspberry
  • On clique sur "Ecrire"

On débranche et rebranche la carte SD.

Deux lecteurs sont detectés:

  • BOOT (en D: pour moi) formaté en vfat donc lisible partout
  • Un second lecteur (E: pour moi) qui semble non formaté sous windows 10.

Ou ouvre le le cteur BOOT et on crée, à la racine, un fichier :

wpa_supplicant.conf

Contenant:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=FR 

network={
	ssid="NOM-RESEAU"
	psk="MOT-DE-PASSE"
	key_mgmt=WPA-PSK
}

En remplacant le SSID et le mot de passe.

il suffit de créer ensuite un fichier "vide" appelé ssh toujours dans la racine.

Insérez la carte dans le raspberry pi et branchez le. Normalement pas besoin de clavier ni d'écran.

Bon, on a e droit d'en brancher un si on en a un et on peut le voir booter tranquilement.

Pi-boot.jpg

On trouve le numéro IP de la nouvelle machine sur la console du routeur (de la box) ou a l'écran si vous en avez branché un.

Le mot de passe pour le user pi est raspberry.

donc:

ssh pi@192.168.0.100 

en changeant le No IP.

  • On change le mot de passe (vraiment on le fait MAINTENANT)
  • On change le "layout" du clavier DEBIANKYFR (en ssh c'est pas indispensable mais si on se logue dessus avec un clavier!)
  • on lance l'utilitaire de config
sudo raspi-config

Là dans l'ordre on change :

  1. System Option | hostname moi je l'ai appelé de façon hyper orriginale "broker"
  2. Localisation Options Je change la "timezone" mais je garde les locales car un ordinateur qui parle en Français.... c'est null. En anglais si on a un message d'erreur on e copie/colle sur google et on a plein de réponses. Le même message en français.... on n'a souvent rien ou si peu. Pour le keyboard layout rien à faire on l'a fait plus haut. Le "WLAN country" peut être utile si vous vivez dans un charmant pays où tous les canaux WIFI ne sont pas autorisés.
  3. Dans Advanced Options
    1. Expand Filesystem pour utiliser tout l'espace de la carte SD
  4. dans Performances Options
    1. Memory Split on réserve seulement 16 Mo pour la carte graphique ce n'est pas un ordinateur graphique!
  5. dans Display Options
    1. Eventuellement on change la résolution à 640x480 pour pouvoir utiliser un écran très bas de game!


On sorts on reboote (sur un PI ca prends 10 secondes).

Tout s'est bien passé?

On se relogue.

ssh pi@192.168.0.100

Et on fait les opérations suivantes :

  • On crée un compte applicatif :
sudo adduser app-mgr

Lui donner un mot de passe et un nom le reste peut rester vide.

sudo usermod -aG sudo app-mgr

Pour que ce "user" puisse passer des commandes root.

L'utilisateur en question pourra passes des commandes root via sudo mais devra entrer son mot de passe (le mécanisme de sodu sans mot de passe de raspberry me semble hasardeux).

On configure la connexion à app-mgr par couple de clés : Certif_ssh

On peut alors interdire la connexion distante (ssh) autrement que pas des échanges de clés (appelées de manière impropre de certificats).

Dans le fichier :

/etc/ssh/sshd_config

On ajoute

AllowUsers  app-mgr
PasswordAuthentication no

Moi je change aussi pour un autologin en mode console de l'utilisateur app-mgr dans raspi-config. Ca peut être vu comme un problème de sécu par certains. Moi je penses que de toute façons si on a accès "physiquement" au PI c'est mort!

On fait le ménage sur le compte pi qui est une potentielle porte d'entrée.

deluser pi
rm -rf /home/pi

On mets à jours le fichier /etc/hosts pour incude dans 127.0.0.1 :

  • Le hostname de la machine
  • Son FQDN cela era utile par la suite pour tester les connexions ssl en local.

On reboote

post-config système

On vérifie que la connexion ssh fonctionne toujours en se loggant depuis le réseau (ssh, putty, mobaXtem.....)

Maintenant on peut tout faire à distance, on peut cacher le PI dans un coin et oublier où il est tant qu'il est connecté :

  • A du courant par son port micro USB (usb C pour PI4)
  • A du réseau par son port RJ45 (pour un serveur le Wifi c'est pas top)
  1. On se loggue par ssh
  2. On lance la mise à jour des packages
sudo apt-get -y update
sudo apt-get -y upgrade

A l'heure ou j'écris ces lignes j'ajoure 4Mo de programe sur la carte et ca prends pas mal de temps. A la fin j'ai une version Raspbian GNU/Linux 10 avec un noyau Linux 5.10.11-v7l+ mais à la limite ça n'a pas d'importance.

En option on peut :

  • Retirer la "franboise" sur l'écran de la console :
sudo vi /boot/cmdline.txt

et on ajoute logo.nologo à la fin de la ligne. ATTENTION UNE SEULE LIGNE DANS LE FICHIER

  • Retirer le "spash screen arc en ciel" au boot :
sudo vi /boot/config.txt

Et on ajoute à la fin

disable_splash=1

On reboote :

sudo reboot

Et on a quelque chose de plus "sérieux".

Dernière option mais à mon avis c'est tres important on change la configuration réseau DHCP par une IP fixe.

Pour ma part le serveur DHCP donne des adresses dans la gamme 192.168.1.100 à 192.168.1.200 donc les fixes sont dans la gamme 192.168.1.2 à 192.168.1.99

Pour le serveur "broker" j'ai choisit 192.168.1.10 mais c'est votre choix.

La configuration est décrite ici.

Pour parachever son oeuvre on ajoute une authentification pas certificats/clés ssh Certif_ssh et un beau message de login dans /etc/motd :

 _               _             
| |             | |            
| |__  _ __ ___ | | _____ _ __ 
| '_ \| '__/ _ \| |/ / _ \ '__|
| |_) | | | (_) |   <  __/ |   
|_.__/|_|  \___/|_|\_\___|_|  
IoT broker server

Crée par : https://manytools.org/hacker-tools/ascii-banner/ (j'utilise la font "standard")

Mosquitto

Il y a un article ici mais pour le PI c'est simple :

sudo apt-get -y install mosquitto mosquitto-clients

Afin de vérifier le fonctionnement de Mosquitto il faut avoir deux terminaux ouverts en même temps.

Sur l'un on "souscrit" aux messages MQTT:

 mosquitto_sub -v -t "#"

On souscrit aux messages sur le broker en mode verbose (-v) et pour tous les topics (-t "#").

Sur l'autre on publie un message:

mosquitto_pub -t "test/feed" -m "First message"

Si on reviens au terminal "subscribe" on voit bien arriver le message.

test/feed First message

Notre broker fonctionne mais il faut le sécuriser un peu!


Ajouter la gestion des utilisateurs

On crée un fichier "users"

sudo mosquitto_passwd -c /etc/mosquitto/userslist operator

On crée un fichier /etc/mosquitto/userslist avec un utilisateur nommé "operator".

On nous demande classiquement un mot de passe deux fois pour éviter les erreurs de saisie.

On peut vérifier par :

pi@broker:~ $ cat /etc/mosquitto/userslist
operator:$6$Q38pk87+4hOGprP4$ZsgCkqvzGfy6iBT1ONDvQRK97+7ppH1BRjDVirTxMPi/u43qcFz79EZ4sHzl8UrqDd+7Frs7DtkPfqWu0ggtdA==

On a bien un user operator. On peut en ajouter d'autres :

sudo mosquitto_passwd /etc/mosquitto/userslist nodered
sudo mosquitto_passwd /etc/mosquitto/userslist probe00000000

ATTENTION L'ajout d'un nouvel utilisateur nécessite un redémmarage du process :

sudo /etc/init.d/mosquitto restart

Un reload ne suffite pas. C'est moche mais c'est comme ça!

On crée un fichier de conf à partir du modèle :

sudo sh -c 'zcat /usr/share/doc/mosquitto/examples/mosquitto.conf.gz > /etc/mosquitto/conf.d/mosquitto.conf'

Et on l'ouvre :

sudo vi /etc/mosquitto/conf.d/mosquitto.conf

On Modifie

allow_anonymous false
password_file /etc/mosquitto/userslist

et on relance le service.

sudo /etc/init.d/mosquitto restart

Maintenant quand on tente un:

mosquitto_sub -v -t "#"

On se prends un gentil

Connection Refused: not authorised.

En revanche un :

mosquitto_sub -v -u operator -P vousvoullezpasquejevousdonnemonmotdepassenon -t "#"

Fonctionne tant que le mot de passe est valide.

On peut même faire des requêtes distantes (depuis un autre serveur):

mosquitto_pub -h 192.168.1.9 -u operator -P vousvoullezpasquejevousdonnemonmotdepassenon -t "test/feed" -m "my remote  message"

Sécuriser le flux

Les certificats & les clés privées

Pour cela il nous faut la paire de fichiers :

  • Une clé privée pour le serveur
server.key
  • Un certificat correspondant à cette clé et dont le "common-name" est le hostname complet de notre serveur.

Soit on s'achète un certificat (cher chez un organisme tiers enregistré) soit on fait une pki avec openssl tel que définit ici and le wiki.

Vu que, dans la plupart des cas, les clients de notre broker seront des clients "maîtrisés" on peut se contenter de la solution "PKI familiale".

On considère donc les fichiers :

CA.crt
serveur.crt
serveur.key

Que l'on va ranger comme ci-dessous:

/etc/ssl/local/certs/serveur.crt
/etc/ssl/local/certs/CA.crt
/etc/ssl/local/keys/serveur.key

Le fichier /etc/ssl/local/keys/serveur.key ne doit pas être lisible par quiconque autre que root.

Installation des certificates sur Mosquitto

On édite le fichier /etc/mosquitto/conf.d/mosquitto.conf

Et on modifie pour avoir :

port 8883

et

cafile /etc/ssl/local/certs/CA.crt
certfile /etc/ssl/local/certs/serveur.crt
keyfile /etc/ssl/local/keys/serveur.key

Attention si il y a un espace après le nom de fichier et le retour à la ligne mosquitto essaye d'ouvrir un fichier portant le nom + les espaces. (avec vi c'est set list)

On peut alors faire les requêtes avec mosquitto_sub / pub

mosquitto_pub -h broker.pinon-hebert.fr -u operator -P hehenontoujourspas -t "test" -m "hello" --cafile CA-par.crt -p 8883
mosquitto_sub -h broker.pinon-hebert.fr -u operator -P hehenontoujourspas -t "test" -v --cafile CA-par.crt -p 8883

NodeRed

Installer

On installe les outils nécessaires au build de NodeRed:

sudo apt install build-essential git

Et on lance le script "magique".

bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)

Le script pause deux questions auxquelles il faut répondre oui mais c'est une bonne idée de lire le texte avant. (moi je suis d'accord avec les infos écrites mais vous ?)

On a ensuite une interface en mode texte qui montre l'avancement de l'installation.

C'est une interface comme je les aimes. Clair simple et qui marche aussi bien en local, au travers d'un xterm ou par une connexion ssh.

Noderedinstall.png

On sait ce qu'il reste à faire...

Adminsitration simple

  • On lance node Red par :
node-red-start

Une magnifique console s'ouvre :

Noderedconsole.png

Encore un modèle de clarté! Nous sommes loin de javalogs !

Un simple <ctrl> + C sort de cette console MAIS N'ARRETE PAS NODE RED !!!

Pour arrêter c'est :

node-red-stop

On a aussi les classiques :

node-red-restart 

arrète et redémarre

node-red-log 

Pour ré ouvrir les logs (les mêmes qu'avec node-red-start)

On peut également demander à Linux de relancer à chaque démarrage :

sudo systemctl enable nodered.service

Ou au contraire laisser cette action manuelle

sudo systemctl disable nodered.service


Ceci est assez satisfaisant!

  • on ouvre l'atelier node Red
http://{your_pi_ip-address}:1880

Pour nous c'est :

http://192.168.1.9:1880

L'atelier NodeRed est aussi classe que sa procédure d'installation.

Nodereddesktop.png

Sécuriser le flux

Pour le moment on utilise node Red sans aucune authentification !

On va ajouter là aussi une notion de login/password !

L'installation de node Red est dans le répertoire

/home/app-mgr/.node-red

La conf est dans le fichier settings.js (les habitués de node.js savent déjà mais bon)

Dans ce fichier on localise la section :

// Securing Node-RED

On a une structure du type

adminAuth: {
    type: "credentials",
    users: [
        {
            username: "admin",
            password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.",
            permissions: "*"
        },
        {
            username: "george",
            password: "$2b$08$wuAqPiKJlVN27eF5qJp.RuQYuy6ZYONW7a/UWYxDTtwKFCdB8F19y",
            permissions: "read"
        }
    ]
}

Pour chaque utilisateur on voit bien son login, son password (le hash de celui ci) et ses droits.

Pour créer un hash de password on a une commande appelée node-red-admin. Il faut l'installer

sudo npm install -g --unsafe-perm node-red-admin

Ensuite on l'utilise pour créer un mot de passe :

pi@broker:~/.node-red $ node-red-admin hash-pw
Password:
$2b$08$qUq2kisW3cHg1j8Ur4cXw.SgsHLjBy.L1f/wpONaw6wUkHy2XvQWm

On dé commente la partie

    adminAuth: {
        type: "credentials",
        users: [{
            username: "admin",
            password: "$2b$08$f0cAc.L.dfHrAmqtgK7SmetS94GA/9LYK9cURzLo/ypc7n1FtXxPi",
            permissions: "*"
        }]
    },

dans le fichier settings.js et on relance node-red.

Vérifications

Système

On se logue au système par :

ssh pi@broker.mondomaine.fr

MQTT

Pour MQTT il faut mettre à disposition le fichier certificat public de votre PKI. Le mien c'est :

-----BEGIN CERTIFICATE-----
MIIEKzCCAxOgAwIBAgIJAPLAgqZBg0f8MA0GCSqGSIb3DQEBBQUAMIGrMQswCQYD
VQQGEwJGUjEcMBoGA1UECAwTQ2VudHJlIFZhbCBkZSBMb2lyZTEZMBcGA1UEBwwQ
QXV0aG9uIGR1IFBlcmNoZTEUMBIGA1UECgwLdmlsbG9pc2VhdXgxDDAKBgNVBAsM
A3BraTEbMBkGA1UEAwwSY2EucGlub24taGViZXJ0LmZyMSIwIAYJKoZIhvcNAQkB
FhNwa2lAamVhbi5waW5vbi5uYW1lMB4XDTIwMDUxNTEzMjYwM1oXDTI2MDUxNDEz
MjYwM1owgasxCzAJBgNVBAYTAkZSMRwwGgYDVQQIDBNDZW50cmUgVmFsIGRlIExv
aXJlMRkwFwYDVQQHDBBBdXRob24gZHUgUGVyY2hlMRQwEgYDVQQKDAt2aWxsb2lz
ZWF1eDEMMAoGA1UECwwDcGtpMRswGQYDVQQDDBJjYS5waW5vbi1oZWJlcnQuZnIx
IjAgBgkqhkiG9w0BCQEWE3BraUBqZWFuLnBpbm9uLm5hbWUwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCdmRGeIpBlaGC/BoWE1yyI2yx9XfLgU4lOzh92
MEpWYNRye0nHlsHiVXADF82M4NJEY1f4mKMOQdx95PMKBBR615204GeDEGkzoDM0
hOeZ/sFerEr7u8Hmn4ECdyxTtAVjNgP4cP/AOxtg0kEUdd+tPYdlE+LVIBCId7NB
6MOrDRbdCJYCA1Mo75ysUTZEFQ8KaqtppVGQwqvkGyx6SiTXKRcJdVZO4xQ2YyHr
uRzro/eMdcFDrbx+swk9Qur28JQiirOedrKVxdb4QCzpMhRJv6o3SH5UcdHEwBGD
HfmkZjnXt0DvovD5RZ7EYyQGjEGWxGX0JbtVTb0FFmEwSemNAgMBAAGjUDBOMB0G
A1UdDgQWBBT55kfpU4vIAdQpwIzxB6iMOrl6yzAfBgNVHSMEGDAWgBT55kfpU4vI
AdQpwIzxB6iMOrl6yzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCL
pdyQUijrE9VPEy6c7uDTYrHamKNptmnSf0G/nZBdHCSpMC1bB9LJMiXc1a5W6a1z
nyWKdbT9zWFDuO7AGtTbdFtmhaX3+UeK7dq2lWwuBoS/Fz4rYv1raELk3gvSSLym
y/VuRXt3KEbNh8pXHKkl4Eo0Or3t8m7DNldNUvDwJLe2t5pEeYCNVP81ssewPlbx
ssERhuQxB0EUOqiemC6CY7C1E+wkHfCaSIJwbJ4nTr+2661upE+resIBhjY6+FPU
pLadzaBoHgTSz53Ccyz+QcfwFptlboFbbGAyOtIVMrMSRaG0jJNEAbSZJ2k1O7Ye
DCTNKE/437/6AY9vMRha
-----END CERTIFICATE-----

Oui je peux le donner puisque c'est le certificat public de ma PKI Familiale.

Sur une machine différente de "broker" mais qui y a accès au travers du DNS broker.modomaine.fr et où une copie de CA.crt dans le répertoire ~/certificates.

On lance un "écouteur" :

mosquitto_sub -v -p 8883 --cafile ~/certificates/CA.crt -u operator -P mosupermotdepasse -h broker.pinon-hebert.fr -t "#"

et on poste un message :

mosquitto_pub -p 8883 --cafile ~/certificates/CA.crt -u operator -P mosupermotdepasse -h broker.pinon-hebert.fr -t "fees/test" -m "remote message"

Si le message est reçu c'est que le serveur MQTT Mosquito est en fonctionnement.

Node red

On se connecte à

http://broker:1880 

On se logge

On crée un flux basique :

1. MQTT In sur localhost en écoutant sur le topic

/in/message

2. un template avec un motif :

 hello {{payload}}

3. un MQTT out sur le même serveur

4. On ajoute deux nœuds de "debug" qui affichent le "payload" sur la console.

/out/message

Ça ressemble à :

Nodered.single-stream.png

On oublie pas de deployer (bouton en haut a droite) et on se connecte en ssh sur broker.

On ouvre 3 terminaux :

1. Sur le premier on lance les logs de node red

node-red-log

2. Sur le second on affiche tous les messages MQTT

mosquitto_sub -v -h broker.pinon-hebert.fr -p 8883 -u operator -P icimonmotdepasse --cafile ~/certificates/CA.crt -t "#"

3. Pour envoyer les messages:

mosquitto_pub -h broker.pinon-hebert.fr -p 8883 -u operator -P icimonmotdepasse --cafile ~/certificates/CA.crt -t "/in/message" -m "Hello mosquitto"

Sur le terminal 1 (les logs) on voit:

18 May 11:32:40 - [info] [debug:reception] Hello mosquitto
18 May 11:32:40 - [info] [debug:template] hello Hello mosquitto

Les deux "debugs" ont bien été affichés. La modification effectuée dans "template" a bien été faite.

Sur le terminal 2 (messages MQTT) on voit les deux messages:

/in/message Hello mosquitto
/out/message hello Hello mosquitto

Notre flux a donc bien fonctionné.

Options

Dans les options envisageables :

  • Ajouter une base NoSql (mongoDB) pour gérer un base de données.
sudo apt-get update
sudo apt-get install mongodb-server
cd ~/.node-red/
npm install node-red-node-mongodb

ATTENTION RIEN N'EST SECURISE.

Pour sécuriser MongoDB c'est ici que ça se trouve.

  • Ajouter le mail
 cd ~/.node-red
 npm i node-red-node-email