Le basi tecnologiche e di sicurezza di PiCockpit

Mi è stato chiesto di elaborare un po' le basi della sicurezza e della tecnologia di PiCockpit.

Le parti coinvolte

PiCockpit è composto da diverse parti:

  • picockpit-client
  • picockpit-frontend
  • picockpit-backend
  • picockpit-api ("papi")
  • il database
  • il server MQTT
  • il repository del pacchetto picockpit

Il server MQTT

I dati tra picockpit-frontend e picockpit-client vengono scambiati utilizzando il server MQTT (chiamato "broker"), tramite Websockets. Noi usiamo VerneMQ per questo scopo.

MQTT è un protocollo di comunicazione, simile a HTTP. Si basa sulla metafora publish / subscribe, a differenza di HTTP (che si basa su request / response).

In MQTT, i client possono connettersi al broker, e sottoscrivere gli argomenti - nel qual caso riceveranno i messaggi che sono pubblicati su questi argomenti. Possono anche pubblicare messaggi su argomenti.

I messaggi possono essere pubblicati come trattenuti - in questo caso il broker manterrà il messaggio, e lo invierà a qualsiasi cliente che si iscrive al particolare argomento su cui il messaggio è stato pubblicato.

Le keep-alive periodiche sono inviate dal broker al client e viceversa, per mantenere la connessione in funzione e assicurare che il client sia ancora online.

Inoltre, è possibile impostare un messaggio di ultima volontà, che sarà pubblicato se il broker perde la connessione con il cliente.

Ogni Raspberry Pi ottiene il proprio percorso di argomenti per i messaggi, il numero di serie del Raspberry Pi è usato per questo scopo.

Secondo la mia ricerca VerneMQ è una scelta perfetta per servire come broker MQTT per PiCockpit:

  • si concentra strettamente su MQTT (a differenza di RabbitMQ)
  • si concentra su alte prestazioni e alta disponibilità

VerneMQ è scritto in Erlang. Erlang è un buon linguaggio/ambiente per le applicazioni di telecomunicazione - è progettato per essere altamente concorrente, scalabile, anche su più nodi. È anche molto leggero per l'elaborazione dei singoli messaggi, permettendo di scalare fino a milioni di messaggi. Il VerneMQ blog è una lettura affascinante.

Caratteristiche di sicurezza

VerneMQ ci permette di utilizzare diversi punti di montaggio, per separare completamente il traffico per i singoli utenti.

Il picockpit-client e il picockpit-frontend di un utente saranno in grado di vedere solo i messaggi nel mountpoint di quell'utente.

Il mountpoint viene assegnato in base ai dati di autenticazione, che identificano un Rasberry Pi (picockpit-client) o una connessione JavaScript (picockpit-frontend) come appartenente a quel particolare utente.

Perché Websockets?

I websockets permettono al traffico di attraversare i firewall ed è l'unico modo in cui il client JavaScript può comunicare.

Il client picockpit

Il picockpit-client è scritto in Python, usando numerose librerie. È impacchettato come un pacchetto Debian (.deb), e distribuito nel nostro repository pubblico, firmato con la nostra chiave.

Per la comunicazione MQTT, usiamo Paho. Paho è una libreria open source. Usiamo Paho anche nel picockpit-frontend.

Il picockpit-client è collegato a PiCockpit in un processo di configurazione (sudo picockpit-client connect).

In questo processo, il client comunica con l'API utilizzando una chiave API, per ottenere le credenziali MQTT.

Sia la chiave API che le credenziali MQTT sono salvate sul Raspberry Pi dell'utente, in forma criptata (compreso il sale!).

Il picockpit-client è progettato per essere costantemente online, se il Pi dell'utente è online e connesso a Internet. In questo modo, i dati del Pi possono essere letti e possono essere controllati dall'utente in modo sicuro.

Disabilitando il servizio picockpit-client, picockpit.com non sarà più in grado di connettersi al Pi e ricevere dati / inviare comandi di controllo.

Il picockpit-client salva i file di configurazione locale nella cartella /etc/picockpit-client

immagine

Vedete un esempio di struttura nell'albero di directory dato sopra.

Il file di configurazione principale è picockpit-client.config.json. Questo file contiene le credenziali necessarie a picockpit-client per connettersi a PiCockpit.com.

Inoltre, si vedono due directory apps/com.picockpit/picontrol/modules e apps/com.picockpit/pidoctor/modules

Questi contengono file .json, file di definizione per i comandi che si possono eseguire attivamente dal frontend in queste particolari app.

Nel caso in cui, per esempio, non vuoi mostrare i pulsanti di riavvio o spegnimento in PiCockpit.com e non permettere a PiCockpit di usare questa funzionalità, devi modificare

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

