Learn how to create a more secure authentication process for your smart home builds with MariaDB and Mosquitto.
In nearly all smart home environments with homemade devices, MQTT is the communication protocol of choice. MQTT is popular not only in the DIY domain, but also in the domain of IoT and even IIoT (industrial internet of things, which is a central part of the European Industrie 4.0 strategy).
It’s not a stretch to say MQTT is an important protocol and a central and important component in those environments is an MQTT broker. MQTT and the function of the broker has been widely discussed. If you’re just starting to learn MQTT, check out these tutorials:
The Mosquitto Broker
A quite common, dead-simple but still feature-rich enough broker is the Mosquitto broker from the Eclipse project of the same name. It is preferred in smart home setups and industrial installations with a limited amount of connected devices and/or low to medium data rate or during prototyping phases. (For large scale installations or huge data rates the operations teams tend to prefer HiveMQ or VerneMQ.)
Mosquitto comes with a complete set of tools and is easy to install, since it is both available as an image on Docker Hub and as a package in several Linux distributions, such as Debian or Raspbian.
Setting Up the Mosquitto MQTT Broker
Getting an Mosquitto MQTT broker up and running is as simple as
apt-get install mosquitto
or
docker run mosquitto/mosquitto:latest
Sometimes the configuration file needs to be adjusted a bit or a volume for persistent storage has to be provided to Docker. However, you can usually start publishing MQTT messages and subscribing to MQTT topics within under an hour. The Python library from Paho or the PubSub library for the Arduino, which can also be used on the ESP8266, the ESP32 or the Teensy, are so simple that literally only a few lines of code are required for the clients.
Adding Security for Smart Home Set-ups
Unfortunately, one significant drawback of this simple setup is that it lacks authentication and authorization.
As long as you are with all your devices and your broker in your safe and warm home, with LAN or Wi-Fi and you only connect sensors to this setup — and not for instance an electronic front door lock — this is fine. Maybe you could be a bit paranoid and separate an isolated home automation VLAN from your default LAN and Wi-Fi where your kids and your guests are connected to and access the Internet. Maybe, if you also have some commercial devices in your setup and want to block them from calling home, you block or at least limit the Internet access of this VLAN. But that's fair enough under these conditions.
As soon as you want to measure the fill level in the rain water tanks in your garden on the other side of town or want to connect a home grown GPS tracker to your bike or the door and window alarm of your mobile home, you need to open the broker to the Internet. When that happens, the conditions change fundamentally. Neither unencrypted nor un-authenticated/authorized communication is acceptable anymore.
Introducing certificates for SSL/TLS encryption of the communication is still straightforward.
I usually generate certificates and keys using XCA, also the signing can be handled here when you’ve created your own CA upfront.
The required Mosquitto configuration is as simple as:
listener 8883 0.0.0.0
cafile /etc/mosquitto/ca_certificates/ca.crt
certfile /etc/mosquitto/certs/broker.crt
keyfile /etc/mosquitto/certs/broker.key
Also, providing a simple user database for authentication in the form of a password file is dead simple.
password_file /etc/mosquitto/pwfile
This file can be maintained using the included mosquitto_passwd tool. But it has a major drawback: you need to restart the broker when you’ve updated the file. This is almost an incident that requires a maintenance window in large scale integrations when thousands of clients get kicked off and all reconnect more or less at the same time — the broker will go down immediately again and you have a problem. That would need to be considered in the system architecture. You would also want to avoid that in a smart home installation. I regularly see situations where clients do not reconnect correctly and need to be restarted as well.
Security Authentication Using a Database
A much better solution would be an authentication backend using a database. Fortunately, there are two plugins available, the first of which is a bit outdated. Here, however, the fundamental work in this scope has been done (thank you very much to the author of this GitHub page!) and a more recent one based on the first one which does a good job and that I deploy in my installations.
To use this plugin, a MariaDB or MySQL server is required. If you don’t already have one or you reckon databases are a complicated topic, don’t be afraid! It is also only a docker pull away.
The following schema must be deployed:
CREATE TABLE users (
id INTEGER AUTO_INCREMENT,
username VARCHAR(25) NOT NULL,
pw VARCHAR(512) NOT NULL,
super INT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (id)
);
CREATE UNIQUE INDEX users_username
ON users (username);
CREATE TABLE acls (
id INTEGER AUTO_INCREMENT,
username VARCHAR(25) NOT NULL,
topic VARCHAR(256) NOT NULL,
rw INTEGER(1) NOT NULL DEFAULT 1, -- 1 is read, 2 is write,
-- 3 is readwrite, 4 is
-- subscribe
PRIMARY KEY (id)
);
CREATE UNIQUE INDEX acls_user_topic
ON acls (username, topic(228));
You can easily deploy this using the mysql command line tool (even in the MariaDB installation, it is still called mysql) or using HeidiSQL.
The Mosquitto configuration file also has to be adjusted a bit. The following snippet just gives the authentication plugin related lines:
#allow_anonymous true
allow_anonymous false
auth_plugin /opt/lib/go-auth.so
auth_opt_log_dest stdout
auth_opt_log_level debug
auth_opt_backends mysql
auth_opt_mysql_host mariadb
auth_opt_mysql_port 3306
auth_opt_mysql_dbname mosquittoauth
auth_opt_mysql_user mosquittoauth
auth_opt_mysql_password xxx
auth_opt_mysql_allow_native_passwords true
auth_opt_mysql_userquery SELECT pw FROM users WHERE username = ?
auth_opt_mysql_aclquery SELECT topic FROM acls WHERE username = ? AND (rw & ?) != 0
I intend to put every piece of software into a docker image to easily run it everywhere as a container, same as I’ve done here. I’ve prepared a Dockerfile and a start script for the container.
And as I learned to love the CI functionality of Gitlab, all the build stuff is performed using a CI script. You find all that stuff on my Gitlab page. If you like to test the Docker image directly, you can get it from Docker Hub or simply pull it using docker pull wollud1969/mosquitto-with-auth.
You can see how I used the MQTT with database authentication in An Automated Light Switch System for Smarthomes That Anyone Can Use.