Blog

An article describing some security techniques that can be applied to an MQ broker that is receiving data published by clients on the Internet, and consumed by back-end services running on a server in the cloud.

SecuringMQTTOnApacheActiveMQ

Securing MQTT on Apache ActiveMQ

Introduction

One of the technologies often associated with the Internet of Things (IoT) is Message Queue Telemetry Transport (MQTT).  It is a lightweight Machine to Machine (M2M) protocol that runs over TCP/IP and offers a publish-subscribe model for messaging.  Its “light” use of network bandwidth and small footprint make it useful in applications where data is collected from devices that operate with constrained resources.  One type of application using MQTT may involve a network of sensor devices that publish data to an MQTT broker.  One or more applications or services may subscribe to the sensor data arriving at the broker, using it as input to perform some function.  In this case, two main software components are in play:  MQTT clients that publish and subscribe to topics, and MQTT brokers that manage publishers and subscribers, routing messages as needed.

Just at there are several MQTT client libraries available, there are numerous MQTT brokers currently available as well.  One of these is the venerable Apache ActiveMQ.  Perhaps known more as a JMS server, ActiveMQ also provides support for MQTT brokering.  This article will focus on using ActiveMQ as an MQTT broker, and more specifically, how to secure it.  In fact, the approach described here could be used to secure any of ActiveMQ’s transport connectors.

It may be obvious why one would want to secure access to an ActiveMQ broker, but the types of and degrees of protection are often driven by the environment in which the broker is used.  Brokers running on highly secure internal networks may not require the same types of protection that a broker exposed to the Internet might need.  The types of data flowing through the broker is also a consideration.  Personal information should not be transferred in plain sight.

An MQTT Application

In this article, we describe some security techniques that can be applied to an MQ broker that is receiving data published by clients on the Internet, and consumed by back-end services running on a server in the cloud.

Consider an architecture like the one shown in Figure 1 and think about some of the types of access one would want to guard against.  The following restrictions come to mind:

  1. Unknown clients should not be able to publish data to the broker.
  2. No clients, outside of the Server, whether known or unknown, should be able to subscribe to data on the MQ broker.
  3. Only the Services running on the back-end server should be able to subscribe to data on the broker.  It might be desirable to restrict access to data types (i.e., topics) by Service.  We won’t address that specifically here, but the sample should make obvious how to do that.
  4. The content of messages transmitted from MQTT Clients to the Broker should not be readable by others sniffing traffic between the two nodes.  This may also be true for messages flowing between the Broker and the back-end Services.  For now, we will assume that is not a concern, but again, it should be clear how that pathway could also be protected.
MQTT Application

Figure 1: MQTT Application

Obviously, these are not the only security concerns one may have with an architecture like this, or any application connected to the Internet, but they are some of the most fundamental.

Secured MQTT Application

Figure 2: Secured MQTT Application

So, how can we overlay protection against the concerns identified above?  We can enforce encryption, authentication and authorization.  So, what we want is a system that includes protection shown in Figure 2.

As you can see, we want to encrypt messages exchanged between the Internet clients and the Broker so that their content is hidden. We want to apply authentication to all clients connecting to the Broker, thereby restricting unwanted access.  Lastly, we want to determine whether an authenticated client is authorized or has permission to perform the action they are requesting.

The ActiveMQ Broker is amenable to adding each of these services.  Let’s start with encryption using SSL.

SSL

For instructions on how to create the certificates for configuring SSL have a look at Giuseppe Urso’s blog →.  Step 1 in the blog provides detailed instructions for creating certificates and keystores.  Also, have a look at Step 2 for directions to enable SSL transport and client authentication.  This article diverges here a little from Giuseppe’s in two ways:  we are using the mqtt protocol, and we will not use SSL client authentication.  The use of SSL authentication or the type we describe later in this article, depends at least on the type of application you are developing and how you can or wish to distribute client credentials.

 
Aside: This article derives from a real application we have built that makes use of the fact that clients provide a username and password for authentication.  There are certainly use cases where SSL authentication is preferred.
 
The result is that we want an ${ACTIVEMQ_HOME}/conf/activemq.xml file that contains this:

 

Figure 3: activemq.xml snippet

 

Notice that we have left the mqtt transportConnector from the default configuration in place.  This connector will still be used by the Services running on the Server.  An “mqtt+ssl” connector is added with the needClientAuth parameter set to false.  Also, we only need to configure a keyStore.  A trustStore is not needed because we are not authenticating clients using SSL.

