IoT Course Week 7: Platform Security Part B (#2)

Internet of Things CourseWelcome to Week 7, part B #2

Note: This is part 2 of a 3 part series about assignment 7B in the course. This particular assignment was quite information dense, and if you are unfamiliar with some of the pieces involved, things can be quite confusing.

In Part #1 we covered the overall solution. Now let’s delve into how we are handling authorization for the LAMPI device(s) and human users of the Django web app. Since the primary interface between LAMPI and the Cloud is MQTT (and hence Mosquitto), let’s look at that first.

Mosquitto’s Authentication Plugin

Mosquitto supports an extensible plugin architecture, for both user authentication and Access Control Lists (ACL). ACLs allow for fine-grained permission models. When applied to Pub/Sub systems, they allow the control of which users can publish to particular topics and which users can subscribe to particular topics.

For these purposes, we will be using mosquitto-auth-plug project. It supports multiple backends such as MySQL, Redis, Postgres and HTTP to name a few. In order to integrate with the Django app, we will use the HTTP backend.

With the plugin configured for HTTP, whenever Mosquitto needs to answer an authentication or ACL question, it will make an HTTP request. What hostname, port, and URLs it uses for the HTTP backend is configurable. The HTTP server then responds with either an HTTP status of 200 (OK), approving the request (e.g., to allow username XYZ to connect with password ABC), or returns a 403 (Forbidden). There is no actual data in either response, just the HTTP response code.

The LAMPI “User”

So, how does the Authentication and Authorization work in regards to LAMPI? Well, the Authentication is basically handled by the TLS certificate. The name of the LAMPI device is the Common Name of the TLS certificate on the device that is used when initiating the MQTT connection to the Mosquitto broker instance in the cloud.

When making a web connection through the auth plugin, Mosquitto creates a POST request to the configured location that contains the following: username, password, topic and acc. In the case of LAMPI, when making a call to /auth, the password field is blank (having already authenticated via TLS) as are the topic and acc fields. If the Django app approves the request when LAMPI connects to the Cloud Mosquitto broker then it will return a 200 HTTP response to Mosquitto.

What about Pub & Sub requests? That is a bit different. When the Mosquitto broker on LAMPI pushes topic requests, through the bridge, to the Mosquitto broker in the Cloud, the auth plugin may defer the ACL check depending on the type of request.

If the LAMPI Mosquitto broker has requested to subscribe to a topic, the ACL of that subscription isn’t immediately checked by the Mosquitto broker in the Cloud. The Cloud Mosquitto broker merely records the subscription request from the LAMPI Mosquitto broker. The Mosquitto broker on LAMPI has no knowledge if it is in fact allowed to subscribe or not.

When a message is published on that topic that the LAMPI Mosquitto broker is subscribed to, then the Mosquitto broker in the Cloud sends an /acl request via the auth plugin to determine if the LAMPI Mosquitto broker is in fact allowed to receive that published message. Once again, the auth plugin creates a POST request with the following fields: username, password, topic, acc and clientid. The topic contains the full path of the message, the acc is a number 1 for a Subscription check, and clientid is the thing that is requesting the action. The Django app will use this information to determine if the LAMPI Mosquitto broker is the correct recipient of the published message. If it is, it will return a 200 HTTP response to the Cloud Mosquitto broker, otherwise a 403 HTTP response will be returned.

If the LAMPI Mosquitto broker attempts to Publish a message to the Cloud Mosquitto broker, an ACL check will be performed immediately via the auth plugin. Once again, the Cloud Mosquitto broker will make a call to /acl on the Django app. As with the Subscription check earlier, the same data will be POSTed to the Django app with the exception of acc being a value of 2 (for Publish). If the LAMPI Mosquitto broker is allowed to push that message up to the Cloud Mosquitto broker, then Django would return a 200 HTTP response.

This sure does seem like a lot of work for the Cloud Mosquitto broker. It would be, if it made these auth calls every time a message came through. This is why Mosquitto actually caches the responses to these Auth & ACL requests for a time. This allows Mosquitto to quickly evaluate ACL checks internally which gives it a very high message throughput. With this out of the way, let us look at the role of the Human being using the Django Web Application.

The Human “User” Interacting with the Django Web App

In order to let a human user into the Django web app, we are using Django’s built in user authentication mechanism. The idea is to allow a simple system to authenticate a human user via username & password, as well as provide an authorization mechanism to associate human users to device users. The device users in this case being one or more LAMPIs registered with their respective users.

The registration of a LAMPI to a human user account in the Django app is used to determine if that human user logged in via the Web has access to publish or subscribe to topics from LAMPIs connected to the Cloud broker. The important point to take note of however, is the web page contains no static data. All of the data the human user interacts with via the web interface is actually generated in real-time via the WebSockets integration with the Cloud Mosquitto broker.

So how do we authenticate and authorize the human user via WebSockets to see messages from Mosquitto? We’ll find out next week in the final installment of this series on Assignment 7B.