Author: Eric Hankinson

About Eric Hankinson

Embedded/Web/Mobile/DevOps Developer and Agile Coach for LeanDog. Love building stuff & things. All about Craftsmanship - Software or otherwise.

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

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

Note: This is part 3 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 #2 we covered how the authentication and ACL mechanism works and how we integrated that with the Django web app. Now, we’ll cover how we deal with auth and ACL checking through the WebSockets support on Mosquitto.

Real-time Feedback of LAMPI in our Web App

In order to have real-time feedback in the web app, we are using the Paho MQTT JavaScript library and WebSockets to provide data to the Human User that has the web app open in their web browser. The WebSocket traffic is being supplied by Mosquitto, not our Django app. So, how do we secure this so that you can’t just go in and twiddle some data to get access to someone else’s LAMPI devices?

Well, first thing to note, since the WebSocket traffic is going through Mosquitto, is taking a look at what Mosquitto does in relation to the Auth integration with the Django app. Mosquitto expects there to be enough data in the WebSocket request to satisfy the /auth & /acl calls that we reviewed in Part #2. To recap, this is username, password and topic (for /acl you also need clientid and access type).

That seems easy enough, but we don’t want to send the user’s actual username and password through the wire (or exposed in the JavaScript) on every call. How do we solve this problem then? We use a collapsed UUID-based Auth token from Django that is unique to the current Human User session in the web app. By using the Auth token as the username and a blank password field, we can validate the request by looking up the Human User session in the Django app to be able to respond appropriately to the Mosquitto Auth Plugin call as to the authorization of that particular Pub/Sub request from WebSockets.

So, to make this easy, we wrote our Django view template to inject a snippet of JavaScript that sets up a few variables, one of which is our Auth token, that we then leverage in our JavaScript code that coordinates the WebSocket data calls with UI manipulation. That code then uses the token, via the Paho JavaScript client, as the username field so that the Django app can determine an authorization response when Mosquitto asks. This will then allow us to restrict the access to topics by user & device so that you can’t easily sniff other Human User’s data. Easy peasy lemon squeezy, right?

What more security do we need?

Well, for starters we should probably TLS encrypt the local backend HTTP traffic between the Cloud Mosquitto broker auth plugin and the Cloud Django web app. While we transfer this traffic over the local loopback device on the server (which means the IP traffic never exits the physical Ethernet device on the server), if you somehow gained access to the server, you could sniff the traffic on that interface. At that point though, we most likely have bigger security problems.

Having the Django auth token being passed around may not be the best, but it is similar to how many REST-based APIs work in that once you authenticate, you then use a token for all subsequent web requests.

Where else do you think the security of this architecture could be improved?

Next Week

Next week, we take a step back from this foray into security for something entirely new: mobile device control. We will forge a path into the unknown as we begin to implement Bluetooth Low Energy connectivity from the smartphone in your pocket directly to the LAMPI hardware.

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.

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

Internet of Things Course

Welcome to Week 7, part B #1

Note: This is part 1 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 a bit confusing.

In the previous week, we added some security to the system with Transport Layer Security (TLS). This encrypts the web, websockets, and MQTT communications. It also allows clients to authenticate that the servers are who they say they are, and Lampi Devices to authenticate the MQTT bridge connection to the EC2 MQTT Broker. This week we will be focusing on a few remaining security gaps in the model, including:

  • protecting the Cloud MQTT broker namespace
  • limiting which devices Django users can communicate with at the MQTT level
  • providing limitations on Lampi devices specifying how and which topics are mapped into the global MQTT topic namespace on EC2 (and a compromised device could potentially wreak havoc on the entire system)
  • requiring authentication of users connecting to the MQTT websockets interface

Where do we begin?

There are a few different ways to skin this security cat. We decided that integrating Mosquitto with Django would provide us with a way to have a single source of truth for Human User authentication, Human User authorization, and Device User authorization. Mosquitto is already configured to authenticate the LAMPIs via the TLS certificates we configured in the previous post. Also, we thought that a REST interface would be easiest to implement for the integration. While we used Django, really any system that supports REST would work with the architecture we’re outlining today.

The high-level components:
Screen Shot 2016-03-07 at 3.13.10 PM

What does this look like overall?

There are a few moving parts to this solution we decided to go with. Let’s take a look at it overall:

Screen Shot 2016-03-07 at 3.10.16 PM

You’ll notice there will be a plugin to Mosquitto that we’ll leverage to connect the Django web app with the MQTT system.

Next post will delve into the ACL support for LAMPI and the Human Users of the system. Stay tuned!

IoT Course Week 7: Platform Security (Part A)

Anytime you are making a product, platform security is something that needs to be addressed. In this post, we look at platform security and the steps you can take protect your users.

Platform Security internet of things collage IoT
By now we’ve created a page that controls LAMPI and are serving it out of Django. We have a user authentication scheme, although we’re not putting it to great use just yet. Before we get there, we have a huge problem — there is really no security to speak of anywhere in this system. Our MQTT bridging is “secured” with a username and password, but those are sent unencrypted over the network. It would be trivial to sniff this communication and discover these credentials.

We have two paths into our EC2 server we need to secure — the path from the lamp to the cloud, and the path from the user’s browser back to the cloud.

TLS Certificate

