Using multi-tenancy in Eclipse Hono
Most business applications in the Internet of Things work with data produced by devices that are connected to the application over public Internet infrastructure. The Eclipse Hono project can be leveraged by such applications to abstract away the particular communication protocols used by the devices, thus allowing the application to ingest data published by devices using a uniform AMQP 1.0 based API. You can find an overview of Hono’s features and capabilities in a previous blog post. With Hono 0.6-M2 having been published just recently, it is time to take a closer look at its new multi-tenancy capabilities.
Ensuring Data Privacy
Hono allows devices to be grouped into tenants. A tenant may represent any kind of organizational or technical domain that the devices are part of. Each device must be assigned to exactly one tenant. The diagram below shows the relationship between tenants and devices.
Examples of tenants include:
- a customer
- an application
- devices of a particular type (e.g. temperature sensors)
Once assigned, Hono makes sure that data produced by devices of a particular tenant can only be consumed by clients that have been explicitly authorized for that tenant. Because the data is kept private to each tenant, it makes a lot of sense to set up a single, highly scalable Hono installation in a cloud environment, making efficient use of computing and networking resources while sharing the operating costs between the tenants.
In the remainder of this blog post we will walk through an example of how to set up multiple tenants in Hono, register devices with these tenants, and consume data produced by the devices securely and privately.
Instead of installing Hono on your local computer, we will use the Hono sandbox provided by the Eclipse Foundation.
The sandbox is specifically intended to be used for experimenting and testing purposes. It comes with a simple Device Registry component which exposes an HTTP based API for managing tenants, devices and credentials.
When a device connects to one of Hono’s protocol adapters in order to publish data, Hono authenticates the device and verifies its registration status by means of information retrieved from the Device Registry.
Each tenant is required to have a unique identifier. The identifier is a string of arbitrary length.
We will use the following command to add a new tenant using acme-corporation as the identifier. Please make sure to pick another (non-existing) identifier when following the example. Otherwise the command will fail with a 409 Conflict, indicating that a tenant with that identifier already exists.
In the same way, another tenant can be created:
Having created the tenants, the next step is to register the devices. Similar to a tenant, a device must have an identifier which is unique within the tenant that it is registered with. The following examples register one device with each of the tenants created above.
You can either use the same device identifiers shown in the code snippets below or create your own identifiers. Just make sure that you are using the same device identifiers when you set the devices’ credentials as described in the next section.
Registering device acme-1 with tenant acme-corporation:
Registering device foo-bar-1 with tenant foo-bar-corporation:
The final step before the devices can actually start publishing data to Hono is to set credentials for the devices. Hono requires a device to authenticate using these credentials before it accepts any data published by the device. This way, applications consuming the data via Hono’s Telemetry or Event APIs can be sure that the data originates from the device indicated in the telemetry message or event.
Eclipse Hono is designed to support multiple types of credentials, supporting authentication schemes like HTTP Basic auth, MQTT username/password authentication, X.509 client certificates and other TLS ciphers that support client authentication using Pre-Shared Keys or RawPublicKeys.
However, for the sake of simplicity, we will use simple hashed-password credentials which the devices can use to authenticate with the HTTP protocol adapter using HTTP Basic Auth or with the MQTT adapter.
As the name suggests, the Device Registry does not store any passwords in clear text but instead stores a hash of the password only. In order to authenticate a device, a protocol adapter retrieves the hashed password from the registry and compares it to a locally computed hash of the password provided by the device. If the hashes match, the device is authenticated and its data is accepted.
Setting credentials for a device requires upfront computation of the password hash. The hash can then be used in an HTTP request to set the credentials for a device.
Here is the code to compute the hash and set the credentials for the acme-1 device (make sure to use your own device ID for the device-id and auth-id in the JSON payload and your tenant name in the URI):
The password for the foo-bar-1 device can be set in the same way:
Publishing & Consuming Data
In order to consume telemetry data or events that have been published by devices, a client needs to connect to Hono’s Telemetry and/or Event API using AMQP 1.0.
Hono provides an example Java client that can be used to consume data from Hono. You can get the client from the download page (in the Latest Milestone section).
After the download has finished, start the client from the command line like this:
NB: Make sure to set the value of the –tenant.id parameter to the name of your tenant.
Once the client is running, the following command can be used to publish some telemetry data for the acme-1 device. Make sure to adapt the command to use the device identifier and password of the device that belongs to the tenant you started the client for.
Now try to start another client (on another console) to consume data from the other tenant:
NB: Do not be confused by the fact that this uses the same user name and password as for the first tenant. This is just a limitation of the sandbox environment. In a production system, the clients will use different credentials specific to the tenant from which they want to consume data.
Now publish some data for the second tenant:
You should see the data being output on the console of the foo-bar-corporation client but not on the console of the acme-corporation client.