Las bases tecnológicas y de seguridad de PiCockpit
Me pidieron que me explayara un poco sobre los fundamentos de seguridad y tecnología de PiCockpit.
Las partes que intervienen
PiCockpit consta de varias partes:
- picockpit-client
- picockpit-frontend
- picockpit-backend
- picockpit-api ("papi")
- la base de datos
- el servidor MQTT
- el repositorio de paquetes de picockpit
El servidor MQTT
Los datos entre el picockpit-frontend y el picockpit-client se intercambian utilizando el servidor MQTT (llamado "broker"), a través de Websockets. Utilizamos VerneMQ para este fin.
MQTT es un protocolo de comunicaciones, similar a HTTP. Se basa en la metáfora publicar / suscribir, a diferencia de HTTP (que se basa en la solicitud / respuesta).
En MQTT, los clientes pueden conectarse al broker y suscribirse a temas, en cuyo caso recibirán los mensajes que se publiquen en esos temas. También pueden publicar mensajes en temas.
Los mensajes pueden ser publicados como retenidos - en este caso el broker mantendrá el mensaje, y lo enviará a cualquier cliente que se suscriba en el tema particular en el que el mensaje fue publicado.
Se envían periódicamente keep-alives del broker al cliente y viceversa, para mantener la conexión en marcha y asegurarse de que el cliente sigue en línea.
Además, se puede configurar un mensaje de última voluntad, que se publicará si el corredor pierde la conexión con el cliente.
Cada Raspberry Pi obtiene su propia ruta de mensajes, el número de serie de la Raspberry Pi se utiliza para este propósito.
Según mi investigación VerneMQ es una opción perfecta para servir como broker MQTT para PiCockpit:
- se centra estrictamente en MQTT (a diferencia de RabbitMQ)
- se centra en el alto rendimiento y la alta disponibilidad
VerneMQ está escrito en Erlang. Erlang es un buen lenguaje / entorno para aplicaciones de telecomunicaciones - está diseñado para ser altamente concurrente, escalable, incluso a través de varios nodos. También es muy ligero para el procesamiento de mensajes individuales, lo que le permite escalar a millones de mensajes. La página web Blog de VerneMQ es una lectura fascinante.
Elementos de seguridad
VerneMQ nos permite utilizar diferentes puntos de montaje, para separar completamente el tráfico de los usuarios individuales.
El picockpit-client y el picockpit-frontend de un usuario sólo podrán ver los mensajes en el punto de montaje de ese usuario.
El punto de montaje se asigna en base a los datos de autenticación, que identifican una Rasberry Pi (picockpit-client) o una conexión JavaScript (picockpit-frontend) como pertenecientes a ese usuario en particular.
¿Por qué Websockets?
Los Websockets permiten que el tráfico atraviese los Firewalls y es la única forma en que el cliente JavaScript puede comunicarse.
El cliente picockpit
El cliente picockpit está escrito en Python, utilizando numerosas bibliotecas. Está empaquetado como un paquete Debian (.deb), y desplegado en nuestro repositorio público, firmado con nuestra clave.
Para la comunicación MQTT, utilizamos Paho. Paho es una biblioteca de código abierto. También utilizamos Paho en el picockpit-frontend.
El picockpit-client se conecta a PiCockpit en un proceso de configuración (sudo picockpit-client connect).
En este proceso, el cliente se comunica con la API utilizando una clave de API, para obtener las credenciales MQTT.
Tanto la clave de la API como las credenciales MQTT se guardan en la Raspberry Pi del usuario, de forma encriptada (¡con sal incluida!).
El picockpit-cliente está diseñado para estar constantemente en línea, si la Pi del usuario está en línea y conectada a Internet. De esta manera, los datos de la Pi pueden ser leídos & pueden ser controlados por el usuario de una manera segura.
Desactivando el servicio picockpit-client, picockpit.com no podrá conectarse más a la Pi y recibir datos / enviar comandos de control.
El cliente picockpit guarda los archivos de configuración local en la carpeta /etc/picockpit-client
Puede ver un ejemplo de estructura en el árbol de directorios indicado anteriormente.
El archivo de configuración principal es picockpit-client.config.json. Este archivo contiene las credenciales necesarias para que picockpit-client se conecte a PiCockpit.com.
Además, verás dos directorios apps/com.picockpit/picontrol/modules y apps/com.picockpit/pidoctor/modules
Estos contienen archivos .json, archivos de definición para los comandos que puedes ejecutar activamente desde el frontend en estas aplicaciones particulares.
En caso de que, por ejemplo, no quiera mostrar los botones de reinicio o apagado en PiCockpit.com y no permitir que PiCockpit utilice esa funcionalidad, deberá editar
apps/com.picockpit/picontrol/modules/core.json
y reiniciar el servicio picockpit-client
Como puede ver, estos archivos contienen las definiciones de los comandos que se muestran en el web-frontend.
Del mismo modo, si quieres ampliar la funcionalidad y añadir comandos o módulos (grupos de comandos) adicionales, puedes hacerlo aquí editando los archivos .JSON o creando otros nuevos.
Los comandos se ejecutan utilizando el usuario "pi" por defecto. La sintaxis .JSON permite especificar con qué usuario debe ejecutarse el comando.
picockpit-client se ejecuta como root, para ejecutar comandos se crea un nuevo hilo con los derechos de usuario que se cambian al usuario especificado. Este cambio para ese hilo en particular es irreversible, por lo que la aplicación no puede recuperar los derechos de root.
Los mismos archivos JSON, con una sintaxis algo diferente, pueden ser creados para PiDoctor.
Elementos de seguridad
Como se mencionó anteriormente, los derechos de usuario pueden ser modificados para PiControl estableciendo el usuario. Actualmente las pruebas de PiDoctor se ejecutan todas como root.
Los comandos no pueden ser definidos por el usuario en el Webinterface, estos comandos tienen que existir como archivos JSON en el Pi específico que desea controlar.
Esto está diseñado para evitar problemas de seguridad, incluso en el caso de que alguien consiga acceder a su webfrontend.
El usuario puede controlar la cantidad de exposición que está dispuesto a dar.
Por defecto, sólo se han añadido a la interfaz web las acciones de control "apagar", "reiniciar" y "actualizar picockpit-cliente".
Los otros módulos (GPIO y PiStats) no permiten ejecutar comandos arbitrarios. PiStats está actualmente codificado con la información que se muestra en la interfaz web:
Y GPIO permite controlar los pines de Raspberry Pi (incluyendo el PWM del software), y leerlos. Se tiene cuidado en la asignación de los pines (para picockpit-cliente solamente, no es consciente de otras aplicaciones - por lo que hay que tener cuidado allí), y la sincronización de los estados a través de múltiples webinterfaces que acceden a la misma Pi (por ejemplo, si el usuario utiliza simultáneamente varias ventanas del navegador o dispositivos).
Toda esta información se transmite utilizando el algoritmo de publicación/suscripción de MQTT.
Por último, la comunicación por websocket se realiza a través de un puerto seguro, por lo que todos los datos que salen o entran en la Pi en comunicación con el broker están encriptados.
picockpit-backend y base de datos
El backend de picockpit está escrito en el lenguaje Cristal lenguaje de programación, utilizando Kemal como marco.
Se eligió Crystal por su rendimiento, su facilidad de desarrollo y su seguridad de tipo.
Crystal habla con la base de datos. Utilizamos MongoDB como base de datos.
Elementos de seguridad
- las contraseñas están codificadas y con sal
- el usuario puede crear varias claves API, y revocarlas (eliminarlas)
- la clave de la API sólo se guarda en forma de hash y salado, por lo que no puede ser objeto de ingeniería inversa, incluso si alguien tiene acceso a la base de datos
Tanto en el lado del cliente picockpit, como en la base de datos, sólo se guardan los derivados hash de la clave API.
Y - no - no coinciden directamente (esto sería perder el punto ), necesitan un procesamiento adicional para validar las credenciales del usuario / el acceso del Pi.
Al eliminar la clave de la API también se eliminan las credenciales MQTT de un determinado Pi.
picockpit-frontend
El frontend de Picockpit se basa ahora cada vez más en JavaScript también para la renderización.
Se ha optado por hacer que PiCockpit sea más bien una aplicación de página única (SPA).
Más adelante, se integrarán en el frontend las páginas que actualmente se generan en el backend.
Utilizamos Vue.js y Vuetify.jsy algunas otras bibliotecas para el frontend, incluyendo Paho para la conexión MQTT usando Websockets.
Dependiendo de qué Pi esté mirando, el webfrontend se suscribe a las rutas MQTT apropiadas.
Si, por ejemplo, se pulsa el botón "apagar", se publicará un mensaje en una ruta MQTT definida, en la que picockpit-client está escuchando.
Elementos de seguridad
El frontend obliga a utilizar una conexión HTTPS. Al igual que el cliente picockpit, los datos se transmiten al broker a través de websockets utilizando únicamente conexiones cifradas (https://).
En PiControl, la ejecución de acciones "peligrosas" como el reinicio o el apagado está protegida por diálogos de confirmación adicionales: