You are on page 1of 25

Configuring MQTT on the Raspberry Pi

MQTT, which originally was an acronym for Message Queue Telemetry Transport, is a
lightweight message queue protocol designed for small data packets sent across high
latency, low bandwidth links. MQTT is a fairly simple protocol and it's perfect for Internet
of Things projects. It's also perfect for this security system project!

The version of MQTT I use in this tutorial is called Mosquitto. It is available via apt, so
installing it is quite easy. There are a number of steps in configuring the Raspberry Pi
component of the security system. As I mentioned, I'm using a Raspberry Pi 3.

The steps you need to follow are, at a high level:

1. Install mosquitto (MQTT) components.


2. Configure mosquitto and restart the service.
3. Copy in the security.py program and edit it for your installation.
4. Configure security.py to run at boot.
5. Start security.py.

As I've mentioned earlier, I'm using the Raspberry Pi 3 running the latest version of
Raspbian Jessie.

Step 1 - Install the Mosquitto (MQTT) Components


Installing mosquitto is as easy as running a few apt commands. First, though, we make sure
we're running the latest version of Jessie and that all the software is up to date. Here are the
commands to run to upgrade the system and install the mosquitto components:
1. sudo apt-get update
2. sudo apt-get upgrade
3. sudo apt-get dist-upgrade
4. sudo apt-get install mosquitto mosquitto-clients python-mosquitto

Step 2 - Configure Mosquitto and Restart the Service


Mosquitto is controlled in two ways. First, the default configuration is in
/etc/mosquitto/mosquitto.conf. I recommend you not edit this file, however, and instead, use
the second mechanism, which is a file with a .conf extension in /etc/mosquitto/conf.d. I
actually named mine mosquitto.conf, too, so the full path to the local configuration file is
/etc/mosquitto/conf.d/mosquitto.conf. This file is populated with example configurations by
default, so you'll want to edit it for your local use. Here is the local configuration file I
recommend:

1. # Config file for mosquitto


2. #
3. # See mosquitto.conf(5) for more information.
4.
5. user mosquitto
6. max_queued_messages 200
7. message_size_limit 0
8. allow_zero_length_clientid true
9. allow_duplicate_messages false
10.
11. listener 1883
12. autosave_interval 900
13. autosave_on_changes false
14. persistence true
15. persistence_file mosquitto.db
16. allow_anonymous true
17. password_file /etc/mosquitto/passwd

Once you have edited the configuration file, restart the service with the command

sudo systemctl restart mosquitto

Step 3 - Copy in the security.py Program and Edit it for


Your Installation
Here is the security.py program:
#######################################################################

# security.py - Monitors a Mosquitto MQTT queue for security events

# from an array of secufity sensors, detects critical changes in those

# sensor values, and injects alarms into an io.adafruit.com queue.

# Note: The hardware to do this is already developed (Feather Huzzah

# ESP8266 with NodeCMU), along with the Lua software to run on

# the ESP8266. The next development steps are:

# - write this python program

# - write the If This Then That interface to do notifications

# Note two: The implementation uses normally-closed reed switches

# from China. If you use normally open switches, you'll have to

# edit this code to invert the tests for the values coming from

# the sensors.

# Philip R. Moyer

# Adafruit

# May 2016

# This code is released under a BSD liense and is in the public domain.

# Any redistribution must include the above header.

#######################################################################
########################

# Libraries

########################

import os

import string

import paho.mqtt.client as mqtt

import Adafruit_IO

import time

########################

# Globals

########################

# -- Change these as needed for your installatin --

localBroker = "YOUR_BROKER_IP" # Local MQTT broker

localPort = 1883 # Local MQTT port

localUser = "YOUR_MQTT_USERID" # Local MQTT user

localPass = "YOUR_MQTT_PASSWORD" # Local MQTT password

localTopic = "/security" # Local MQTT topic to monitor

localTimeOut = 120 # Local MQTT session timeout

adafruitUser = "YOUR_ADAFRUIT_IO_USERID" # Adafruit.IO user ID


adafruitKey = "YOUR_ADAFRUIT_IO_KEY" # Adafruit.IO user key

adafruitTopic = "alarms" # Adafruit.IO alarm topic

# -- You should not need to change anything below this line --

sensorList = {} # List of sensor objects

########################

# Classes and Methods

########################

class sensor():

def __init__(self):

self.name = "" # Name of sensor in MQTT

self.humanName = "" # Human-meaningful name (e.g., "front door")

self.lastSeen = 0 # Number of seconds since the sensor was last seen

self.state = "unknown" # State of the object: unknown, open, or closed

def setState(self, newstate):

self.state = newState

def getState(self):

return self.state
def resetHeartbeat(self):

self.lastSeen = 0

def setname(self, newName, humanName):

self.name = newName

self.humanName = humanName

def getname(self):

return self.humanName

def checkState(self, newState):

if ("unknown" == self.state):

self.state = newState

return 0

else:

if (newState != self.state):

self.state = newState

if ("closed" == self.state):

return -1

else:

return 1

return 0
class sensorList():

def __init__(self):

self.sensorList = {}

def addSensor(self, sensorName, humanName):

self.sensorList[sensorName] = sensor()

self.sensorList[sensorName].setname(sensorName, humanName)

def getSensorName(self, sensorID):

return self.sensorList[sensorID].getname()

def sensorState(self, sensorID, monitorState):

rv = self.sensorList[sensorID].checkState(monitorState)

if (0 != rv):

# State changed!

if (0 > rv):

outBuf = "INFO "+self.getSensorName(sensorID)+"


"+monitorState

print(outBuf)

else:

outBuf = "ALARM "+self.getSensorName(sensorID)+"


"+monitorState

print(outBuf)
print("Initiating connection to Adafruit.IO")

AIOclient = Adafruit_IO.MQTTClient(adafruitUser,
adafruitKey)

print("Setting callbacks for Adafruit.IO")

AIOclient.on_connect = AIOconnected

AIOclient.on_disconnect = AIOdisconnected

AIOclient.on_message = AIOmessage

print("Connecting to Adafruit.IO")

AIOclient.connect()

time.sleep(5)

print("Publishing outBuf")

# AIOclient.publish("alarms", outBuf)

AIOclient.publish("alarms", outBuf)

print("Disconnecting")

AIOclient.disconnect()

########################

# Functions

########################

# Callback functions for Adafruit.IO connections

def AIOconnected(client):

# client.subscribe('alarms')

print("Connected to Adafruit.IO")

def AIOdisconnected(client):
print("adafruit.io client disconnected!")

def AIOmessage(client, feed_id, payload):

print("adafruit.io received ", payload)

# returnState takes a numeric voltage value from the sensor and

# returns the state of the monitored device. With a voltage divider

# that uses a 1M ohm R1 and a 470K ohm R2, the "closed" state returns

# 1024 and the open state returns between 1 and 40.

def returnState(inVal):

if (1000 < inVal):

return "closed"

if (100 > inVal):

return "open"

else:

return "unknown"

########################

# Main

######################

if "__main__" == __name__:

# Set timer
sensList = sensorList()

sensList.addSensor("security_001", "front door")

# The callback for when the client receives a CONNACK response from the server.

def on_connect(client, userdata, flags, rc):

print("Connected with result code "+str(rc))

# Subscribing in on_connect() means that if we lose the connection and

# reconnect then subscriptions will be renewed.

client.subscribe("/security")

# The callback for when a PUBLISH message is received from the server.

def on_message(client, userdata, msg):

(sensorID, sensorVoltage) = string.split(msg.payload)

sensorVoltage = string.atoi(sensorVoltage)

sensorName = sensList.getSensorName(sensorID)

sensList.sensorState(sensorID, returnState(sensorVoltage))

# print(sensorName+" "+returnState(sensorVoltage))

client = mqtt.Client()

client.on_connect = on_connect

client.on_message = on_message
client.connect(localBroker, localPort, localTimeOut)

# Blocking call that processes network traffic, dispatches callbacks and

# handles reconnecting.

# Other loop*() functions are available that give a threaded interface and a

# manual interface.

client.loop_forever()

quit()

Copy security.py to /home/pi/security.py on the machine that is your MQTT broker. Edit
the program so the parameters are correct for your installation. I recommend keeping the
"/security" topic, though.

