Les fondements technologiques et sécuritaires de PiCockpit
On m'a demandé d'élaborer un peu plus sur les fondements de la sécurité et de la technologie de l'UE. PiCockpit.
Les parties qui sont impliquées
PiCockpit se compose de plusieurs parties :
- picockpit-client
- picockpit-frontend
- picockpit-backend
- picockpit-api ("papi")
- la base de données
- le serveur MQTT
- le dépôt de paquets picockpit
Le serveur MQTT
Les données entre le picockpit-frontend et le picockpit-client sont échangées en utilisant le serveur MQTT (appelé "broker"), via des Websockets. Nous utilisons VerneMQ à cette fin.
MQTT est un protocole de communication, similaire à HTTP. Il est basé sur la métaphore du publish / subscribe, contrairement à HTTP (qui est basé sur le request / response).
Dans MQTT, les clients peuvent se connecter au courtier et s'abonner à des sujets - dans ce cas, ils recevront les messages publiés sur ces sujets. Ils peuvent également publier des messages sur des sujets.
Les messages peuvent être publiés comme étant conservés - dans ce cas, le courtier conservera le message et l'enverra à tout client qui s'abonne au sujet particulier sur lequel le message a été publié.
Des "keep-alives" périodiques sont envoyés du courtier au client et inversement, pour maintenir la connexion et s'assurer que le client est toujours en ligne.
En outre, il est possible de configurer un message de testament qui sera publié si le courtier perd la connexion avec le client.
Chaque Raspberry Pi reçoit son propre chemin de sujet de message, le numéro de série du Raspberry Pi est utilisé à cet effet.
Selon mes recherches, VerneMQ est un choix parfait pour servir de courtier MQTT pour PiCockpit :
- il est strictement axé sur MQTT (contrairement à RabbitMQ)
- elle est axée sur la haute performance et la haute disponibilité
VerneMQ est écrit en Erlang. Erlang est un bon langage / environnement pour les applications de télécommunications - il est conçu pour être hautement concurrent, évolutif, même sur plusieurs nœuds. Il est également très léger pour le traitement des messages individuels, ce qui lui permet d'évoluer vers des millions de messages. Le site Le blog de VerneMQ constitue une lecture fascinante.
Caractéristiques de sécurité
VerneMQ nous permet d'utiliser différents points de montage, pour séparer complètement le trafic de chaque utilisateur.
Le picockpit-client et le picockpit-frontend d'un utilisateur ne pourront voir que les messages dans le mountpoint de cet utilisateur.
Le point de montage est attribué en fonction des données d'authentification, qui identifient un Rasberry Pi (picockpit-client) ou une connexion JavaScript (picockpit-frontend) comme appartenant à cet utilisateur particulier.
Pourquoi Websockets ?
Les websockets permettent au trafic de traverser les pare-feu et constituent le seul moyen pour le client JavaScript de communiquer.
Le picockpit-client
Le picockpit-client est écrit en Python, en utilisant de nombreuses bibliothèques. Il est empaqueté comme un paquet Debian (.deb), et déployé dans notre dépôt public, signé avec notre clé.
Pour la communication MQTT, nous utilisons Paho. Paho est une bibliothèque open source. Nous utilisons également Paho dans le picockpit-frontend.
Le picockpit-client est connecté à PiCockpit dans un processus d'installation (sudo picockpit-client connect).
Au cours de ce processus, le client communique avec l'API à l'aide d'une clé API, afin d'obtenir des informations d'identification MQTT.
La clé API et les informations d'identification MQTT sont enregistrées sur le Raspberry Pi de l'utilisateur, sous une forme cryptée (y compris le sel !).
Le picockpit-client est conçu pour être constamment en ligne, si le Pi de l'utilisateur est en ligne et connecté à l'Internet. De cette façon, les données du Pi peuvent être lues et l'utilisateur peut le contrôler en toute sécurité.
En désactivant le service picockpit-client, picockpit.com ne pourra plus se connecter au Pi et recevoir des données / envoyer des commandes de contrôle.
Le picockpit-client enregistre les fichiers de configuration locaux dans le dossier /etc/picockpit-client.
Vous voyez un exemple de structure dans l'arborescence de répertoires donnée ci-dessus.
Le principal fichier de configuration est picockpit-client.config.json. Ce fichier contient les informations d'identification nécessaires à picockpit-client pour se connecter à PiCockpit.com.
En outre, vous voyez deux répertoires apps/com.picockpit/picontrol/modules et apps/com.picockpit/pidoctor/modules.
Ils contiennent des fichiers .json, des fichiers de définition pour les commandes que vous pouvez exécuter activement à partir de l'interface dans ces applications particulières.
Si, par exemple, vous ne souhaitez pas afficher les boutons de redémarrage ou d'arrêt dans PiCockpit.com et interdire à PiCockpit d'utiliser cette fonctionnalité, vous pouvez modifier les éléments suivants
apps/com.picockpit/picontrol/modules/core.json
et redémarrez le service picockpit-client
Comme vous pouvez le voir, ces fichiers contiennent des définitions pour les commandes qui sont affichées dans le web-frontend.
De même, si vous souhaitez étendre la fonctionnalité et ajouter des commandes ou des modules (groupes de commandes) supplémentaires, vous pouvez le faire ici en modifiant les fichiers .JSON ou en en créant de nouveaux.
Les commandes sont exécutées par l'utilisateur "pi" par défaut. La syntaxe .JSON vous permet de spécifier sous quel utilisateur la commande doit être exécutée.
picockpit-client s'exécute en tant que root, pour exécuter des commandes, un nouveau Thread est créé avec les droits d'utilisateur modifiés pour l'utilisateur spécifié. Ce changement pour ce thread particulier est irréversible, l'application ne peut donc pas récupérer les droits root.
Les mêmes fichiers JSON, avec une syntaxe quelque peu différente, peuvent être créés pour PiDoctor.
Caractéristiques de sécurité
Comme mentionné ci-dessus, les droits d'utilisateur peuvent être modifiés pour PiControl en définissant l'utilisateur. Les tests de PiDoctor sont actuellement tous exécutés en tant que root.
Aucune commande ne peut être définie par l'utilisateur dans l'interface Web, ces commandes doivent exister sous forme de fichiers JSON sur le Pi spécifique que vous voulez contrôler.
Ceci est conçu pour éviter les problèmes de sécurité, même dans le cas où quelqu'un aurait accès à votre webfrontend.
L'utilisateur peut contrôler le degré d'exposition qu'il est prêt à donner.
Par défaut, seules les actions de contrôle "poweroff", "reboot" et "update picockpit-client" ont été ajoutées à l'interface web.
Les autres modules (GPIO & PiStats) ne permettent pas d'exécuter des commandes arbitraires. PiStats est actuellement codé en dur avec les informations qui sont affichées dans l'interface web :
Et GPIO permet de contrôler les broches du Raspberry Pi (y compris le PWM logiciel), et de les lire. Il faut faire attention à l'allocation des broches (pour picockpit-client uniquement, il n'est pas conscient des autres applications - il faut donc être prudent à ce niveau), et à la synchronisation des états entre plusieurs interfaces web accédant au même Pi (par exemple si l'utilisateur utilise simultanément plusieurs fenêtres de navigateur ou appareils).
Toutes ces informations sont transmises à l'aide de l'algorithme MQTT publish / subscribe.
Enfin, la communication par websocket passe par un port sécurisé, de sorte que toutes les données qui sortent ou entrent dans le Pi en communication avec le courtier sont cryptées.
picockpit-backend & base de données
Le backend de picockpit est écrit dans le langage Cristal langage de programmation, en utilisant Kemal comme cadre.
Crystal a été choisi pour ses performances, sa convivialité pour les développeurs et sa sécurité de type.
Crystal communique avec la base de données. Nous utilisons MongoDB comme base de données.
Caractéristiques de sécurité
- les mots de passe sont hachés et salés
- l'utilisateur peut créer plusieurs clés API, et les révoquer (les supprimer)
- la clé API est également sauvegardée uniquement sous une forme hachée et salée - elle ne peut pas faire l'objet d'une ingénierie inverse, même si quelqu'un a accès à la base de données.
Tant du côté du picockpit-client que dans la base de données, seuls les dérivés hachés de la clé API sont enregistrés.
Et - non - ils ne correspondent pas directement (cela reviendrait à passer à côté de l'essentiel). ), ils nécessitent un traitement supplémentaire afin de valider les informations d'identification de l'utilisateur / l'accès au Pi.
La suppression de la clé API supprime également les informations d'identification MQTT pour un Pi particulier.
picockpit-frontend
Le frontal du picockpit est maintenant de plus en plus basé sur JavaScript, y compris pour le rendu.
Le choix a été fait de faire évoluer PiCockpit vers une SPA (single page application).
Une intégration plus poussée des pages actuellement rendues par le backend sera faite dans le frontend en cours de route.
Nous utilisons Vue.js et Vuetify.jset d'autres bibliothèques pour l'interface, notamment Paho pour la connexion MQTT à l'aide de Websockets.
Selon le Pi que vous regardez, le webfrontend s'abonne aux chemins MQTT appropriés.
Si vous appuyez, par exemple, sur le bouton "shutdown", un message sera publié sur un chemin MQTT défini, sur lequel picockpit-client est à l'écoute.
Caractéristiques de sécurité
Le frontend impose l'utilisation d'une connexion HTTPS. Comme pour le picockpit-client, les données sont transmises au broker par websockets en utilisant uniquement des connexions cryptées (https://).
Dans PiControl, l'exécution d'actions "dangereuses" comme le redémarrage ou l'arrêt est protégée par des dialogues de confirmation supplémentaires :