DennisOSRM / hms-mqtt-publisher

HMS-XXXXW-2T MQTT publisher and Home Assistant addon
BSD 2-Clause "Simplified" License
111 stars 16 forks source link

Allow MQTT connection to be TLS encrypted #90

Open dicer opened 7 months ago

dicer commented 7 months ago

I have a MQTT server which allows access via TLS only. Just setting the port to 8883 results in a lot of complaining by the server as hms-mqtt-publisher seems to reconnect really fast and often, but not with TLS enabled.

Is there a way this could be implemented and exposed to the config.toml?

DennisOSRM commented 7 months ago

Sure, this can be implemented. Probably wouldn't even take that long. Biggest barrier would be to setup a server with TLS support for testing. Is there some good tutorial how to do that?

dicer commented 7 months ago

I tried to implement this myself, but this is the first time I fumble with rust, so I couldn't get thinks very far... This is what I came up with after reading lots of docs, but I couldn't get it to compile yet:

In rumqttc_wrapper.rs:

        let root_cert_store = rustls::RootCertStore {
            roots: webpki_roots::TLS_SERVER_ROOTS.iter().cloned().collect(),
        };

        let client_config = tokio_rustls::rustls::ClientConfig::builder()
          //  .with_safe_defaults()
            .with_root_certificates(root_cert_store)
            .with_no_client_auth();

        mqttoptions.set_transport(Transport::tls_with_config(client_config.into()));

I think webpki_roots is a good idea, cause in a docker environment there might not be any certs available for rust to load.

Regarding a TLS supported MQTT server you could try testing with https://www.hivemq.com/products/mqtt-cloud-broker/ They offer a free cloud server. Alternatively you could use the official mosquitto docker container, get some LetsEncrypt certs and configure it something like this:

listener 8883
protocol mqtt
cafile   /mosquitto/config/ca.crt
certfile /mosquitto/config/server.crt
keyfile  /mosquitto/config/server.key
tls_version tlsv1.2
DennisOSRM commented 7 months ago

I think I got this to work. The code change is PR #93, but it needs testing. As of writing it is only tested on macOS/X86. And should work, but with TLS things might be funny on other platforms.

Btw, I implemented this using a free instance from hivemq and their web client.

Bildschirmfoto 2024-02-03 um 15 25 59
DennisOSRM commented 7 months ago

Also tested on rPi4/Ubuntu successfully

dicer commented 7 months ago

Thanks! This does not work for me, but I think it is because of my self-signed cert I'm currently running with :( I have all the certs in the right place, but something is going wrong. The server is showing me OpenSSL Error[0]: error:1403F418:SSL routines:ACCEPT_SR_FINISHED:tlsv1 alert unknown ca. Well, not up to you to debug. Just writing this here so you know I'm trying to test but I'm not quite there yet...

What I did notice though: When running in the docker container, there are no system CAs installed in /etc/ssl/certs. Have you tried running this PR in a container? I added a RUN apt-get update && apt-get -y install ca-certificates but as written above I'm not able to verify if this is necessary or not.

DennisOSRM commented 7 months ago

What I did notice though: When running in the docker container, there are no system CAs installed in /etc/ssl/certs. Have you tried running this PR in a container? I added a RUN apt-get update && apt-get -y install ca-certificates but as written above I'm not able to verify if this is necessary or not.

Haven't tried to run it in a container, yet. But adding system CAs sounds like a necessary step.

dicer commented 7 months ago

I had some time to test this and can confirm this works with a mosquitto server using letsencrypt certificates. The one thing missing for me: The supplied Dockerfile does not come with CAs, so TLS with the official docker image is not working at all at the moment. I fixed this by building the container with the following addition to the Dockerfile:

...
# Copy the installed application from the build image to the smaller image.
COPY --from=builder /usr/local/cargo/bin/hms-mqtt-publish /usr/local/bin/hms-mqtt-publish

# Install ca-certificates to support TLS connections
RUN apt-get update && apt-get -y install ca-certificates

# Generate the config file from given environment variables
...