MQTT2_SERVER absichern/härten

Begonnen von spi3845, 21 Juni 2022, 16:36:42

Vorheriges Thema - Nächstes Thema

spi3845

Hallo zusammen,

bisher betreibe ich einige MQTT-Geräte am fhem MQTT2_SERVER, die alle selbst gebaut wurden und gemeinsam mit fhem in einem separierten, abgesicherten Netz stehen. Authentifizierung und TLS-Transportverschlüsselung nutze ich daher aus Verfügbarkeitsgründen nicht, sehr wohl aber, wenn es um Zugriffe auf andere meiner Systeme aus anderen Netzen geht.

Hier geht es mir um Überlegungen darum, wie ich den MQTT2-Server und damit fhem vor Manipulationen schützen kann durch Geräte, die ich entweder nicht genau kenne oder die in teilweise öffentlichen  Bereichen stehen. Authentifizierung und Transportverschlüsselung, vielleicht gar Client-Zertifikat-Authentisierung helfen in dem einen oder anderen Fall, sie helfen aber erst einmal nicht, wenn sich jemand Zugang zu einem MQTT-Device verschaffen und dann mit dem MQTT2-Server sprechen kann. Hier wäre es hilfreich, den MQTT2-Server selbst abzusichern, z. B. per allowed.

Was mir hier vorschwebt ist, dass ich für bestimmte MQTT-Devices im MQTT2-Server bestimmte Regeln vorgeben kann, z. B. welche topics das entsprechende Gerät posten oder abonnieren kann. Die Unterscheidung nach Geräten kann dann über Username, CID oder IP-Adresse etc. erfolgen, je nachdem, welches Kriterium in dem entsprechenden Fall geeignet ist.

Ich habe verstanden, dass ich allowed für die MQTT2-Server Instanz anlegen kann - das nutze ich bereits für FHEMWEB, um Zugang für bestimmte Geräte einzuschränken, z. B. dass sie nur ihren eigenen Kontext ändern (allowedDevicesRegexp) oder nur bestimmte Aktionen durchführen können (allowedCommands).

Im Falle von MQTT will ich aber nicht eine separate MQTT2-Server-Instanz aufsetzen, sondern mit einer Instanz serverseitig arbeiten und je MQTT-Device filtern bzw. vorgeben, was dieses Gerät darf (Autorisierung). Vielleicht ließe sich allowed an die Client-Instanzen (mqtt_broker_IP_port) binden, aber diese werden dynamisch erzeugt und eignen sich wohl nicht. Man könnte es auch an die MQTT2-Server-Instanz binden, aber dann bräuchte man irgendeine Art der Zuordnung zu dem jeweiligen Gerät, z. B. (device_IP|device_Name):allow(device-123/.*/command.(on|off)).

Ist so etwas bereits jetzt mit fhem möglich und ich habe es bisher einfach nur nicht gefunden?

Eine Alternative außerhalb fhem wäre ein separater MQTT-Server oder -Proxy, der die Anfragen entsprechend filtert und an fhem übergibt - auf fhem selbst wäre es aber einfacher zu pflegen, da dort auch die topics in den einzelnen Devices hinterlegt sind - cool wäre es, wenn man direkt dort per Einstellung definieren könnte, dass nur die dort konfigurierten Befehle für das einzelne MQTT-Device akzeptiert würden (würde aber autocreate killen).

Falls die Frage aufkommt, warum man einem MQTT-Device nicht vertrauen sollte, ein Beispiel: fhem-Server mit MQTT2-Instanz in gesicherter Umgebung. Veranstaltungsfläche mit vielen Aktoren, kommunizieren alle per MQTT mit fhem. Selbst wenn die Aktoren sich an fhem authentisieren und eine Transportverschlüsselung aktiv ist, könnte jemand mit gewissem Aufwand über den Aktor oder an seiner statt Zugang zum MQTT2 erhalten. Der Schutz durch Einschränkung möglicher Befehle (Autorisierung) sollte also nicht im MQTT-Device, sondern zentralen MQTT2-Server erfolgen.

Viele Grüße,
spi

rudolfkoenig

MQTT2_SERVER kennt z.Zt. nur Authenticate, nicht aber Authorize.

Um eine Authorisierung fuer MQTT2_SERVER (und CLIENT?) zu implementieren muesste man sowohl das allowed Modul um neue Typen erweitern (z.Zt. sind "nur" cmd und devicename implementiert), wie auch die entsprechenden Pruefungen in MQTT2_SERVER implementieren. Letzteres muesste optimiert passieren.

Bin nicht sicher, ob ich das angehen will, da ich das Problem (noch?) als speziell ansehe.
Womoeglich ist mosquitto mit seinem ACLs die bessere Loesung.

