MQTT Projekt Umsetzung: Unterschied zwischen den Versionen
| (27 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 2: | Zeile 2: | ||
==Grundaufbau== | ==Grundaufbau== | ||
{{#drawio:mqtt-plan1}} | {{#drawio:mqtt-plan1}} | ||
| − | |||
==Connectivity== | ==Connectivity== | ||
===ssh=== | ===ssh=== | ||
| Zeile 17: | Zeile 16: | ||
;aktor | ;aktor | ||
*https://aktor.dkbi.com | *https://aktor.dkbi.com | ||
| − | |||
==Unverschlüsselt ohne Passwort== | ==Unverschlüsselt ohne Passwort== | ||
===mqtt=== | ===mqtt=== | ||
;Konfiguration kopieren | ;Konfiguration kopieren | ||
| − | *sudo cp | + | *sudo cp /etc/mosquitto/conf.d/defaults.conf.ohne-password /etc/mosquitto/conf.d/defaults.conf |
;Konfigurationsdatei | ;Konfigurationsdatei | ||
| + | *cat /etc/mosquitto/conf.d/defaults.conf | ||
<pre> | <pre> | ||
# Öffnet den MQTT-Broker auf Port 1883 und bindet ihn an alle verfügbaren Netzwerkinterfaces. | # Öffnet den MQTT-Broker auf Port 1883 und bindet ihn an alle verfügbaren Netzwerkinterfaces. | ||
| Zeile 39: | Zeile 38: | ||
===Aktor=== | ===Aktor=== | ||
Der Aktor '''abonniert (subscribed)''' die Nachrichten und reagiert darauf. | Der Aktor '''abonniert (subscribed)''' die Nachrichten und reagiert darauf. | ||
| − | *mosquitto_sub -h mqtt. | + | *mosquitto_sub -h mqtt.dkbi.com -t test |
===Sensor=== | ===Sensor=== | ||
Der Sensor '''sendet (published)''' die Nachrichten an das Topic. | Der Sensor '''sendet (published)''' die Nachrichten an das Topic. | ||
| − | *mosquitto_pub -h mqtt. | + | *mosquitto_pub -h mqtt.dkbi.com -t test -m "Hello World" |
| − | *mosquitto_pub -h mqtt. | + | *mosquitto_pub -h mqtt.dkbi.com -t test -m "2 Nachricht" |
===kali=== | ===kali=== | ||
Hier kann man auf Wireshark mitschneiden. Der Text ist Hexadezimal codiert. | Hier kann man auf Wireshark mitschneiden. Der Text ist Hexadezimal codiert. | ||
| Zeile 56: | Zeile 55: | ||
Dieses Projekt dient zur steuerbaren MQTT-basierten Hausautomation mit Node.js und Mosquitto als MQTT-Broker. Es ermöglicht das Schalten und Überwachen von Geräten wie Lichtquellen und Türschlössern über eine Web-Oberfläche. | Dieses Projekt dient zur steuerbaren MQTT-basierten Hausautomation mit Node.js und Mosquitto als MQTT-Broker. Es ermöglicht das Schalten und Überwachen von Geräten wie Lichtquellen und Türschlössern über eine Web-Oberfläche. | ||
===Hauptbestandteile des Projekts=== | ===Hauptbestandteile des Projekts=== | ||
| − | Mosquitto MQTT-Broker | + | ;Mosquitto MQTT-Broker |
| − | + | :Verwaltung der Nachrichten zwischen Sensoren und Aktoren. Zunächst ohne Authentifizierung, später mit Benutzer/Passwort und TLS. | |
| − | Zunächst ohne Authentifizierung, später mit Benutzer/Passwort und TLS. | + | ;Node.js-Backend mit Express.js |
| − | Node.js-Backend mit Express.js | + | :Verbindet sich als MQTT-Client zum Broker. Abonniert Status-Topics und aktualisiert den Gerätestatus. Bietet eine REST-API, um den Status abzufragen und Geräte zu steuern. |
| − | + | ;Web-Interface | |
| − | Abonniert Status-Topics und aktualisiert den Gerätestatus. | + | :Zeigt den aktuellen Gerätestatus in einer einfachen Oberfläche. Ermöglicht das Schalten der Geräte per Klick. Aktualisiert sich automatisch über API-Anfragen. |
| − | Bietet eine REST-API, um den Status abzufragen und Geräte zu steuern. | ||
| − | Web-Interface | ||
| − | |||
| − | Ermöglicht das Schalten der Geräte per Klick. | ||
| − | Aktualisiert sich automatisch über API-Anfragen. | ||
===Schrittweise Absicherung=== | ===Schrittweise Absicherung=== | ||
Das Projekt startet mit einer offenen MQTT-Verbindung, wird dann um Benutzer/Passwort ergänzt und am Ende mit TLS-Verschlüsselung abgesichert. | Das Projekt startet mit einer offenen MQTT-Verbindung, wird dann um Benutzer/Passwort ergänzt und am Ende mit TLS-Verschlüsselung abgesichert. | ||
| − | |||
==Node.js konkret== | ==Node.js konkret== | ||
===Sensor=== | ===Sensor=== | ||
| Zeile 85: | Zeile 78: | ||
====Zugriff==== | ====Zugriff==== | ||
*Siehe oben per https | *Siehe oben per https | ||
| − | |||
===Aktor=== | ===Aktor=== | ||
;Verzeichnis | ;Verzeichnis | ||
| Zeile 99: | Zeile 91: | ||
*sudo systemctl restart control.service | *sudo systemctl restart control.service | ||
====Zugriff==== | ====Zugriff==== | ||
| − | * | + | *Siehe oben per https |
| + | =Anpassen von node.js= | ||
| + | ;sensor | ||
| + | *sudo cp /usr/local/control-switch/env.ohne-passwd /usr/local/control-switch/.env | ||
| + | *cat /usr/local/control-switch/.env | ||
| + | MQTT_HOST=mqtt.dkbi.com | ||
| + | MQTT_PORT=1883 | ||
| + | ;Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen) | ||
| + | *cd /usr/local/control-switch/ | ||
| + | *nodejs server.js | ||
| + | ;Läuft es, als Service starten | ||
| + | *sudo systemctl restart control-switch.service | ||
| + | ;aktor | ||
| + | *sudo cp /usr/local/control/env.ohne-passwd /usr/local/control/.env | ||
| + | *cat /usr/local/control/.env | ||
| + | MQTT_HOST=mqtt.dkbi.com | ||
| + | MQTT_PORT=1883 | ||
| + | ;Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen) | ||
| + | *cd /usr/local/control/ | ||
| + | *nodejs server.js | ||
| + | ;Läuft es, als Service starten | ||
| + | *sudo systemctl restart control.service | ||
| + | |||
| + | =Stufe 2= | ||
| + | =Unverschlüsselt mit Passwort= | ||
| + | ==mqtt== | ||
| + | ;Benutzer anlegen | ||
| + | *user: kit | ||
| + | *pass: 123Start$ | ||
| + | *rm -f /etc/mosquitto/passwd | ||
| + | *sudo mosquitto_passwd -c /etc/mosquitto/passwd kit | ||
| + | *sudo chown mosquitto:mosquitto /etc/mosquitto/passwd | ||
| + | *sudo chmod 600 /etc/mosquitto/passwd | ||
| + | ;Konfiguration kopieren | ||
| + | *sudo cp /etc/mosquitto/conf.d/defaults.conf.mit-password /etc/mosquitto/conf.d/defaults.conf | ||
| + | ;Konfigurationsdatei | ||
| + | *cat /etc/mosquitto/conf.d/defaults.conf | ||
| + | <pre> | ||
| + | # Öffnet den MQTT-Broker auf Port 1883 und bindet ihn an alle verfügbaren Netzwerkinterfaces. | ||
| + | listener 1883 0.0.0.0 | ||
| + | # Verbietet anonyme Verbindungen, Authentifizierung ist erforderlich. | ||
| + | allow_anonymous false | ||
| + | # Aktiviert alle Log-Typen für eine detaillierte Protokollierung. | ||
| + | log_type all | ||
| + | # Zeigt Verbindungs- und Trennungsmeldungen von Clients im Log an. | ||
| + | connection_messages true | ||
| + | # Gegen diese Datei wird authentifiziert. | ||
| + | password_file /etc/mosquitto/passwd | ||
| + | </pre> | ||
| + | ;Restarten | ||
| + | *sudo systemctl restart mosquitto.service | ||
| + | ;Checken | ||
| + | *systemctl status mosquitto.service | ||
| + | |||
| + | ==Aktor== | ||
| + | Der Aktor '''abonniert (subscribed)''' die Nachrichten und reagiert darauf. | ||
| + | *mosquitto_sub -h mqtt.dkbi.com -u kit -P '123Start$' -t test | ||
| + | ==Sensor== | ||
| + | Der Sensor '''sendet (published)''' die Nachrichten an das Topic. | ||
| + | *mosquitto_pub -h mqtt.dkbi.com -u kit -P '123Start$' -t test -m "Hello World" | ||
| + | *mosquitto_pub -h mqtt.dkbi.com -u kit -P '123Start$' -t test -m "2 Nachricht" | ||
| + | ==kali== | ||
| + | Hier kann man auf Wireshark mitschneiden. Der Text ist weiterhin im Klartext (Hexadezimal codiert) sichtbar — das Passwort schützt den Zugang, nicht die Übertragung. | ||
| + | ;Schaut mal, was man sieht. | ||
| + | |||
| + | =Anpassen von node.js= | ||
| + | ;sensor | ||
| + | *sudo cp /usr/local/control-switch/env.mit-passwd /usr/local/control-switch/.env | ||
| + | *cat /usr/local/control-switch/.env | ||
| + | MQTT_HOST=mqtt.dkbi.com | ||
| + | MQTT_PORT=1883 | ||
| + | MQTT_USER=kit | ||
| + | MQTT_PASS=123Start$ | ||
| + | ;Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen) | ||
| + | *cd /usr/local/control-switch/ | ||
| + | *nodejs server.js | ||
| + | ;Läuft es, als Service starten | ||
| + | *sudo systemctl restart control-switch.service | ||
| + | ;aktor | ||
| + | *sudo cp /usr/local/control/env.mit-passwd /usr/local/control/.env | ||
| + | *cat /usr/local/control/.env | ||
| + | MQTT_HOST=mqtt.dkbi.com | ||
| + | MQTT_PORT=1883 | ||
| + | MQTT_USER=kit | ||
| + | MQTT_PASS=123Start$ | ||
| + | ;Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen) | ||
| + | *cd /usr/local/control/ | ||
| + | *nodejs server.js | ||
| + | ;Läuft es, als Service starten | ||
| + | *sudo systemctl restart control.service | ||
| + | |||
| + | =Stufe 3= | ||
| + | =Verschlüsselt mit Passwort= | ||
| + | Zusätzlich zur Authentifizierung wird die Verbindung per TLS verschlüsselt. Auf dem Broker liegen das Server-Zertifikat (own.crt), der zugehörige private Schlüssel (own.key) und das Zertifikat der CA (kit-ca.crt). Die Clients prüfen den Broker gegen die CA. | ||
| + | ==mqtt== | ||
| + | *sudo cp /etc/mosquitto/conf.d/defaults.conf.verschlüsselt /etc/mosquitto/conf.d/defaults.conf | ||
| + | ;Konfigurationsdatei | ||
| + | *cat /etc/mosquitto/conf.d/defaults.conf | ||
| + | <pre> | ||
| + | # Öffnet den MQTT-Broker auf Port 8883 und bindet ihn an alle verfügbaren Netzwerkinterfaces. | ||
| + | listener 8883 0.0.0.0 | ||
| + | # Verbietet anonyme Verbindungen, Authentifizierung ist erforderlich. | ||
| + | allow_anonymous false | ||
| + | # Aktiviert alle Log-Typen für eine detaillierte Protokollierung. | ||
| + | log_type all | ||
| + | # Zeigt Verbindungs- und Trennungsmeldungen von Clients im Log an. | ||
| + | connection_messages true | ||
| + | # Gegen diese Datei wird authentifiziert. | ||
| + | password_file /etc/mosquitto/passwd | ||
| + | # Server-Zertifikat | ||
| + | certfile /etc/mosquitto/conf.d/own.crt | ||
| + | # Privater Schlüssel | ||
| + | keyfile /etc/mosquitto/conf.d/own.key | ||
| + | # Zertifikat der CA | ||
| + | cafile /etc/mosquitto/conf.d/kit-ca.crt | ||
| + | </pre> | ||
| + | ;Rechte setzen, damit der Broker Key und Zertifikate lesen darf | ||
| + | *sudo chown mosquitto:mosquitto /etc/mosquitto/conf.d/own.key /etc/mosquitto/conf.d/own.crt /etc/mosquitto/conf.d/kit-ca.crt | ||
| + | *sudo chmod 600 /etc/mosquitto/conf.d/own.key | ||
| + | *sudo chmod 644 /etc/mosquitto/conf.d/own.crt /etc/mosquitto/conf.d/kit-ca.crt | ||
| + | ;Restarten | ||
| + | *sudo systemctl restart mosquitto.service | ||
| + | ;Checken | ||
| + | *systemctl status mosquitto.service | ||
| + | |||
| + | ==Aktor== | ||
| + | Der Aktor '''abonniert (subscribed)''' die Nachrichten und reagiert darauf. | ||
| + | *mosquitto_sub -h mqtt.dkbi.com -p 8883 --cafile /usr/local/control/kit-ca.crt -u kit -P '123Start$' -t test | ||
| + | ==Sensor== | ||
| + | Der Sensor '''sendet (published)''' die Nachrichten an das Topic. | ||
| + | *mosquitto_pub -h mqtt.dkbi.com -p 8883 --cafile /usr/local/control-switch/kit-ca.crt -u kit -P '123Start$' -t test -m "Hello World" | ||
| + | *mosquitto_pub -h mqtt.dkbi.com -p 8883 --cafile /usr/local/control-switch/kit-ca.crt -u kit -P '123Start$' -t test -m "2 Nachricht" | ||
| + | ==kali== | ||
| + | Hier kann man auf Wireshark mitschneiden. Der Verkehr ist jetzt TLS-verschlüsselt — der Klartext aus Stufe 1 und 2 ist nicht mehr lesbar. | ||
| + | ;Schaut mal, was man (nicht mehr) sieht. | ||
| + | =Anpassen von node.js= | ||
| + | ;sensor | ||
| + | *sudo cp /usr/local/control-switch/env.mit-tls /usr/local/control-switch/.env | ||
| + | *cat /usr/local/control-switch/.env | ||
| + | MQTT_HOST=mqtt.dkbi.com | ||
| + | MQTT_PORT=8883 | ||
| + | MQTT_USER=kit | ||
| + | MQTT_PASS=123Start$ | ||
| + | MQTT_TLS=true | ||
| + | MQTT_CA=/usr/local/control-switch/kit-ca.crt | ||
| + | ;Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen) | ||
| + | *cd /usr/local/control-switch/ | ||
| + | *nodejs server.js | ||
| + | ;Läuft es, als Service starten | ||
| + | *sudo systemctl restart control-switch.service | ||
| + | ;aktor | ||
| + | *sudo cp /usr/local/control/env.mit-tls /usr/local/control/.env | ||
| + | *cat /usr/local/control/.env | ||
| + | MQTT_HOST=mqtt.dkbi.com | ||
| + | MQTT_PORT=8883 | ||
| + | MQTT_USER=kit | ||
| + | MQTT_PASS=123Start$ | ||
| + | MQTT_TLS=true | ||
| + | MQTT_CA=/usr/local/control/kit-ca.crt | ||
| + | ;Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen) | ||
| + | *cd /usr/local/control/ | ||
| + | *nodejs server.js | ||
| + | ;Läuft es, als Service starten | ||
| + | *sudo systemctl restart control.service | ||
| + | =Stufe 4= | ||
| + | ==Verschlüsselt mit 2FA (Zertifikat + Passwort)== | ||
| + | Zusätzlich zum Passwort muss der Client ein gültiges Client-Zertifikat vorlegen. Damit greifen zwei Faktoren: Besitz (Zertifikat + privater Schlüssel) und Wissen (Passwort). | ||
| + | |||
| + | Auf dem Broker liegen das Server-Zertifikat (own.crt) mit dem privaten Schlüssel (own.key) und das Zertifikat der CA (kit-ca.crt). Dazu gibt es zwei Client-Zertifikate: sensor.crt/sensor.key und aktor.crt/aktor.key. | ||
| + | |||
| + | '''Wichtig:''' Mit <code>use_identity_as_username true</code> leitet der Broker den Benutzernamen aus dem CN des Client-Zertifikats ab. Die Benutzer in der passwd müssen daher '''sensor''' und '''aktor''' heißen (genau wie der CN), nicht kit. | ||
| + | |||
| + | ==mqtt== | ||
| + | ;Sensor Benutzer anlegen (CN des Client-Zertifikats) | ||
| + | *user: sensor | ||
| + | *pass: 123Start$ | ||
| + | *sudo mosquitto_passwd -c /etc/mosquitto/passwd sensor | ||
| + | ;Aktor Benutzer anlegen | ||
| + | *user: aktor | ||
| + | *pass: 123Start$ | ||
| + | ;Wichtig: hier kein -c, das sonst die Datei überschreibt. | ||
| + | *sudo mosquitto_passwd /etc/mosquitto/passwd aktor | ||
| + | ;Rechte setzen, damit der Broker die Datei lesen darf | ||
| + | *sudo chown mosquitto:mosquitto /etc/mosquitto/passwd | ||
| + | *sudo chmod 600 /etc/mosquitto/passwd | ||
| + | ;Kontrolle | ||
| + | *cat /etc/mosquitto/passwd | ||
| + | sensor:$7$101$... | ||
| + | aktor:$7$101$... | ||
| + | ;Konfiguration kopieren | ||
| + | *sudo cp /etc/mosquitto/conf.d/defaults.conf.verschlüsselt.2fa /etc/mosquitto/conf.d/defaults.conf | ||
| + | ;Konfigurationsdatei | ||
| + | *cat /etc/mosquitto/conf.d/defaults.conf | ||
| + | <pre> | ||
| + | # Öffnet den MQTT-Broker auf Port 8883 und bindet ihn an alle verfügbaren Netzwerkinterfaces. | ||
| + | listener 8883 0.0.0.0 | ||
| + | # Verbietet anonyme Verbindungen, Authentifizierung ist erforderlich. | ||
| + | allow_anonymous false | ||
| + | # Aktiviert alle Log-Typen für eine detaillierte Protokollierung. | ||
| + | log_type all | ||
| + | # Zeigt Verbindungs- und Trennungsmeldungen von Clients im Log an. | ||
| + | connection_messages true | ||
| + | # Gegen diese Datei wird authentifiziert. | ||
| + | password_file /etc/mosquitto/passwd | ||
| + | # Server-Zertifikat | ||
| + | certfile /etc/mosquitto/conf.d/own.crt | ||
| + | # Privater Schlüssel | ||
| + | keyfile /etc/mosquitto/conf.d/own.key | ||
| + | # Zertifikat der CA | ||
| + | cafile /etc/mosquitto/conf.d/kit-ca.crt | ||
| + | # Client-Zertifikat erforderlich (2FA: Besitz) | ||
| + | require_certificate true | ||
| + | # Benutzername wird aus dem CN des Client-Zertifikats abgeleitet | ||
| + | use_identity_as_username true | ||
| + | </pre> | ||
| + | ;Restarten | ||
| + | *sudo systemctl restart mosquitto.service | ||
| + | ;Checken | ||
| + | *systemctl status mosquitto.service | ||
| + | |||
| + | ==Aktor== | ||
| + | Der Aktor '''abonniert (subscribed)''' die Nachrichten und reagiert darauf. Auf der Kommandozeile entfällt das -u, der Benutzer kommt aus dem CN von aktor.crt | ||
| + | *mosquitto_sub -h mqtt.dkbi.com -p 8883 --cafile /usr/local/control/kit-ca.crt --cert /usr/local/control/aktor.crt --key /usr/local/control/aktor.key -u aktor -P '123Start$' -t test | ||
| + | |||
| + | ==Sensor== | ||
| + | Der Sensor '''sendet (published)''' die Nachrichten an das Topic. | ||
| + | *mosquitto_pub -h mqtt.dkbi.com -p 8883 --cafile /usr/local/control-switch/kit-ca.crt --cert /usr/local/control-switch/sensor.crt --key /usr/local/control-switch/sensor.key -u sensor -P '123Start$' -t test -m "Zertifikat + Passwort" | ||
| + | |||
| + | ==Gegenprobe== | ||
| + | Ohne Client-Zertifikat wird die Verbindung abgewiesen — der Besitz-Faktor fehlt. | ||
| + | *mosquitto_pub -h mqtt.dkbi.com -p 8883 --cafile /usr/local/control-switch/kit-ca.crt -u sensor -P '123Start$' -t test -m "ohne Cert" | ||
| + | Connection error: Connection Refused: not authorised. | ||
| + | |||
| + | ==kali== | ||
| + | Hier kann man auf Wireshark mitschneiden. Der Verkehr ist weiterhin TLS-verschlüsselt — ohne gültiges Client-Zertifikat kommt gar keine Verbindung mehr zustande. | ||
| + | ;Schaut mal, was man (nicht mehr) sieht. | ||
| + | |||
| + | =Anpassen von node.js= | ||
| + | '''Hinweis zum Benutzernamen:''' Auf der Kommandozeile (mosquitto_pub/sub) kann -u entfallen, der Broker nimmt den CN aus dem Zertifikat. Die Bibliothek mqtt.js verlangt jedoch ein gesetztes username-Feld, sobald ein Passwort gesetzt ist (sonst: "Username is required to use password"). Daher steht MQTT_USER in der .env weiterhin drin — der Wert wird vom Broker durch den CN überschrieben. | ||
| + | ;sensor | ||
| + | *sudo cp /usr/local/control-switch/env.mit-2fa /usr/local/control-switch/.env | ||
| + | *cat /usr/local/control-switch/.env | ||
| + | MQTT_HOST=mqtt.dkbi.com | ||
| + | MQTT_PORT=8883 | ||
| + | MQTT_USER=sensor | ||
| + | MQTT_PASS=123Start$ | ||
| + | MQTT_TLS=true | ||
| + | MQTT_CA=/usr/local/control-switch/kit-ca.crt | ||
| + | MQTT_CERT=/usr/local/control-switch/sensor.crt | ||
| + | MQTT_KEY=/usr/local/control-switch/sensor.key | ||
| + | ;Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen) | ||
| + | *cd /usr/local/control-switch/ | ||
| + | *nodejs server.js | ||
| + | ;Läuft es, als Service starten | ||
| + | *sudo systemctl restart control-switch.service | ||
| + | ;aktor | ||
| + | *sudo cp /usr/local/control/env.mit-2fa /usr/local/control/.env | ||
| + | *cat /usr/local/control/.env | ||
| + | MQTT_HOST=mqtt.dkbi.com | ||
| + | MQTT_PORT=8883 | ||
| + | MQTT_USER=aktor | ||
| + | MQTT_PASS=123Start$ | ||
| + | MQTT_TLS=true | ||
| + | MQTT_CA=/usr/local/control/kit-ca.crt | ||
| + | MQTT_CERT=/usr/local/control/aktor.crt | ||
| + | MQTT_KEY=/usr/local/control/aktor.key | ||
| + | ;Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen) | ||
| + | *cd /usr/local/control/ | ||
| + | *nodejs server.js | ||
| + | ;Läuft es, als Service starten | ||
| + | *sudo systemctl restart control.service | ||
Aktuelle Version vom 20. Juni 2026, 12:20 Uhr
Stufe 1
Grundaufbau
Connectivity
ssh
Zugriff von einem internen Client
- mqtt
- ssh kit@mqtt.dkbi.com
- sensor
- ssh kit@sensor.dkbi.com
- aktor
- ssh kit@aktor.dkbi.com
http
- sensor
- aktor
Unverschlüsselt ohne Passwort
mqtt
- Konfiguration kopieren
- sudo cp /etc/mosquitto/conf.d/defaults.conf.ohne-password /etc/mosquitto/conf.d/defaults.conf
- Konfigurationsdatei
- cat /etc/mosquitto/conf.d/defaults.conf
# Öffnet den MQTT-Broker auf Port 1883 und bindet ihn an alle verfügbaren Netzwerkinterfaces. listener 1883 0.0.0.0 # Erlaubt anonyme Verbindungen, d. h. ohne Benutzername und Passwort. allow_anonymous true # Aktiviert alle Log-Typen für eine detaillierte Protokollierung. log_type all # Zeigt Verbindungs- und Trennungsmeldungen von Clients im Log an. connection_messages true
- Restarten
- sudo systemctl restart mosquitto.service
- Checken
- systemctl status mosquitto.service
Aktor
Der Aktor abonniert (subscribed) die Nachrichten und reagiert darauf.
- mosquitto_sub -h mqtt.dkbi.com -t test
Sensor
Der Sensor sendet (published) die Nachrichten an das Topic.
- mosquitto_pub -h mqtt.dkbi.com -t test -m "Hello World"
- mosquitto_pub -h mqtt.dkbi.com -t test -m "2 Nachricht"
kali
Hier kann man auf Wireshark mitschneiden. Der Text ist Hexadezimal codiert.
- Beispiel
- 536368616c7465206469652054757262696e656e20766f6d2041746f6d6b726166747765726b20617573
- Die kann man mit Follow TCP Stream oder auf der Konsole decodieren.
- echo -n "536368616c7465206469652054757262696e656e20766f6d2041746f6d6b726166747765726b20617573" | xxd -r -p
Schalte die Turbinen vom Atomkraftwerk aus
Node.js Umsetzung
Einführung in das Node.js-MQTT-Projekt
Dieses Projekt dient zur steuerbaren MQTT-basierten Hausautomation mit Node.js und Mosquitto als MQTT-Broker. Es ermöglicht das Schalten und Überwachen von Geräten wie Lichtquellen und Türschlössern über eine Web-Oberfläche.
Hauptbestandteile des Projekts
- Mosquitto MQTT-Broker
- Verwaltung der Nachrichten zwischen Sensoren und Aktoren. Zunächst ohne Authentifizierung, später mit Benutzer/Passwort und TLS.
- Node.js-Backend mit Express.js
- Verbindet sich als MQTT-Client zum Broker. Abonniert Status-Topics und aktualisiert den Gerätestatus. Bietet eine REST-API, um den Status abzufragen und Geräte zu steuern.
- Web-Interface
- Zeigt den aktuellen Gerätestatus in einer einfachen Oberfläche. Ermöglicht das Schalten der Geräte per Klick. Aktualisiert sich automatisch über API-Anfragen.
Schrittweise Absicherung
Das Projekt startet mit einer offenen MQTT-Verbindung, wird dann um Benutzer/Passwort ergänzt und am Ende mit TLS-Verschlüsselung abgesichert.
Node.js konkret
Sensor
- Verzeichnis
- /usr/local/control-switch
Wichtige Dateien
- JavaScript Datei
- server.js
- HTML Datei
- index.html
- Die Umgebungsvariablen
- .env
- Service Unit
- sudo systemctl restart control-switch.service
Zugriff
- Siehe oben per https
Aktor
- Verzeichnis
- /usr/local/control
Wichtige Dateien
- JavaScript Datei
- server.js
- HTML Datei
- index.html
- Die Umgebungsvariablen
- .env
- Service Unit
- sudo systemctl restart control.service
Zugriff
- Siehe oben per https
Anpassen von node.js
- sensor
- sudo cp /usr/local/control-switch/env.ohne-passwd /usr/local/control-switch/.env
- cat /usr/local/control-switch/.env
MQTT_HOST=mqtt.dkbi.com MQTT_PORT=1883
- Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen)
- cd /usr/local/control-switch/
- nodejs server.js
- Läuft es, als Service starten
- sudo systemctl restart control-switch.service
- aktor
- sudo cp /usr/local/control/env.ohne-passwd /usr/local/control/.env
- cat /usr/local/control/.env
MQTT_HOST=mqtt.dkbi.com MQTT_PORT=1883
- Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen)
- cd /usr/local/control/
- nodejs server.js
- Läuft es, als Service starten
- sudo systemctl restart control.service
Stufe 2
Unverschlüsselt mit Passwort
mqtt
- Benutzer anlegen
- user: kit
- pass: 123Start$
- rm -f /etc/mosquitto/passwd
- sudo mosquitto_passwd -c /etc/mosquitto/passwd kit
- sudo chown mosquitto:mosquitto /etc/mosquitto/passwd
- sudo chmod 600 /etc/mosquitto/passwd
- Konfiguration kopieren
- sudo cp /etc/mosquitto/conf.d/defaults.conf.mit-password /etc/mosquitto/conf.d/defaults.conf
- Konfigurationsdatei
- cat /etc/mosquitto/conf.d/defaults.conf
# Öffnet den MQTT-Broker auf Port 1883 und bindet ihn an alle verfügbaren Netzwerkinterfaces. listener 1883 0.0.0.0 # Verbietet anonyme Verbindungen, Authentifizierung ist erforderlich. allow_anonymous false # Aktiviert alle Log-Typen für eine detaillierte Protokollierung. log_type all # Zeigt Verbindungs- und Trennungsmeldungen von Clients im Log an. connection_messages true # Gegen diese Datei wird authentifiziert. password_file /etc/mosquitto/passwd
- Restarten
- sudo systemctl restart mosquitto.service
- Checken
- systemctl status mosquitto.service
Aktor
Der Aktor abonniert (subscribed) die Nachrichten und reagiert darauf.
- mosquitto_sub -h mqtt.dkbi.com -u kit -P '123Start$' -t test
Sensor
Der Sensor sendet (published) die Nachrichten an das Topic.
- mosquitto_pub -h mqtt.dkbi.com -u kit -P '123Start$' -t test -m "Hello World"
- mosquitto_pub -h mqtt.dkbi.com -u kit -P '123Start$' -t test -m "2 Nachricht"
kali
Hier kann man auf Wireshark mitschneiden. Der Text ist weiterhin im Klartext (Hexadezimal codiert) sichtbar — das Passwort schützt den Zugang, nicht die Übertragung.
- Schaut mal, was man sieht.
Anpassen von node.js
- sensor
- sudo cp /usr/local/control-switch/env.mit-passwd /usr/local/control-switch/.env
- cat /usr/local/control-switch/.env
MQTT_HOST=mqtt.dkbi.com MQTT_PORT=1883 MQTT_USER=kit MQTT_PASS=123Start$
- Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen)
- cd /usr/local/control-switch/
- nodejs server.js
- Läuft es, als Service starten
- sudo systemctl restart control-switch.service
- aktor
- sudo cp /usr/local/control/env.mit-passwd /usr/local/control/.env
- cat /usr/local/control/.env
MQTT_HOST=mqtt.dkbi.com MQTT_PORT=1883 MQTT_USER=kit MQTT_PASS=123Start$
- Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen)
- cd /usr/local/control/
- nodejs server.js
- Läuft es, als Service starten
- sudo systemctl restart control.service
Stufe 3
Verschlüsselt mit Passwort
Zusätzlich zur Authentifizierung wird die Verbindung per TLS verschlüsselt. Auf dem Broker liegen das Server-Zertifikat (own.crt), der zugehörige private Schlüssel (own.key) und das Zertifikat der CA (kit-ca.crt). Die Clients prüfen den Broker gegen die CA.
mqtt
- sudo cp /etc/mosquitto/conf.d/defaults.conf.verschlüsselt /etc/mosquitto/conf.d/defaults.conf
- Konfigurationsdatei
- cat /etc/mosquitto/conf.d/defaults.conf
# Öffnet den MQTT-Broker auf Port 8883 und bindet ihn an alle verfügbaren Netzwerkinterfaces. listener 8883 0.0.0.0 # Verbietet anonyme Verbindungen, Authentifizierung ist erforderlich. allow_anonymous false # Aktiviert alle Log-Typen für eine detaillierte Protokollierung. log_type all # Zeigt Verbindungs- und Trennungsmeldungen von Clients im Log an. connection_messages true # Gegen diese Datei wird authentifiziert. password_file /etc/mosquitto/passwd # Server-Zertifikat certfile /etc/mosquitto/conf.d/own.crt # Privater Schlüssel keyfile /etc/mosquitto/conf.d/own.key # Zertifikat der CA cafile /etc/mosquitto/conf.d/kit-ca.crt
- Rechte setzen, damit der Broker Key und Zertifikate lesen darf
- sudo chown mosquitto:mosquitto /etc/mosquitto/conf.d/own.key /etc/mosquitto/conf.d/own.crt /etc/mosquitto/conf.d/kit-ca.crt
- sudo chmod 600 /etc/mosquitto/conf.d/own.key
- sudo chmod 644 /etc/mosquitto/conf.d/own.crt /etc/mosquitto/conf.d/kit-ca.crt
- Restarten
- sudo systemctl restart mosquitto.service
- Checken
- systemctl status mosquitto.service
Aktor
Der Aktor abonniert (subscribed) die Nachrichten und reagiert darauf.
- mosquitto_sub -h mqtt.dkbi.com -p 8883 --cafile /usr/local/control/kit-ca.crt -u kit -P '123Start$' -t test
Sensor
Der Sensor sendet (published) die Nachrichten an das Topic.
- mosquitto_pub -h mqtt.dkbi.com -p 8883 --cafile /usr/local/control-switch/kit-ca.crt -u kit -P '123Start$' -t test -m "Hello World"
- mosquitto_pub -h mqtt.dkbi.com -p 8883 --cafile /usr/local/control-switch/kit-ca.crt -u kit -P '123Start$' -t test -m "2 Nachricht"
kali
Hier kann man auf Wireshark mitschneiden. Der Verkehr ist jetzt TLS-verschlüsselt — der Klartext aus Stufe 1 und 2 ist nicht mehr lesbar.
- Schaut mal, was man (nicht mehr) sieht.
Anpassen von node.js
- sensor
- sudo cp /usr/local/control-switch/env.mit-tls /usr/local/control-switch/.env
- cat /usr/local/control-switch/.env
MQTT_HOST=mqtt.dkbi.com MQTT_PORT=8883 MQTT_USER=kit MQTT_PASS=123Start$ MQTT_TLS=true MQTT_CA=/usr/local/control-switch/kit-ca.crt
- Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen)
- cd /usr/local/control-switch/
- nodejs server.js
- Läuft es, als Service starten
- sudo systemctl restart control-switch.service
- aktor
- sudo cp /usr/local/control/env.mit-tls /usr/local/control/.env
- cat /usr/local/control/.env
MQTT_HOST=mqtt.dkbi.com MQTT_PORT=8883 MQTT_USER=kit MQTT_PASS=123Start$ MQTT_TLS=true MQTT_CA=/usr/local/control/kit-ca.crt
- Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen)
- cd /usr/local/control/
- nodejs server.js
- Läuft es, als Service starten
- sudo systemctl restart control.service
Stufe 4
Verschlüsselt mit 2FA (Zertifikat + Passwort)
Zusätzlich zum Passwort muss der Client ein gültiges Client-Zertifikat vorlegen. Damit greifen zwei Faktoren: Besitz (Zertifikat + privater Schlüssel) und Wissen (Passwort).
Auf dem Broker liegen das Server-Zertifikat (own.crt) mit dem privaten Schlüssel (own.key) und das Zertifikat der CA (kit-ca.crt). Dazu gibt es zwei Client-Zertifikate: sensor.crt/sensor.key und aktor.crt/aktor.key.
Wichtig: Mit use_identity_as_username true leitet der Broker den Benutzernamen aus dem CN des Client-Zertifikats ab. Die Benutzer in der passwd müssen daher sensor und aktor heißen (genau wie der CN), nicht kit.
mqtt
- Sensor Benutzer anlegen (CN des Client-Zertifikats)
- user: sensor
- pass: 123Start$
- sudo mosquitto_passwd -c /etc/mosquitto/passwd sensor
- Aktor Benutzer anlegen
- user: aktor
- pass: 123Start$
- Wichtig
- hier kein -c, das sonst die Datei überschreibt.
- sudo mosquitto_passwd /etc/mosquitto/passwd aktor
- Rechte setzen, damit der Broker die Datei lesen darf
- sudo chown mosquitto:mosquitto /etc/mosquitto/passwd
- sudo chmod 600 /etc/mosquitto/passwd
- Kontrolle
- cat /etc/mosquitto/passwd
sensor:$7$101$... aktor:$7$101$...
- Konfiguration kopieren
- sudo cp /etc/mosquitto/conf.d/defaults.conf.verschlüsselt.2fa /etc/mosquitto/conf.d/defaults.conf
- Konfigurationsdatei
- cat /etc/mosquitto/conf.d/defaults.conf
# Öffnet den MQTT-Broker auf Port 8883 und bindet ihn an alle verfügbaren Netzwerkinterfaces. listener 8883 0.0.0.0 # Verbietet anonyme Verbindungen, Authentifizierung ist erforderlich. allow_anonymous false # Aktiviert alle Log-Typen für eine detaillierte Protokollierung. log_type all # Zeigt Verbindungs- und Trennungsmeldungen von Clients im Log an. connection_messages true # Gegen diese Datei wird authentifiziert. password_file /etc/mosquitto/passwd # Server-Zertifikat certfile /etc/mosquitto/conf.d/own.crt # Privater Schlüssel keyfile /etc/mosquitto/conf.d/own.key # Zertifikat der CA cafile /etc/mosquitto/conf.d/kit-ca.crt # Client-Zertifikat erforderlich (2FA: Besitz) require_certificate true # Benutzername wird aus dem CN des Client-Zertifikats abgeleitet use_identity_as_username true
- Restarten
- sudo systemctl restart mosquitto.service
- Checken
- systemctl status mosquitto.service
Aktor
Der Aktor abonniert (subscribed) die Nachrichten und reagiert darauf. Auf der Kommandozeile entfällt das -u, der Benutzer kommt aus dem CN von aktor.crt
- mosquitto_sub -h mqtt.dkbi.com -p 8883 --cafile /usr/local/control/kit-ca.crt --cert /usr/local/control/aktor.crt --key /usr/local/control/aktor.key -u aktor -P '123Start$' -t test
Sensor
Der Sensor sendet (published) die Nachrichten an das Topic.
- mosquitto_pub -h mqtt.dkbi.com -p 8883 --cafile /usr/local/control-switch/kit-ca.crt --cert /usr/local/control-switch/sensor.crt --key /usr/local/control-switch/sensor.key -u sensor -P '123Start$' -t test -m "Zertifikat + Passwort"
Gegenprobe
Ohne Client-Zertifikat wird die Verbindung abgewiesen — der Besitz-Faktor fehlt.
- mosquitto_pub -h mqtt.dkbi.com -p 8883 --cafile /usr/local/control-switch/kit-ca.crt -u sensor -P '123Start$' -t test -m "ohne Cert"
Connection error: Connection Refused: not authorised.
kali
Hier kann man auf Wireshark mitschneiden. Der Verkehr ist weiterhin TLS-verschlüsselt — ohne gültiges Client-Zertifikat kommt gar keine Verbindung mehr zustande.
- Schaut mal, was man (nicht mehr) sieht.
Anpassen von node.js
Hinweis zum Benutzernamen: Auf der Kommandozeile (mosquitto_pub/sub) kann -u entfallen, der Broker nimmt den CN aus dem Zertifikat. Die Bibliothek mqtt.js verlangt jedoch ein gesetztes username-Feld, sobald ein Passwort gesetzt ist (sonst: "Username is required to use password"). Daher steht MQTT_USER in der .env weiterhin drin — der Wert wird vom Broker durch den CN überschrieben.
- sensor
- sudo cp /usr/local/control-switch/env.mit-2fa /usr/local/control-switch/.env
- cat /usr/local/control-switch/.env
MQTT_HOST=mqtt.dkbi.com MQTT_PORT=8883 MQTT_USER=sensor MQTT_PASS=123Start$ MQTT_TLS=true MQTT_CA=/usr/local/control-switch/kit-ca.crt MQTT_CERT=/usr/local/control-switch/sensor.crt MQTT_KEY=/usr/local/control-switch/sensor.key
- Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen)
- cd /usr/local/control-switch/
- nodejs server.js
- Läuft es, als Service starten
- sudo systemctl restart control-switch.service
- aktor
- sudo cp /usr/local/control/env.mit-2fa /usr/local/control/.env
- cat /usr/local/control/.env
MQTT_HOST=mqtt.dkbi.com MQTT_PORT=8883 MQTT_USER=aktor MQTT_PASS=123Start$ MQTT_TLS=true MQTT_CA=/usr/local/control/kit-ca.crt MQTT_CERT=/usr/local/control/aktor.crt MQTT_KEY=/usr/local/control/aktor.key
- Zum Testen im Vordergrund (zeigt Verbindungs- und Fehlermeldungen)
- cd /usr/local/control/
- nodejs server.js
- Läuft es, als Service starten
- sudo systemctl restart control.service
