DEV Community

Shan Desai
Shan Desai

Posted on • Originally published at shantanoo-desai.github.io

Use htpasswd to secure your node-RED Container

Securing Node-RED

node-RED containers can be made secure when using Admin Authorization features
using its settings.js file and mounting it to the container. Sounds quite simple,
however unlike other containers that let your configure their environments via environment
variables whereby the stored credentials are in plaintext, node-RED passwords typically are
stored in encrypted format i.e., bcrypt.

Automation: Encrypted Passwords

There is a possibility of obtaining the hashed (encrypted) password using an ephemeral container
using:

docker run -it --rm --entrypoint /bin/bash nodered/node-red:2.2.2-12-minima
Enter fullscreen mode Exit fullscreen mode

One in the container use:

bash-5.0$ node-red-admin hash-pw
Enter fullscreen mode Exit fullscreen mode

which will prompt you to enter the password and the resultant hash password will be available for you
to use.

This is however, a bit more of manual work and in case where you wish to perform more easy, automated
setups we might need to find a different way.

Automation Script via htpasswd

Apache provide a great CLI tool called htpasswd that can encrypt our plaintext passwords
into the required bcrypt hashed format which the node-RED UI and Admin Auth backend will decrypt.

For most of the distributions the package name is apache2-utils so for Ubuntu/Debian you can install
htpasswd using:

sudo apt-get install apache2-utils
Enter fullscreen mode Exit fullscreen mode

Jumping right into it!

You can go through the man pages of htpasswd to find how it might suit for your needs. I am cutting
to the chase as to how I used it.

In order to generate my hashed password that will be compatible with node-RED's decryption backend, I had
to find the total Computation Cost (rounds) needed, which I found out the value was 8 based on some
code diving using node-red-admin repository.

htpasswd -nb -B -C 8 admin testpassword
Enter fullscreen mode Exit fullscreen mode

will produce the following result:

admin:$2y$08$JTOJDi/whZxz8qwsdwCkfedhVOhh00QiKHICdHLImGS8XM2v.fng2
Enter fullscreen mode Exit fullscreen mode

Creating an Environment Variable Template file for node-RED Docker Container

we will make the automation a bit more easier for us, whereby we can use envsubst commandline to fill
and environment variable called NODERED_AUTH_ADMIN in a file called node-red.env. But in order leverage
the power of envsubst we will create a template file called node-red.tpl.env which has the following
content:

cat node-red.tpl.env
NODERED_AUTH_ADMIN='${NODERED_AUTH_ADMIN}'
Enter fullscreen mode Exit fullscreen mode

We create simple bash script which will do the following:

  1. Accept a plaintext password as an argument to the script
  2. use this plaintext password and hash it with htpasswd
  3. export the variable which has the result of htpasswd
  4. use the exported variable to replace the node-red.tpl.env file to node-red.env with the value
  5. unset variable

The script is as follows:

cat nodeREDPwgen.sh
#!/bin/env bash

function nodeREDPW {
    # 1st argument to this script is plaintext password
    local NODERED_AUTH_ADMIN=$(htpasswd -nb -B -C 8 admin "$1")
    export NODERED_AUTH_ADMIN
    touch node-red.env
    envsubst '${NODERED_AUTH_ADMIN}' < node-red.tpl.env > node-red.env
    unset NODERED_AUTH_ADMIN 
}

nodeREDPW $1
Enter fullscreen mode Exit fullscreen mode

Example Usage:

chmod +x nodeREDPwgen.sh

./nodeREDPWgen.sh testpasswd
Enter fullscreen mode Exit fullscreen mode

will produce a node-red.env file after successful execution with the following content:

NODERED_AUTH_ADMIN='admin:$2y$08$/8NVmF2gJ3JDrmv0tX2ud.P7S9gqvB0ds2cRByhnZcRdZOWhTnPN.'
Enter fullscreen mode Exit fullscreen mode

Creating a settings.js file for Node-RED Container

copy the settings.js file from the node-red repository and adapt the adminAuth object
as follows:


  adminAuth: {
    type: "credentials",
    users: [{
      username: process.env.NODERED_AUTH_ADMIN.slice(0, process.env.NODERED_AUTH_ADMIN.indexOf(':')),
      password: process.env.NODERED_AUTH_ADMIN.slice(process.env.NODERED_AUTH_ADMIN.indexOf(':')+1)
    }]
  },
}
Enter fullscreen mode Exit fullscreen mode

Creating a docker-compose.yml file

services:
  node-red:
    image: nodered/node-red:2.2.2-12-minimal
    container_name: secure_nodered
    env_file:
      - ./node-red.env
    ports:
      - "1880:1880"
    volumes:
      - ./settings.js:/data/settings.js
Enter fullscreen mode Exit fullscreen mode

bring the container up:

docker compose up -d
Enter fullscreen mode Exit fullscreen mode

The UI is available at http://localhost:1880

Problem

If you try to login in by typing testpassword in the Admin UI, you will get Login Failed! But Why?

Investigations

It turns out that the password generated by htpasswd produces a variant of bcrypt $2y where as,
if we were to generate the password using node-red-admin hash-pw and added testpassword it would
generate a completely different looking password with the variant $2b.

Example: $2b$08$sfPlvPNDVVz/duAbAC2bbuNEVuvrwmU01x7plOAQIem6H187Xxq9G

Solution

It turns out that the $2y variant of bcrypt has compatibiltity and we could simply try and replace
$2y to $2b in our settings.js as follows:

module.exports = {
  // .. removed for brewity
  adminAuth: {
    type: "credentials",
    users: [{
      username: process.env.NODERED_AUTH_ADMIN.slice(0, process.env.NODERED_AUTH_ADMIN.indexOf(':')),
      password: process.env.NODERED_AUTH_ADMIN.slice(process.env.NODERED_AUTH_ADMIN.indexOf(':')+1).replace("$2y$", "$2b$"),
      permissions: "*"
    }]
  },
  // removed for brewity
}
Enter fullscreen mode Exit fullscreen mode

notice the .replace("$2y", "$2b") at the end of password key.

Let's spin the container up again using docker compose up -d and try to login with testpassword et Voila!!

We are able to login into Node-RED!

I found that Nick O'Leary (founder of Node-RED and the great guy that he is..) already did some research on this,
I just had to bring this all together.

If you have some suggestions, critiques than please get in touch with me and I would be happy to help.

Resources

GitHub Gist of the files for the impatient ones!

Oldest comments (0)