IoT end-to-end encryption with E4 (6/n): deployment

In this post, we’ll present how E4 could be deployed in your infrastructure. We’ll go through its requirements, its components, and the additional services that we offer for monitoring and observability. We’ll describe how everything is set up, from application deployment to initial provisioning of devices and the start of operations.

E4 is mainly offered as an on-premise solution, such that our applications will run on your own infrastructure, as opposed the managed version. Our philosophy is to have a minimal footprint, and a tight exposed surface from our services. We also carefully E4’s back-end to be modular, so we can easily adapt to your constraints. We can also interface with your existing services, such as your own database server or logging system, if you already have them in place.

Deploying E4 is a 4-step process:

  1. Installing applications and services
  2. Preparing the device software
  3. Enrolling the devices
  4. Operating the devices

Below we’ll review each of these steps:

Installing applications and services

E4 is composed of several components and services, where the bare minimum required is:

  • Our E4 core application (C2)
  • An MQTT broker (typically the one already used by your IoT devices); we use VerneMQ, but any MQTT 3.1-compliant
  • A relational database management system (any *SQL, such as SQLite, PostgreSQL, MySQL, and so on). Teserakt can provide the database (including a failover replication and backups) or reuse one you already have.

Additional components typically required for production environments are:

  • Our automation engine application, enabling key rotation policies
  • A web UI, to ease devices and topics management (or two command line clients, providing the same set of features)
  • ElasticSearch, Logstash/Filebeat, Kibana instances for the application logs and/or MQTT messages collection, processing, and analysis
  • Jaeger and OpenCensus agents instances, for observability metrics collection and analysis

The high-level architecture looks as described in the diagram below:


Hosting requirements

Sizing the hosts for deploying all the stack is mostly dependent on the number of devices you are managing, but our applications are very lightweight, and usually require little resources to operate (that is, less than 500MB of memory). Other services such as storage and monitoring require more, but all in all everything would fit on a single standard virtual machine, with 4 cores and 8 GB or memory.

Our back-end applications are built in Go and are statically compiled by default. This allows them to run on a wide range of OS and architectures, should it be Linux, OSX, Windows or Arm platforms, without any additional libraries or packages.

Additionally, our stack can fully be deployed in containers, such as Docker. Application images are built from our continuous integration on each release, and can be pulled from our private registry. Containers make it really easy to deploy and update, but are not always an option. We can adapt to what works the best for you.

Automated installation and updates

We want to offer repeatable, reproducible, and verifiable deployments. This is why we choose Ansible and scripted the full installation process of our services. This requires at least one host, and SSH access with a user having administration privileges. All the services are configured from a single file, making first installation or maintenance updates as simple as the push of a button.


Although we can provide our monitoring stack, we don’t exclude integrating with your own to leverage your existing processes and avoid having to define new ones. All our applications produce structured logs in JSON format, making it easy to adapt and transfer to any log management solution or SIEM. Observability traces can also be forwarded to any OpenTracing compatible back-end of your choice.

Scalability and high availability

Our deployment support horizontal scalability, by load-balancing requests to our applications. But it would require a large number of operated devices before hitting the limits of a single instance, as our applications generates no load or traffic when not provisioning new devices or performing key rotation operations. For high availability, we still suggest to deploy failover instances of the C2, automation engine, and database in order to ensure service continuity. This being highly dependent of your infrastructure and use cases, we’ll provide you advice tailored to your needs prior to the initial deployment.

Preparing the device software

Here, the goal is to add the E4 client library in your application, in order to support message protection. We’ve already discussed the client library integration in our previous post, and here’s a quick reminder:

  • The application must load a saved version of an E4 client during initialization, or create it if it does not exist yet
  • The application must subscribe to its device’s control topic upon initialization
  • Outgoing MQTT messages must be protected before being published
  • Incoming messages must be unprotected before letting the application process them

Our client library is open-source and available in various languages and format to allow a wide range of applications to include it. But in case you don’t see one fitting your needs, feel free to contact us.

Enrolling the devices

When integrating the client library in your application, you will probably notice that creating an E4 client require an initial key. Such key will for example be generated and burned into the device at production time. Then, you will be ready to provision the device.

We’ve identified two main scenarios to provision device keys in E4:

  • Manually: where you will need to hold the device identifier and its key (either a symmetric key or a public key, depending on the preferred mode of operation), and manually provide those information to the C2, via the CLI client, the web interface, or directly calling the API.

  • Automatically: based on a trust-on-first-use (TOFU) mechanism, whereby the device will be first started inside a trusted environment, and register itself in E4 by making a C2 API call, with its identifier and key.

Operating the devices

Once registered on the C2, the device is almost ready to be operated. The last step is to assign it the topics it must publish to or receive messages from, so that the C2 server can transmit the keys of those topics to the the device. With a proper client library integration, and the device powered up enrolled, this should only require a few clicks from the web UI, and can also be automated in the enrollment phase.

To deal with reboot or power failures, on first creation, the E4 client will save a copy of its state inside the provided storage, allowing to restore it from this save when the device application initialize, without having to go through the E4 client creation steps again. The E4 client updates the saved data automatically each time it is modified by a control message, such as when receiving a new key (from a key rotation), when a topic is assigned or removed, or any other operations where information is transmitted to the client and must be persisted.


From here, your devices are ready to communicate securely, with minimal changes to your infrastructure and applications. Thanks to our modular approach, E4 can be easily adapted to your needs and constraints. Contact us if you’d like to learn more about it or have any questions.