You also need to install the Adafruit_IO Python library. You can clone it from the GitHub
repository or click this button to download a Zip file. Put it in the same directory as your
security.py program.

1. #######################################################################

2. # security.py - Monitors a Mosquitto MQTT queue for security events

3. # from an array of secufity sensors, detects critical changes in those

4. # sensor values, and injects alarms into an io.adafruit.com queue.

5. #

6. # Note: The hardware to do this is already developed (Feather Huzzah

7. # ESP8266 with NodeCMU), along with the Lua software to run on

8. # the ESP8266. The next development steps are:

9. # - write this python program

10. # - write the If This Then That interface to do notifications

11. #
12. # Note two: The implementation uses normally-closed reed switches

13. # from China. If you use normally open switches, you'll have to

14. # edit this code to invert the tests for the values coming from

15. # the sensors.

16. #

17. # Philip R. Moyer

18. # Adafruit

19. # May 2016

20. #

21. # This code is released under a BSD liense and is in the public domain.

22. # Any redistribution must include the above header.

23. #######################################################################

24.

25. ########################

26. # Libraries

27. ########################

28.

29. import os

30. import string

31. import paho.mqtt.client as mqtt

32. import Adafruit_IO

33. import time

34.

35.

36. ########################

37. # Globals
38. ########################

39.

40. # -- Change these as needed for your installatin --

41.

42. localBroker = "YOUR_BROKER_IP" # Local MQTT broker

43. localPort = 1883 # Local MQTT port

44. localUser = "YOUR_MQTT_USERID" # Local MQTT user

45. localPass = "YOUR_MQTT_PASSWORD" # Local MQTT password

46. localTopic = "/security" # Local MQTT topic to monitor

47. localTimeOut = 120 # Local MQTT session timeout

48.

49. adafruitUser = "YOUR_ADAFRUIT_IO_USERID" # Adafruit.IO user ID

50. adafruitKey = "YOUR_ADAFRUIT_IO_KEY" # Adafruit.IO user key

51. adafruitTopic = "alarms" # Adafruit.IO alarm topic

52.

53. # -- You should not need to change anything below this line --

54.

55. sensorList = {} # List of sensor objects

56.

57.

58. ########################

59. # Classes and Methods

60. ########################

61.

62. class sensor():

63. def __init__(self):


64. self.name = "" # Name of sensor in MQTT

65. self.humanName = "" # Human-meaningful name (e.g., "front door")

66. self.lastSeen = 0 # Number of seconds since the sensor was last


seen

67. self.state = "unknown" # State of the object: unknown, open, or closed

68.

69. def setState(self, newstate):

70. self.state = newState

71.

72. def getState(self):

73. return self.state

74.

75. def resetHeartbeat(self):

76. self.lastSeen = 0

77.

78. def setname(self, newName, humanName):

79. self.name = newName

80. self.humanName = humanName

81.

82. def getname(self):

83. return self.humanName

84.

85. def checkState(self, newState):

86. if ("unknown" == self.state):

87. self.state = newState

88. return 0
89. else:

90. if (newState != self.state):

91. self.state = newState

92. if ("closed" == self.state):

93. return -1

94. else:

95. return 1

96. return 0

97.

98.

99. class sensorList():

100. def __init__(self):

101. self.sensorList = {}

102.

103. def addSensor(self, sensorName, humanName):

104. self.sensorList[sensorName] = sensor()

105. self.sensorList[sensorName].setname(sensorName, humanName)

106.

107. def getSensorName(self, sensorID):

108. return self.sensorList[sensorID].getname()

109.

110. def sensorState(self, sensorID, monitorState):

111. rv = self.sensorList[sensorID].checkState(monitorState)

112. if (0 != rv):

113. # State changed!

114. if (0 > rv):


115. outBuf = "INFO "+self.getSensorName(sensorID)+"
"+monitorState

116. print(outBuf)

117. else:

118. outBuf = "ALARM


"+self.getSensorName(sensorID)+" "+monitorState

119. print(outBuf)

120. print("Initiating connection to Adafruit.IO")

121. AIOclient = Adafruit_IO.MQTTClient(adafruitUser,


adafruitKey)

122. print("Setting callbacks for Adafruit.IO")

123. AIOclient.on_connect = AIOconnected