Rather than use username and password, we are going to use Transport Layer Security (TLS) to encrypt our communications. Using this channel of public key cryptography will ensure that messages being sent between the lamp and the cloud are impossible to decrypt or interfere with, without first compromising the private key of the Certificate Authority.

We will create our own local certificate authority which we will use to issue and sign certificates for both the lamp and web client. A CA functions via the following steps:

  1. Someone decides to be a CA
  2. Generate a Public and Private Key Pair
  3. Generate a CA Certificate, including the Public Key, and Sign it with the Private Key
  4. Distribute your CA Certificate to the World

Note: For a real CA, Private Key should be stored securely, probably on a non-networked computer. Compromise of the Private Key compromises all derived certificates!
If you want to read more about how TLS (and it’s predecessor SSL) work, here is an excellent Stack Overflow post.

For the purposes of this discussion, the Common Name of the TLS certificate has to be unique to the LAMPI instance. This is because the Common Name will be used as part of the authentication process later.

Add to Bridging

As was set up in Lecture 4, MQTT bridging between cloud and LAMPi is handled using the tool Mosquitto. Mosquitto supports TLS security natively, and turning it on is as simple as ensuring each device has the appropriate CA and generated keys to communicate with each other. On the LAMPi, the configuration is:

/etc/mosquitto/conf.d/bridging.conf

connection b827eb74663e_broker
 address ec2-52-20-29-213.compute-1.amazonaws.com:52122
bridge_cafile /etc/mosquitto/ca_certificates/lampi_ca.crt
 bridge_certfile /etc/mosquitto/certs/b827eb74663e_broker.crt
 bridge_keyfile /etc/mosquitto/certs/b827eb74663e_broker.key
 bridge_tls_version tlsv1.2
topic lamp/set_config in 1 "" devices/b827eb74663e/
 topic lamp/changed out 1 "" devices/b827eb74663e/
 topic lamp/connection/+/state out 2 "" devices/b827eb74663e/
 cleansession true

and on the cloud, the configuration is set to:

/etc/mosquitto/conf.d/port.conf:
 listener 52122 0.0.0.0
 cafile /etc/mosquitto/ca_certificates/lampi_ca.crt
 certfile /etc/mosquitto/certs/lampi_server.crt
 keyfile /etc/mosquitto/certs/lampi_server.key
 tls_version tlsv1.2
 require_certificate true
 use_identity_as_username true

Next, we need to allow that “user” access, so we configure Mosquitto’s passwords file and add the Common Name of the LAMPI instance. Once these are set, and Mosquitto is restarted, each Mosquitto instance is reset and the bridging will now be TLS secured!

Serving Django pages from NGINX

Next we’ll need to secure our web client. The current Django web server does not support TLS, and we are hoping to use TLS to communicate between the cloud and a user’s web browser. Since we already have nginx installed and it is a TLS capable web server, we will use that. nginx does not natively know how to serve a Django app, so we’ll use uWSGI as a WSGI adapter between nginx and Django. uWSGI provides detailed instructions on making this web server change in their docs.

lampi_server_nginx.conf

# configuration of the server
 server {
# the port your site will be served on
 listen 443 ssl;
 ssl_certificate /home/ubuntu/ssl_keys/lampi_server.crt;
 ssl_certificate_key /home/ubuntu/ssl_keys/lampi_server.key;
 ssl_protocols TLSv1.2;
# the domain name it will serve for
 server_name ec2-52-20-29-213.compute-1.amazonaws.com; # substitute your machine's IP address or FQDN
 charset utf-8;

Restarting uWSGI and nginx at this point will apply the changes. Now traffic when navigating to https://{django_web_address} will be secured via the CA that we created!

Securing Websockets

Since we’re getting some of the real-time information over websockets, and MQTT is serving that data using the websockets protocol, we want to also encrypt the transport of that data from MQTT to the Client’s web browser. Also, since this websocket data is in a web page that is already coming from a now encrypted NGINX server, we need MQTT to encrypt that websocket data with the same TLS certificate that we use for our NGINX configuration.

/config/mosquitto_cloud/conf.d/websockets.conf

listener 8081
 protocol websockets
 cafile /home/ubuntu/ssl_keys/lampi_ca.crt
 certfile /home/ubuntu/ssl_keys/lampi_server.crt
 keyfile /home/ubuntu/ssl_keys/lampi_server.key

Here is an example of what this would look like:

Platform Security Diagram for IoT Class

Wrapup

Device

  • no services listening on anything but localhost
  • MQTT bridge using TLS with unique certificate

EC2

  • Require TLS on MQTT (MQTT and Websockets)
  • Require TLS on NGINX HTTP (HTTPS)

Next Week

This week laid down the groundwork that makes up our platform’s security. Next week, we will continue this robust buildout, specifically focusing on the MQTT layer. User accounts will be limited through Django to lock down communication to specific LAMPi devices. The MQTT web sockets interface will also undergo some lockdown.

In case you missed it, here’s a link to last week’s post: IoT Week 6: Setting Up User Accounts or, if you’re hankering to snack on some Cucumber, check out How to Run Cucumber Tests with Docker.

CodeMash 2014

A number of us from LeanDog attended CodeMash 2014. You may have seen us with our fuzzy hats walking around the halls or talking to other conference attendees. One of the great things we like about CodeMash is the diversity of languages and skill levels of all the attendees. It is always a great opportunity to talk to like-minded folks.
Continue reading »