Die Technologie- und Sicherheitsgrundlagen von PiCockpit

Ich wurde gebeten, ein wenig über die Sicherheits- und Technologiegrundlagen von PiCockpit.

Die beteiligten Teile

PiCockpit besteht aus mehreren Teilen:

  • picockpit-client
  • picockpit-Frontend
  • picockpit-backend
  • picockpit-api ("papi")
  • die Datenbank
  • den MQTT-Server
  • das picockpit Paket-Repository

Der MQTT-Server

Der Datenaustausch zwischen picockpit-frontend und picockpit-client erfolgt über den MQTT-Server (genannt "Broker") via Websockets. Wir verwenden VerneMQ zu diesem Zweck.

MQTT ist ein Kommunikationsprotokoll, ähnlich wie HTTP. Es basiert auf der Veröffentlichungs-/Abonnement-Metapher, im Gegensatz zu HTTP (das auf Anfrage/Antwort basiert).

In MQTT können sich Clients mit dem Broker verbinden und Topics abonnieren - in diesem Fall erhalten sie Nachrichten, die in diesen Topics veröffentlicht werden. Sie können auch Nachrichten in Topics veröffentlichen.

In diesem Fall bewahrt der Broker die Nachricht auf und sendet sie an jeden Client, der das entsprechende Thema abonniert hat, in dem die Nachricht veröffentlicht wurde.

In regelmäßigen Abständen werden Keepalives vom Broker zum Client und zurück gesendet, um die Verbindung aufrechtzuerhalten und sicherzustellen, dass der Client noch online ist.

Darüber hinaus kann eine Nachricht "Letzter Wille und Testament" eingerichtet werden, die veröffentlicht wird, wenn der Broker die Verbindung zum Kunden verliert.

Jeder Raspberry Pi erhält seinen eigenen Nachrichten-Themenpfad, die Seriennummer des Raspberry Pi wird zu diesem Zweck verwendet.

Nach meinen Recherchen ist VerneMQ die perfekte Wahl, um als MQTT-Broker für PiCockpit zu dienen:

  • es ist ausschließlich auf MQTT ausgerichtet (im Gegensatz zu RabbitMQ)
  • der Schwerpunkt liegt auf hoher Leistung und hoher Verfügbarkeit

VerneMQ ist in Erlang geschrieben. Erlang ist eine gute Sprache/Umgebung für Telekommunikationsanwendungen - sie ist für hochgradige Gleichzeitigkeit und Skalierbarkeit ausgelegt, auch über mehrere Knoten hinweg. Außerdem ist sie sehr leichtgewichtig für die Verarbeitung einzelner Nachrichten, so dass sie auf Millionen von Nachrichten skaliert werden kann. Die Website VerneMQ-Blog ist eine faszinierende Lektüre.

Sicherheitsmerkmale

VerneMQ ermöglicht es uns, verschiedene Mountpoints zu verwenden, um den Datenverkehr für einzelne Benutzer vollständig zu trennen.

Der picockpit-client und das picockpit-frontend eines Benutzers können nur Nachrichten im Mountpoint dieses Benutzers sehen.

Der Einhängepunkt wird auf der Grundlage der Authentifizierungsdaten zugewiesen, die einen Rasberry Pi (picockpit-client) oder eine JavaScript-Verbindung (picockpit-frontend) als dem jeweiligen Benutzer zugehörig ausweisen.

Warum Websockets?

Websockets ermöglichen es dem Datenverkehr, Firewalls zu überwinden, und sind die einzige Möglichkeit, wie der JavaScript-Client kommunizieren kann.

Der picockpit-Client

Der picockpit-Client ist in Python geschrieben und verwendet zahlreiche Bibliotheken. Er wird als Debian-Paket (.deb) verpackt und mit unserem Schlüssel signiert in unserem öffentlichen Repository bereitgestellt.

Für die MQTT-Kommunikation verwenden wir Paho. Paho ist eine Open-Source-Bibliothek. Wir verwenden Paho auch im picockpit-Frontend.

Der picockpit-client wird in einem Setup-Prozess mit PiCockpit verbunden (sudo picockpit-client connect).

Bei diesem Verfahren kommuniziert der Client mit der API unter Verwendung eines API-Schlüssels, um MQTT-Anmeldeinformationen zu erhalten.

Sowohl der API-Schlüssel als auch die MQTT-Zugangsdaten werden auf dem Raspberry Pi des Benutzers in verschlüsselter Form (einschließlich Salz!) gespeichert.

Der picockpit-Client ist so konzipiert, dass er ständig online ist, wenn der Pi des Nutzers online und mit dem Internet verbunden ist. Auf diese Weise können die Daten des Pi ausgelesen werden und er kann vom Benutzer auf sichere Weise gesteuert werden.

Durch die Deaktivierung des picockpit-client Dienstes kann sich picockpit.com nicht mehr mit dem Pi verbinden und Daten empfangen bzw. Steuerbefehle senden.

Der picockpit-client speichert lokale Konfigurationsdateien im Verzeichnis /etc/picockpit-client

Bild

Eine Beispielstruktur sehen Sie in der oben angegebenen Verzeichnisstruktur.

Die wichtigste Konfigurationsdatei ist picockpit-client.config.json. Diese Datei enthält die notwendigen Anmeldedaten für den picockpit-client, um sich mit PiCockpit.com zu verbinden.

Außerdem sehen Sie zwei Verzeichnisse apps/com.picockpit/picontrol/modules und apps/com.picockpit/pidoctor/modules

Diese enthalten .json-Dateien, d.h. Definitionsdateien für die Befehle, die Sie aktiv über das Frontend in diesen speziellen Anwendungen ausführen können.