spi3845

Zitat von: rudolfkoenig am 21 Juni 2022, 17:07:36
Bin nicht sicher, ob ich das angehen will, da ich das Problem (noch?) als speziell ansehe.
Womoeglich ist mosquitto mit seinem ACLs die bessere Loesung.

Ha ha, kann ich gut verstehen. Mosquitto oder z. B. Janus MQTT Proxy sind auch gerade mein Ansatz dafür. Aber schon mal danke, dann habe ich da nichts übersehen.

spi3845

Zitat von: rudolfkoenig am 21 Juni 2022, 17:07:36
Bin nicht sicher, ob ich das angehen will, da ich das Problem (noch?) als speziell ansehe.
Falls Du deine Meinung änderst, sag Bescheid, vielleicht kann ich helfen und niedere Dienste leisten...

rudolfkoenig

Gibt es noch Weitere, die an sowas Interesse haetten?

spi3845

#5
Zitat von: rudolfkoenig am 22 Juni 2022, 08:53:57
Gibt es noch Weitere, die an sowas Interesse haetten?
Falls jemand schon jetzt MQTT filtern will, um fhem und andere Geräte zu schützen: ich habe das auf die Schnelle mit mosquitto gelöst. Läuft parallel auf meinem fhem-Server auf Port 8883. Dort ist eine ACL implementiert, die nach Usernamen bestimmte topics vorgibt - auf andere kann das Endgerät nicht zugreifen. Man kann die auch nach Client-IDs strukturieren oder gar in Gruppen organisieren, also ein aufwändigeres Berechtigungskonzept. Der mosquitto selber ist als MQTT-Bridge konfiguriert, so dass er sich als MQTT-Client mit MGTT2_SERVER verbindet. Der Flow sieht so aus:

mgtt-device -- ( mosquitto-Broker:8883 -- mosquitto-Client ) -- fhem mit MQTT2_SERVER:1883

Als Bridge kann man mosquitto mitgeben, welche Topics es zum MQTT2_SERVER kopieren und bei diesem auch wieder abonnieren soll. Das ist insofern einfach, weil man ein neues MQTT-Device per autocreate zuerst am MQTT2_SERVER erkennen lässt und konfiguriert. Dann zieht man es auf den mosquitto um (Portänderung auf MQTT-Device von 1883 auf 8883, ggf. Umzug in anderes Netzsegment oder Firewall-Regeländerung). Im mosquitto ACLs anpassen und ggf. topics in Bridge konfigueren. Mosquitto publiziert/abonniert die topics im MQTT2_SERVER, so dass das ursprünglich über den MQTT2_SERVER per autocreate erzeugte Gerät sofort funktioniert. Mit neuen Geräte funktioniert das genauso.

Alternativ lernt fhem neue MQTT-Devices über seine MQTT-Schnittstelle (=MQTT2_DEVICE) zu mosquitto - aber dann muss man eine Kopie des Device erzeugen, die readingList bereinigen, ggf. ein Template zuweisen. Da erscheint mit der zuerst beschriebene Weg einfacher.

Man könnte auch fhem als MQTT2_CLIENT mit dem mosquitto reden lassen, aber auch das erschien mir für meinen Anwendungsfall aufwändiger. Vielleicht brauche ich das mal in Zukunft, dann kann ich immer noch umstellen.

Die Configs für mosquitto als Beispiel für Shelly-Devices sehen so aus (Standard-Installation unter Debian, Configs liegen unter /etc/mosquitto und darunter):
/etc/mosquitto/conf.d/default.conf

# general config
#log_dest stdout
#log_type information
acl_file /etc/mosquitto/aclfile

# default listener
listener 8883
allow_anonymous true
#password_file /etc/mosquitto/passwd

# bridges
connection fhem_1883
address 127.0.0.1:1883
try_private true
cleansession true
topic shellies/+/# out 0
topic shellies/+/# in 0
remote_clientid bridge-01


/etc/mosquitto/aclfile

user shelly-eg01                                                                                                                                                                             
topic shellies/+/#                                                                                                                                                                           

# user shelly-xxx                                                                                                                                                                             
# topic shellies/+/#                                                                                                                                                                           

# oder falls es viele Devices mit gleichartiger topic-Struktur sind, kann man auch per Client-ID (%c) filtern
# aber dann könnten auch andere Devices auf diesen topic zugreifen, muss man abwägen
# pattern readwrite shellies/%c/#

# zum Checken die folgenden zwei Zeilen auskommentieren                                                                                                                                                                                             
#user admin                                                                                                                                                                                 
#topic #