e riavviare il servizio picockpit-client

immagine

Come potete vedere, questi file contengono definizioni per i comandi che vengono mostrati nel web-frontend.

Allo stesso modo, se volete espandere la funzionalità e aggiungere ulteriori comandi o moduli (gruppi di comandi), potete farlo qui modificando i file .JSON o creandone di nuovi.

I comandi sono eseguiti usando l'utente "pi" per impostazione predefinita. La sintassi .JSON permette di specificare con quale utente il comando dovrebbe essere eseguito.

picockpit-client viene eseguito come root, per eseguire i comandi viene creato un nuovo thread con i diritti dell'utente che vengono cambiati all'utente specificato. Questo cambiamento per quel particolare thread è irreversibile, quindi l'applicazione non può recuperare i diritti di root.

Gli stessi file JSON, con una sintassi un po' diversa, possono essere creati per PiDoctor.

immagine

Caratteristiche di sicurezza

Come detto sopra, i diritti utente possono essere modificati per PiControl impostando l'utente. I test di PiDoctor sono attualmente eseguiti tutti come root.

Nessun comando può essere definito dall'utente nell'interfaccia web, questi comandi devono esistere come file JSON sul Pi specifico che volete controllare.

Questo è progettato per prevenire problemi di sicurezza, anche nel caso in cui qualcuno abbia accesso al vostro webfrontend.

L'utente può controllare la quantità di esposizione che è disposto a dare.

Per default solo le azioni di controllo "poweroff", "reboot" e "update picockpit-client" sono state aggiunte all'interfaccia web.

Gli altri moduli (GPIO & PiStats) non permettono di eseguire comandi arbitrari. PiStats è attualmente hardcoded alle informazioni che vengono visualizzate nell'interfaccia web:

pistole

E GPIO permette di controllare i pin di Raspberry Pi (incluso PWM software), e di leggerli. È necessario prestare attenzione nell'allocazione dei pin (solo per picockpit-client, non è a conoscenza di altre applicazioni - quindi bisogna fare attenzione lì), e nella sincronizzazione degli stati tra più interfacce web che accedono allo stesso Pi (ad esempio se l'utente utilizza contemporaneamente diverse finestre del browser o dispositivi).

Tutte queste informazioni sono trasmesse utilizzando l'algoritmo MQTT publish / subscribe.

Infine, la comunicazione websocket funziona su una porta sicura, quindi tutti i dati che escono o entrano dal Pi nella comunicazione con il broker sono criptati.

picockpit-backend e database

Il backend di picockpit è scritto nella classe Cristallo linguaggio di programmazione, utilizzando Kemal come quadro di riferimento.

Crystal è stato scelto per le sue prestazioni, la facilità di sviluppo e la sicurezza dei tipi.

Crystal parla con il database. Noi usiamo MongoDB come database.

Caratteristiche di sicurezza

  • le password sono sottoposte a hash e salted
  • l'utente può creare diverse chiavi API e revocarle (cancellarle)
  • la chiave API è anche salvata solo in una forma hash e salata - non può essere reingegnerizzata, anche se qualcuno ha accesso al database

Sia dal lato di picockpit-client, che nel database, vengono salvati solo i derivati hash della chiave API.

E - no - non corrispondono direttamente (questo sarebbe un po' mancare il punto Sorriso), hanno bisogno di un'ulteriore elaborazione per convalidare le credenziali dell'utente / l'accesso del Pi.

La cancellazione della chiave API cancella anche le credenziali MQTT per un particolare Pi.

picockpit-frontend

Il frontend di picockpit è ora sempre più basato su JavaScript anche per il rendering.

È stata fatta una scelta per spostare PiCockpit più verso l'essere una SPA (applicazione a pagina singola).

Un'ulteriore integrazione delle pagine attualmente rese dal backend sarà fatta nel frontend più avanti.

Noi usiamo Vue.js e Vuetify.jse alcune altre librerie per il frontend, tra cui Paho per la connessione MQTT usando Websockets.

A seconda del Pi che stai guardando, il webfrontend si iscrive ai percorsi MQTT appropriati.

Se, per esempio, premi il pulsante "shutdown", un messaggio sarà pubblicato su un percorso MQTT definito, su cui picockpit-client è in ascolto.

Caratteristiche di sicurezza

Il frontend forza l'uso di una connessione HTTPS. Analogamente al picockpit-client, i dati sono trasmessi al broker tramite websockets usando solo connessioni criptate (https://).

In PiControl, l'esecuzione di azioni "pericolose" come il riavvio o lo spegnimento è protetta da ulteriori dialoghi di conferma:

immagine