124. AIOclient.on_disconnect = AIOdisconnected

125. AIOclient.on_message = AIOmessage

126. print("Connecting to Adafruit.IO")

127. AIOclient.connect()

128. time.sleep(5)

129. print("Publishing outBuf")

130. # AIOclient.publish("alarms", outBuf)

131. AIOclient.publish("alarms", outBuf)

132. print("Disconnecting")

133. AIOclient.disconnect()

134.

135.

136. ########################

137. # Functions

138. ########################
139.

140. # Callback functions for Adafruit.IO connections

141. def AIOconnected(client):

142. # client.subscribe('alarms')

143. print("Connected to Adafruit.IO")

144.

145. def AIOdisconnected(client):

146. print("adafruit.io client disconnected!")

147.

148. def AIOmessage(client, feed_id, payload):

149. print("adafruit.io received ", payload)

150.

151.

152. # returnState takes a numeric voltage value from the sensor and

153. # returns the state of the monitored device. With a voltage divider

154. # that uses a 1M ohm R1 and a 470K ohm R2, the "closed" state returns

155. # 1024 and the open state returns between 1 and 40.

156.

157. def returnState(inVal):

158. if (1000 < inVal):

159. return "closed"

160. if (100 > inVal):

161. return "open"

162. else:

163. return "unknown"

164.
165.

166. ########################

167. # Main

168. ########################

169.

170. if "__main__" == __name__:

171. # Set timer

172.

173. sensList = sensorList()

174. sensList.addSensor("security_001", "front door")

175.

176. # The callback for when the client receives a CONNACK response from the
server.

177. def on_connect(client, userdata, flags, rc):

178. print("Connected with result code "+str(rc))

179.

180. # Subscribing in on_connect() means that if we lose the connection


and

181. # reconnect then subscriptions will be renewed.

182. client.subscribe("/security")

183.

184. # The callback for when a PUBLISH message is received from the server.

185. def on_message(client, userdata, msg):

186. (sensorID, sensorVoltage) = string.split(msg.payload)

187. sensorVoltage = string.atoi(sensorVoltage)

188. sensorName = sensList.getSensorName(sensorID)


189. sensList.sensorState(sensorID, returnState(sensorVoltage))

190. # print(sensorName+" "+returnState(sensorVoltage))

191.

192. client = mqtt.Client()

193. client.on_connect = on_connect

194. client.on_message = on_message

195.

196. client.connect(localBroker, localPort, localTimeOut)

197.

198. # Blocking call that processes network traffic, dispatches callbacks and

199. # handles reconnecting.

200. # Other loop*() functions are available that give a threaded interface and a

201. # manual interface.

202. client.loop_forever()

203.

204. quit()

MQTT Security: Securing a Mosquitto


Server
This post describes how to implement MQTT security. In more detail, we will describe
how to secure a Mosquitto MQTT server. As you may already know, MQTT is one of the
most important protocols widely used in IoT and IIoT. MQTT is a lightweight, messaging-
oriented protocol where an MQTT client exchanges messages through an MQTT server
called an MQTT broker. We have covered all these aspects of MQTT in my MQTT
protocol tutorial.

In this post, we want to face the MQTT security aspects with a special regard to the aspects
related to MQTT Mosquitto security.

Generally speaking, the Internet of Things is the upcoming technological revolution where
objects, called smart objects, are connected to the Internet exchanging data and
information. One of the main concerns about IoT is the security aspect. Considering that
IoT will impact our everyday lives and these smart objects are able to acquire and collect
different kinds of information, security is an important aspect. Some of this information is
sensitive (we can think about health data), and it is important to be sure that no one else can
use it except the permitted persons and systems.

In this context, it is important to know how to secure the MQTT protocol and how to
protect your information. In the next paragraphs, we will analyze the steps we have to
follow to secure MQTT using a Raspberry Pi as the MQTT broker.

What Does MQTT Security Mean?


By its nature, MQTT is a plain protocol. All the information exchanged is in plain-text
format. In other words, anyone could access to this message and read the payload. Of
course, there are several use cases where we want to keep information private and
guarantee that it cannot be read or modified during the transmitting process. In this case,
there are several approaches we can use to face the MQTT security problem:

