DIY Dry box — Part 5
Everything is now in place… except there’s nothing to monitor the humidity in the boxes anymore. As I said before, I’m not fond of the battery powered hygrometers.
The best solution here is to have desiccant that change color when wet and design the desiccant box in a way that allows to see the color from the outside.
But that’s not what I chose. I wanted to experiment with something else. Being a software engineer, this project was lacking software so far 😉.
The idea is to put a hygrometer chip in each box, link them to a microcontroller through an I²C bus. Then develop a program for the microcontroller to fetch the humidity level of each sensor and send it to an MQTT server.
First the MQTT server. MQTT is a message queuing system, so the microcontroller will send messages to it, and they will be consumed by something else (a bit more on that later). Mosquitto is probably the most well known MQTT server implementation, and there are docker images for it.
A well known thing about IoT, is that the “S” in “IoT” stands for security… so there are a few things I want to put in place:
- Encrypted channel, by default MQTT messages are sent over the network in plain text.
- Authentication, you may prevent eavesdropping by encrypting the communication, but if anyone can log into the system and read the content, that’s pointless. Both work together: having authentication but not encrypting the communication leaves eavesdroppers the possibility to steal the authentication credentials.
- Add ACL: the microcontroller should be allowed to only post in its topics, not others, while the visualization client should be able to read all the topics it is allowed to.
As it could be expected, securing an MQTT channel simply consists in tunneling it through TLS. TLS works better with a valid certificate, we can generate one with Let’s encrypt.
There are plenty of ways to do so. Here I’ll use Traefik proxy, which is a reverse proxy that can generate Let’s encrypt certificates automatically. All incoming connections will go through Traefik, Traefik will be in charge of the TLS part, but then the connections between Traefik and the other Docker containers will not be encrypted.
Example of docker compose file:
- Lines 7 to 10: ports opened on the container and exposed to the network. 80 and 443 for HTTP and HTTPS, used by Let’s encrypt to validate certificates. Port 8883 is the standard MQTT over TLS port.
- Lines 14 to 16: definition of endpoints in Traefik, basically the ports Traefik will listen to.
- Lines 20 to 22: Let’s encrypt configuration. Your Let’s encrypt account email address, where the certificates will be stored (they need to be on a permanent storage otherwise they will need to be generated each tie the container starts, then probably be blocked by Let’s encrypt quota…).
- Line 39: tell Traefik to route TCP connections to the mqtt container when the SNI matches the specified domain. Obviously the domain should be declared in DNS and point to the server.
- Lines 40 and 42: make the connection to the entrypoint called “mqtts” over TLS and use Let’s encrypt.
- Line 43: make the connection from the entrypoint to the mqtt container on port 1883 (standard non-encrypted MQTT port).
mosquitto.conf file, make sure anonymous connections are not allowed and specify the path to a password file.
Example of configuration file:
listener 1883 persistence true persistence_location /mosquitto/data log_dest file /mosquitto/log/mosquitto.log allow_anonymous false password_file /mosquitto/config/mosquitto.passwd
Now, create the password file, give mosquitto user (1883) ownership of the file, make sure its readable only by that user and call the
mosquitto_passwd command (living inside the docker container) in order to add credentials to the file:
sudo touch mosquitto.passwd sudo chown 1883:1883 mosquitto.passwd sudo chmod 600 mosquitto.passwd docker exec <mqtt-container-name> mosquitto_passwd -b /mosquitto/config/mosquitto.passwd <username> <password>
mosquitto.conf file, specify a file for ACL:
Then create the matching file on the server.
Here is an example of a user
home_automation that can do everything and a user
drybox that can only write to a specific topic:
user home_automation topic readwrite # user drybox topic write devices/drybox/#
More about security
This is a basic example, a few more things to consider:
- IoT devices should be in their own network with limited/no internet access;
- depending on your setup, the example here may expose some services to the internet, tweaking the configurations (firewall, router’s port forwarding…) is required;
- if access from outside the internal network is required, if possible, don’t expose the services to the internet but connect to the internal network through a VPN;
- keep everything up-to-date.
Make sure mosquitto has been restarted to take into account the modifications made in the configuration file.
Install an MQTT client, for instance on debian:
sudo apt install mosquitto-clients
In a terminal, subscribe to all topics:
mosquitto_sub -h mqtt.example.com -p 8883 -u home_automation -P <password> -t '#' -v
In another terminal, send messages like:
mosquitto_pub -h mqtt.exmaple.com -p 8883 -u home_automation -P <password> -t devices/drybox/humidity -m 36
On the first terminal, the messages and their topic should be displayed.
Any messages sent to a topic the user is not allowed to write should not be received by the subscribed user. A wrong login and/or password should throw an error message, likewise when not providing any credentials.