Limit access to Node-RED via client certificates

Hi folks,

I saw tonight an interesting proposal about an extra level of security for Node-RED via internet, by whitelisting a list of ip addresses.

Although it is a very interesting article, I don't think I will be able to use it because my ip addresses (that need access NR) are not fixed. Filtering on MAC addresses would solve my case, but you don't know the MAC address of the device that sends the request (if I am not mistaken).

So there need to be something else on my devices, that allows them to access my Node-RED web application. I am not a security expert, but I assume a client certificate is safe enough to do the job.

1. Setup SSL

Note that in order to be able to use a client certificate, you first need to setup SSL in Node-RED (i.e. https).

SSL works like this:

  1. Your device (e.g. browser on your smartphone) accesses your Node-RED system.
  2. Based on your server certificate, an SSL handshake will be executed between both devices.
  3. Your device browser receives the server certificate and will encrypt all data with it, before sending it to the Node-RED server.
  4. Your Node-RED server will decrypt the data using the corresponding private key.
  5. Which means all your data is transferred in a secure way between both devices.

On my Raspberry I had to execute following commands to create a private key, csr (certificate signing request) and corresponding (self signed) certificate:

cd /home/pi/.node-red/
openssl genrsa -out server-key.pem 2048
openssl req -new -sha256 -key server-key.pem -out server-csr.pem
openssl x509 -req -in server-csr.pem -signkey server-key.pem -out server-cert.pem

In the third command (to generate the csr file) you will get some questions which you need to answer. It is very important that for the CN (common name) you enter the hostname that you use in the url to access your Node-RED web application. Because when the CN of the server certificate does not match with the hostname in the url, your browser will reject the server certificate.

And you need to enable SSL in Node-RED, via the settings.js file by providing the key pair (i.e. private key and corresponding certificate):

    https: {
        // Server key pair
        key: require("fs").readFileSync('/home/pi/.node-red/server-key.pem'),
        cert: require("fs").readFileSync('/home/pi/.node-red/server-cert.pem'),
        
        // Enable SSL (i.e. https)
        requireHttps: true,
    },

After restarting Node-RED, you should be able to access your flow editor via https.

2. Setup client authentication

As an extra step we will setup client authentication, which works like this:

  1. During the SSL handshake, the device browser client will need to send a client certificate to the Node-RED server.
  2. The SSL handshake will only be successfull if the client certificate is recognized by the Node-RED server.

Which means that the client can only access the Node-RED system when it has the correct client certificate.

To implement this, create a client certificate in a similar way. At the end we also do an extra step, to convert the pem file to a crt file (which can be loaded into a browser):

cd /home/pi/.node-red/
openssl genrsa -out client-key.pem 2048
openssl req -new -sha256 -key client-key.pem -out client-csr.pem
openssl x509 -req -in client-csr.pem -signkey client-key.pem -out client-cert.pem
openssl x509 -in client-cert.pem -outform pem -outform der -out client-cert.cer

In the third command (to generate the csr file) you will get some questions which you need to answer. It is very important that for the CN (common name) you enter the hostname that you use in the url to access your Node-RED web application. Because your browser will only pass (automatically) this client certificate to the Node-RED server, when you navigate to the hostname (that matches the CN of the client certificate).

And you need to let Node-RED know that it is only allowed to give access to the clients that have this client certificate

    https: {
        // See the SSL settings from the first section above...
       
        // Only accept certificates from these certificate authorities
        ca: require("fs").readFileSync('/home/pi/.node-red/client-cert.pem'),
        
        // Requesting the client to provide a certificate, to authenticate.
        requestCert: true,
        
        // Server should not accept any unauthenticated traffic
        rejectUnauthorized: true
    },

After restarting Node-RED you should not able anymore to access your web application, because your browser does NOT send yet the client certificate to the Node-RED server:

image

So you need to import the client certificate into your browser. For Chrome on my Windows portable I did it like this:

  1. Go to the Settings menu

  2. Go to Security:

  3. Go to Manage Certificates:

    image

  4. Import the client-cert.cer file that you have created in the last command

  5. When you now navigate to the hostname of your Node-RED server, your browser should pass the client certificate in the request which should allow you to access your Node-RED web application again.

Of course you need to import the client certificate in the browsers on ALL your devices!

P.S. This was a very quick experiment, so it might not be complete. As always all constructive feedback is very welcome!

Bart

6 Likes

Very nice @BartButenaers
Client certificates is indeed very effective.

I recommend reviewing xca : Home

It’s a really nice cert management platform (local), and allows to create the various types of certs, and certificate authority management.

Should remove the need for the various terminal sessions with openssl

Hi @marcus-j-davies,
What I liked more in your proposal, is the fact that you only have to make adjustements in your Node-RED server. When using client certificates, you need to do changes on all your clients. Which requires more maintenance.

Yes indeed a cert manager program is more user friendly compared to openssl commands. Or if somebody has some free time left to create a sidebar in the flow editor to manage the cert files. Or it might perhaps be useful to add this kind of stuff in the bash script for installing Node-RED on a raspberry? Don't know...

1 Like

I think my aim for it, is to allow the inexperienced users to have a barrier without trying to understand the various products / services that are around.

It's been updated and now uses a built in class to help add the IP Address', Ranges & Subnets.

example:

const allowedIPs = [
  "127.0.0.1",                    /* Localhost */
  "172.16.0.0/24",                /* Private Network */
  "103.22.200.1-103.22.203.254"   /* CloudFlare range example */
];

Taking out the hosted services from the equation, both the client cert and IP White listing approach are both extremely powerful mechanisms! :nerd_face:

Note: I added the the security tag to this post

2 Likes

It is a good way. But only if you protect your certs and keys correctly.

It is critical that node red only has read access and only to the correct files. Sorry not at pc so not in position to work out details.

1 Like

Are you sure that does what you think?

Won't work for anyone with a local proxy? Might not work for anyone on a double NAT WAN?

So you may need to add some caveats.

Using cloudflare was just an example, it's more to demonstrate adding a range is supported.

@BartButenaers Thank you for this walk through, where are the config files located to update them for Node-RED?

@inayet,
Could you please explain a bit more what you mean with the config files? I only have adjusted my /home/pi/.node-red/settings.js file. And that contains the paths to my certifcates, as shown in my post above.