1. Create a VPN between the clients and the server.


2. Use MQTT over SSL/TSL to encrypt and secure the information between the
MQTT clients and MQTT broker.

We will focus our attention on how to create an MQTT over SSL. To make MQTT a
secure protocol, we have to follow these steps:

Create a private key (CA Key).


Generate a certificate using the private key (CA cert).
Create a certificate for Mosquitto MQTT server with the key.

The final step is configuring Mosquitto MQTT so that it uses these certificates.

Securing Mosquitto MQTT Server


The first step in this process is creating a private key. Connect to the Raspberry Pi using ssh
or a remote desktop as you prefer and open a command terminal. Before starting, it is
important you ensure OpenSSL is installed on your Raspberry Pi. If not, you can download
it from here.

Before creating the private key, you should create a directory where you store all the
certificates you will create. In the terminal, write:

openssl genrsa -out mosq-ca.key 2048


Using this command, we are creating a 2048-bit key called mosq-ca.key. The result is
shown in the picture below:

The next step is creating an X509 certificate that uses the private key generated in the
previous step. Open the terminal again and, in the same directory you used to store the
private key, write:

openssl req -new -x509 -days365 -key mosq-ca.key -out mosq-ca.crt

In this step, you have to provide different information before creating the certificate as
shown in the picture below:

Creating the MQTT Server Certificate

Once the private key and the certificate are ready, we can move on and create the MQTT
server certificate and private key:

openssl genrsa -out mosq-serv.key 2048


Then the server certificate. During this step, we have to create a CSR (Certificate Signing
Request). This certificate should be sent to the Certification authority that, after verifying
the author identity, returns a certificate. In this tutorial, we will use a self-signed certificate:

openssl req -new -key mosq-serv.key -out mosq-serv.csr

As you can see, we have used the private key generated in the step before. Finally, we can
create the certificate to use in our MQTT Mosquitto Server:

openssl x509 -req -in mosq-serv.csr -CA mosq-ca.crt -CAkey mosq-ca.key -


CAcreateserial -out mosq-serv.crt -days 365 -sha256

All done! We have completed the steps necessary to secure our MQTT server. You can
verify your certificate:

openssl x509 -in mosq-serv.crt -noout -textjavascript:void(0)

Now you should see the certificate.

How to Configure MQTT Mosquitto Server to Secure


MQTT
Once the certificates are ready, we have to configure MQTT Mosquitto Server so that it can
use these certificates. The certificates we have to use are:

mosq-ca.crt
mosq-serv.crt
mosq-serv.key

Locate the mosquitto.conf file that holds all the configuration parameters and add the
following lines:

listener 8883
cafile /home/pi/ssl-cert-mosq/mosq-ca.crt
certfile /home/pi/ssl-cert-mosq/mosq-serv.crt
keyfile /home/pi/ssl-cert-mosq/mosq-serv.key
The path /home/pi/ssl-cert-mosq is the path where you stored your certificate. Moreover,
we change the default Mosquitto MQTT port to 8883.

Now you have to stop and restart Mosquitto MQTT so that it can read the new
configuration file:

sudo service mosquitto stop/start

That's all. Now our MQTT protocol is secure and encrypted. The last step is testing the
configuration and the MQTT server.

MQTT Security Testing Mosquitto Over SSL/TSL


In this step, we will verify if the connection is correctly configured. For this purpose, we
use MQTT.fx, a Java-based MQTT client. After you install it, we have to create a new
profile providing all the information as shown in the picture below:

Notice that we have enabled the SSL/TSL configuration, providing the mosq-ca.crt creating
during the previous steps.

Finally, we can connect to the MQTT Mosquitto server:


Click on Connect. You will notice that the MQTT client will establish the connection to the
MQTT broker as you can check in the log tab.

Now it is time to test if our client gets the message. Select the subscribe menu and
subscribe the MQTT client to a topic (choosing a topic name).

On the Raspberry Pi side, let's send a message on the same channel:

mosquitto_pub -p 8883 -t "test" -cafile mosq-ca.crt -m "Hello MQTT" -d -h


192.168.1.8

The result is shown in the picture below:

On the subscriber side, we have:

As you can see, we received the message sent by the publisher.