With the keystore file copied to the {ACTIVEMQ_HOME}/conf folder and activemq.xml file updated, the ActiveMQ broker can be started.  The startup output should indicate that the “mqtt+ssl” and “mqtt” connectors have started.

Authentication

There are several ways to do authentication with the ActiveMQ Broker.  See the official documentation for some background:  Apache ActiveMQ Security →.  Out of the box, ActiveMQ has a few authentication plugins, including a SimpleAuthenticationPlugin, as well as one for use with LDAP.

If you are not satisfied with these options, a custom authentication mechanism can be developed.  One way is to develop an Interceptor plugin that allows you to intercept message processing within the broker and execute your own code, more specifically a BrokerFilter type of interceptor could be used to perform your own authentication during connection or session addition.  Another way, and the one we demonstrate here, is to create a JAAS based authentication plugin.

A custom JAAS authentication plugin is created by providing implementations of javax.security.auth.spi.LoginModule and java.security.Principal.  We used the the sample implementations from the official JAAS tutorial as a guideline:  ( SampleLoginModule.java → SamplePrincipal.java →).  In our application, a back-end User Manager web service takes usernames and passwords as input and checks for a match against credentials stored in a database.  This architecture is illustrated in the Figure 4.

Authenticated MQTT Application

Figure 4: Authenticated MQTT Application

The custom code for the LoginModule and the Principal are shown below.  Essentially, the M2MLoginModule receives an authentication request by way of its “login” method.  The “authenticate” method is then called, which in turn makes a call to the User Mgr web service.  Authentication results are determined at this line in the “authenticate” method: 

if( response.getStatusLine().getStatusCode() == 200 )

A 200 (success) code means the user was authenticated.  The remaining code after that line is related to the authorization function and will be discussed later.  If authenticated, “commit” is eventually called and an M2MPrincipal is created, representing the authenticated user.

Figure 5: M2MLoginModule

 

Figure 6: M2MPrincipal

We can then configure our LoginModule as a JAAS authentication plugin.  This can be done by building a jar with the two classes above and placing them into the ${ACTIVEMQ_HOME}/lib folder.  We also need to configure the plugin in the activemq.xml configuration file by adding the following:

Figure 7: activemq.xml authentication plugin

Additionally, the login module must be configured in the ${ACTIVEMQ_HOME}/conf/login.config file as shown below.  Notice the inclusion of the custom parameter “userMgrUrl”, which provides the URL to the web service needed to perform authentication.

Figure 8: login.config

Authorization

ActiveMQ provides a mechanism to restrict access to groups of users by topic or queue.  It provides control over read, write and admin permissions.  The “admin” permission is needed in order to create or initialize a topic or queue.  In our application we want to restrict our Sensor clients to have write-only access to a set of topics.  Meanwhile, Services running on our server have admin and read access to the same topics.

This authorization scheme requires that we define two different groups, and assign members and permissions to them.  So, we have two groups:  sensors and server.  Let’s also say that we are receiving two different types of measurements from the sensors, location and temperature.  Each measurement type is received via a unique topic.  We can define access rights in the activemq.xml file by adding an authorization plugin definition like this:

Figure 9: activemq.xml authorization

 

The net result of this configuration is to disallow access to queues and any topics not explicitly named in the configuration file, while providing access to the sensor and server groups as describe above.  Note that if you are networking brokers or relying on some additional services that take advantage of the “Activmeq.Advisory.>” topics, you may also need to include it in the authorization map and grant access to necessary groups.

The last step is to connect our custom user management system with ActiveMQ group principals.  We define another class, M2MGroupPrincipal, in which a user’s group membership is stored.  It’s implementation is identical to the M2MPrincipal class defined earlier to identify users.  When authentication is performed, the M2MLoginModule also obtains the list of groups that the user belongs to from the User Manager web service.  If the web service returns a success on a username/password lookup, it also returns a comma separated list of groups that the user belongs to.  The authenticate method in the M2MLoginModule processes that list storing the names.  The commit method then turns those names into M2MGroupPrincipal objects.

Figure 10: M2MGroupPrincipal

Conclusion

This article has demonstrated how to overlay authentication, authorization and encryption capabilities on an ActiveMQ Broker that may be used in an MQTT application.  We have not discussed the client side of the equation.  There are too many different platforms and frameworks to cover here, but one way to test your setup is with a Java test client using the Paho client.  Here is a simple class that could be used to try out your security setup on the Broker.

Figure 11: MQTT Test Client

References

Leave a Reply

You must be logged in to post a comment.