Wenn Sie z.B. die Reboot- oder Shutdown-Buttons in PiCockpit.com nicht anzeigen möchten und PiCockpit die Nutzung dieser Funktionen verbieten wollen, müssen Sie

apps/com.picockpit/picontrol/modules/core.json

und starten Sie den picockpit-client Dienst neu

Bild

Wie Sie sehen können, enthalten diese Dateien Definitionen für die Befehle, die im Web-Frontend angezeigt werden.

Wenn Sie die Funktionalität erweitern und zusätzliche Befehle oder Module (Befehlsgruppen) hinzufügen möchten, können Sie dies hier tun, indem Sie die JSON-Dateien bearbeiten oder neue Dateien erstellen.

Befehle werden standardmäßig unter dem Benutzer "pi" ausgeführt. Mit der .JSON-Syntax können Sie angeben, unter welchem Benutzer der Befehl ausgeführt werden soll.

picockpit-client läuft als root, für die Ausführung von Befehlen wird ein neuer Thread gesponnen, dessen Benutzerrechte auf den angegebenen Benutzer geändert werden. Diese Änderung für diesen bestimmten Thread ist irreversibel, so dass die Anwendung keine Root-Rechte zurückfordern kann.

Die gleichen JSON-Dateien, mit einer etwas anderen Syntax, können für PiDoctor erstellt werden.

Bild

Sicherheitsmerkmale

Wie bereits erwähnt, können die Benutzerrechte für PiControl geändert werden, indem der Benutzer festgelegt wird. Die Tests von PiDoctor werden derzeit alle als root ausgeführt.

Es können keine Befehle vom Benutzer im Webinterface definiert werden, diese Befehle müssen als JSON-Dateien auf dem jeweiligen Pi existieren, den Sie steuern möchten.

Dies soll Sicherheitsprobleme verhindern, selbst wenn jemand Zugang zu Ihrem Webfrontend erhält.

Der Nutzer kann selbst bestimmen, wie viel er von sich preisgeben möchte.

Standardmäßig wurden dem Webinterface nur die Steuerungsaktionen "Ausschalten", "Neustart" und "Picockpit-Client aktualisieren" hinzugefügt.

Die anderen Module (GPIO & PiStats) erlauben es nicht, beliebige Befehle auszuführen. PiStats ist derzeit fest auf die Informationen kodiert, die im Webinterface angezeigt werden:

Pistolen

Über GPIO können die Pins des Raspberry Pi (einschließlich Software-PWM) gesteuert und ausgelesen werden. Vorsicht ist geboten bei der Zuweisung der Pins (nur für den Picockpit-Client, er kennt keine anderen Anwendungen - hier muss man also aufpassen) und bei der Synchronisation von Zuständen über mehrere Webinterfaces, die auf denselben Pi zugreifen (z.B. wenn der Benutzer gleichzeitig mehrere Browserfenster oder Geräte verwendet).

Alle diese Informationen werden mit dem MQTT-Veröffentlichungs-/Abonnement-Algorithmus übertragen.

Schließlich läuft die Websocket-Kommunikation über einen sicheren Port, so dass alle Daten, die bei der Kommunikation mit dem Broker an den Pi gehen oder von ihm empfangen werden, verschlüsselt werden.

picockpit-Backend & Datenbank

Das picockpit Backend ist in der Programmiersprache Kristall Programmiersprache, mit Kemal als Rahmen.

Crystal wurde aufgrund seiner Leistungsfähigkeit, Entwicklerfreundlichkeit und Typsicherheit ausgewählt.

Crystal spricht mit der Datenbank. Wir verwenden MongoDB als Datenbank.

Sicherheitsmerkmale

  • Passwörter werden gehasht und gesalzen
  • der Benutzer kann mehrere API-Schlüssel erstellen und diese widerrufen (löschen)
  • der API-Schlüssel wird außerdem nur in gehashter und gesalzener Form gespeichert - er kann nicht zurückentwickelt werden, selbst wenn jemand Zugang zur Datenbank erhält

Sowohl auf der Seite des picockpit-Clients als auch in der Datenbank werden nur gehashte Ableitungen des API-Schlüssels gespeichert.

Und - nein - sie stimmen nicht direkt überein (das wäre irgendwie am Thema vorbei) Lächeln), müssen sie weiterverarbeitet werden, um die Anmeldedaten des Benutzers bzw. den Zugang des Pis zu validieren.

Durch das Löschen des API-Schlüssels werden auch die MQTT-Anmeldeinformationen für einen bestimmten Pi gelöscht.

picockpit-Frontend

Das picockpit Frontend basiert nun auch beim Rendering zunehmend auf JavaScript.

Es wurde beschlossen, PiCockpit mehr in Richtung einer SPA (Single Page Application) zu entwickeln.

Eine weitere Integration der Seiten, die derzeit vom Backend gerendert werden, wird später in das Frontend erfolgen.

Wir verwenden Vue.js und Vuetify.jsund einige andere Bibliotheken für das Frontend, darunter Paho für die MQTT-Verbindung über Websockets.

Je nachdem, welchen Pi Sie gerade betrachten, abonniert das Webfrontend die entsprechenden MQTT-Pfade.

Wenn Sie z.B. den "shutdown"-Button drücken, wird eine Nachricht auf einem definierten MQTT-Pfad veröffentlicht, auf dem der picockpit-client lauscht.

Sicherheitsmerkmale

Das Frontend erzwingt die Verwendung einer HTTPS-Verbindung. Ähnlich wie beim picockpit-Client werden die Daten über Websockets ausschließlich über verschlüsselte Verbindungen an den Broker übertragen (https://).

In PiControl wird das Ausführen von "gefährlichen" Aktionen wie Neustart oder Herunterfahren durch zusätzliche Bestätigungsdialoge geschützt:

Bild