Centurion: Server in the Cloud to Control Everything

by RakaAmburo in Teachers > 1

109 Views, 0 Favorites, 0 Comments

Centurion: Server in the Cloud to Control Everything

centurion intro.png
Centurion: Server in the Cloud to Control Everything

Welcome again to this new episode of our blog/channel. In this opportunity, we will be starting a new series that we will call the "Centurion series". Which by the way will be tightly related to the alarm series. As a brief introduction, I can say that it will be based on a continuously evolving HTTPS/WebSocket server, that we will use as a centralized system to connect and coordinate all our devices. You can think of it as the Tony Stark Jarvis, who controls the devices connected to the cloud. With this system, you will be able to control not only the security in your home but all the IoT gadgets everywhere. I thought this to be located in the cloud, in this way we will able to triangulate all communications by this system.

For this first chapter, of course, we will be working on a simple starting point. A straightforward implementation of an HTTPS server in NODEJS, that will serve as a WebSocket server as well. With a basic security configuration that will restrict access only to our clients. This server will allow secure WebSockets clients to establish a permanent and reliable connection to exchange constant information. And also, will allow HTTPS connections for specific situations that require only a "request and response".

In incoming chapters we will be adding features, like for example, more security layers to make it bulletproof; artificial intelligence, and much more.

You may be asking, well ok but I would need a server in the cloud. Yes, but nowadays you can have that at a very affordable price. Am talking about, let's say, a Linux system with the basics. We would not need that much computational power at first. For now, we totally can work locally to learn and understand the basics.

Supplies

nodejs4now.png

Just for now! we will be working with Nodejs and its libraries. So we will be needing a computer with a NODEJS installed. And.. our brains of course.

Check this tutorials for nodejs basics.

Diagram

centurionDiagramFinal.png

As you can see in the diagram, on the left we have the server in the cloud that for now could be perfectly hosted on a local machine. On the right you will find all the possible clients that we can have and how they can interact with the server. And how we will be able to triangulate connections, let's say, from our phones to all the devices in our homes or offices.

You can check out the code from the Git repository.

Security Layer (creating the Certificates)

securityLayer.png

As mentioned earlier, we will apply many security layers. The first barrier for possible attackers will be our well-known HTTPS protocol. To do that we will have to provide certain files containing keys and certificates to the HTTPS NODEJS server configuration. Those will encrypt the content of the communications established to the server, and we will add a key that the client will have to present to be able to establish the connection. Since this will not be a public service and only will be used by us, we will create self-signed certificates, which have no cost at all.

I will not dive deep into the specifics of these certificates since the subject is kind of complex and I want to keep things straightforward. I have created a simple list of commands to create the required certificates with the use of the OpenSSL tool. You will find this information in certificatesDocumentation.txt

The important thing here to keep in mind is that you will need to run these commands each time you want to renew the certificates. Which can be done, depending on the criteria of each one. As you will see is fairly easy to do it. Moreover, we will be automating its creation in future episodes, so basically you can renew the certificates once a day if you want. Or for the paranoid ones, can be done each hour :). But I would say it doesn't make sense.

You will find in the documentation how to install SSLTool in Windows as well. In many Unix systems is installed by default.

Centurion (the Server)

centurionTheServer.png

Centurion is located in the file called main.js. If you open the file you will find the libraries we will use. Of course, libs like HTTPS, WS, FS, and EXPRESS are self-explained and we have used them before. We will add a new one "ws-rate-limit" which restricts the message events and is part of this first security layer. So this configuration will only allow a certain number of messages per time unit.

It follows the configuration of the certificates and the creation of the HTTPS server. The variable wsConns will be storing the objects representing each client containing their identification among other things. In this way, we will be able to control them, send them messages, and terminate their connection if required.

noop and hearbeat functions will be part of the connection status checking. We revisit them in a few lines.

Then the web socket configuration, mounted over the HTTPS server. And of course its security behaviour.

const wss = new WebSocket.Server({
    noServer: true,
    maxPayload: 450, //max size per message
    verifyClient: async (info, callback) => {
        callback(true);
    }
});
server.on('upgrade', function upgrade(request, socket, head) {
    wss.handleUpgrade(request, socket, head, function done(ws) {
        wss.emit('connection', ws, request);
    });
})

Notice that you will see many lines commented on. We will use those lines in the future. I leave them there for practical reasons.

The function respObserver will be handling timeouts in case some internal applications do not respond. We will discuss this in the future.

Then we will set the behavior of several events on the connection, like pong, message, limited, close, and error. Take notice that for this simple implementation, the event message will be logging the incoming message and sending a message back. We will use this for testing purposes.

utils.logInfo("incomming raw msg: " + msg)
ws.send("received")

The limited event will be handling the clients that reach their limit of messages sent. For now, we will log information about the request.

Close and error will be logging details as well. its behaviors will be getting more complex in the future.

A function is defined to establish a system to check the connection status:

/* ping heartbeat interval, terminates the connections if idle */
const interval = setInterval(function ping() {
    wss.clients.forEach(function each(ws) {
        if (ws.isAlive === false) return ws.terminate();
        ws.isAlive = false;
        ws.ping(noop);
    });
}, 60000 * 4); // four minutes!

In case the connection gets idle. The function will terminate it forcing the client to re-connect. This, among pong event, "noop" and "heartbeat" functions, will be sending back-and-forth heartbeat messages every 4 minutes, to ensure the connection reliability.

The validate function will be validating tokens in the future. That will be a part of our second security layer.

Next, we define the post method (we can define all methods that we need), again with a dummy response just to test.

Also a default response for nonexistent routes

Finally, we complete the configuration of our server providing the port and logging the server information.

The Websocket Client

webSocketClient.png

So as you may figured out so far, we will be connecting our homes, offices, or whatever physical location you want to monitor, with Centurion through a WebSocket client. You may have heard about this protocol mainly used in web pages to interact dynamically with servers. We will use it as kind of different as you can see. Establishing a permanent connection and feeding information that is required, or that is triggered in that physical location, an alarm for example.

Similarly to the server, if we look at the code, we will find at the top, the lines related to the basic configuration. The required libraries, of course, the certificate configuration and the noop and heartbeat function to monitor the connection.

Beare in mind this is just an example to illustrate basic communication, this will be getting more complex in future episodes.

The object const wsClient = [] will be containing the functions start, send, isConnected, and stop. I guess they are self-explanatory. And we will be using those as the system grows. When the client starts, the connection is stablish with the required configuration:

wss = new WebSocket(`wss://${ip}:${wsPort}`, {
    protocolVersion: 8,
    origin: `wss://${ip}:${wsPort}`,
    rejectUnauthorized: false, //since we have an self signed certificate is required
    key: privateKey,
    cert: certificate,
    headers: { "authorization": "12345", "client-id": 'asus' }
  });

Stick to this configuration, will deal with details in the future.

Certain events can be handled like open, ping, close, error, and message. To handle the life cycle of the client. For now, we have the basics and logging, just to understand what is happening.

As this file is executed with node, the client will establish the connection and send each 4 hours (60000 * 60 * 4)

wsClient.start(serverIp, "")
setInterval(function () {
  wsClient.send("to the server");
}, 60000 * 60 * 4);

That will give us a total of 6 messages per day, I would say a fare amount that will be required normally.

Https Client

httpClient.png

This type of communication will be used in cases in which it doesn't make sense to have a permanent connection. For example, a specific request and Android devices to give an instruction or consult some status. So for this section, I give you examples to test with curl and wget:

Git Bash (Windows environments downloading Git)

curl --key client-key.pem --cert client-crt.pem -d '{}' -H "Content-Type: application/json" -X POST -k 
https://{host ip or name}:8888/exec

wget (Linux environments like Ubuntu)

wget --no-check-certificate --certificate=client-crt.pem --private-key=client-key.pem  --method POST --header 'Content-Type: application/json' --body-data '{}' 'https://{host ip or name}:8888/exec'


Notice that we will be expanding in future episodes, the "Android path" so do not despair. For now, you can play arround with the above ones. For the inpatients, you will find a Java class containing an example to make a Post request in Android attached below this Step. With error management, retry policy, JSON result handling, and of course TLS mutual authentication.

Also, you will find attached, some images showing how to configure Postman to achieve the same.


What Is Next?

whatisnexcenturion.png

So in future episodes, as mentioned before, we will be adding more security layers. Like for example tokens and message encryption. We will dive deep into Android not only to send post requests but to connect with WebSocket. And finally, we will build a basic functional system that will serve us as our assistant in the cloud, monitoring everything.