How do you securely give credentials to a stand-alone Function node?

Hi all,

I’m stuck on what should be a simple design question:

How do you securely provide credentials to a stand-alone Function node without putting them in clear text anywhere in the flow?

Most credential handling in Node-RED is tied to specific node types (MQTT, HTTP, DB, etc.). But I have custom logic in plain Function nodes that needs credentials — and I can’t find any built-in way to feed them in securely.

I don’t want to hardcode them, put them in flow/global context, or expose them as env vars.
And to me, this seems like something Node-RED should support without having to install third-party integrations, since those can introduce their own security concerns.

Is there an established, built-in pattern for this?

For totally secure access, you need a hardware key manager. Failing that, a software key manager should be used.

But no, there is no existing pattern for this specifically. A lot of people use environment variables to hide credentials. But, of course, that is NOT AT ALL SECURE. Though you will find many articles online telling you otherwise.

You should be able to find a number of software key manager tools that could be put to use with a function node. Anything that works with node.js should be possible.

Software key manager still needs a secret to unlock? How to provide that then?

There are various ways, best to read through the docs for some of the tools.

Of course having a air gapped hardware will be most secure. But to balance out the ease of use with security, could we have a context/node/module which stores credentials and nodes could query it with a specific key to retrieve the credentials. That node/module could encrypt all the secrets on disk using node's security key. That would atleast take care of clear text secrets stored in context/code.

Basic credentials already exist in Node-RED, it is up to node authors to use them. I believe there is still also a contrib node that pulls/writes credentials. Node-RED credentials are encrypted using a key stored in settings.js - which honestly means that they can, in no way be considered secure. However, they do prevent them being exported when sharing flows.

If you want something more secure, you need to at least use a key manager as I said.

I've not needed to use a key manager for Node-RED so I don't have masses of detailed knowledge. I DO use a key manager now for securing git commits and npm publishing. This runs on my desktop and requires a manual passcode to open the locker. Obviously, that is less suited for a server but tools exist and they can be used with node.js and therefore with Node-RED as already mentioned.

The part I like the least about how it currently works is that it's not entirely clear what is affected by NR's secrets vault or not. And it certainly doesn't cover enough, for example secrets in urls. It should ideally at least have a js api to be called in function nodes, perhaps anywhere else too.

If you put the function node in a subflow then you could use a Credential type property in the subflow. It is then stored encrypted in the flow in the same way as mqtt credentials, for example.

1 Like

Basic credentials already exist in Node-RED, it is up to node authors to use them. I believe there is still also a contrib node that pulls/writes credentials...If you want something more secure, you need to at least use a key manager as I said.

That's what my concern is, credentials are not available to users of node-red (people who use node-red) but only to developers who write node modules.
There is a contrib node and people can use third party key managers, however storing credentials should be a basic capability (IMHO) provided in node-red .

If you put the function node in a subflow then you could use a Credential type property in the subflow. It is then stored encrypted in the flow in the same way as mqtt credentials, for example.

This sounds promising, but I tried creating a subflow, but I couldn't find a place to specify a 'credential' type property. I only see plain text properties with no way to specify the type.

We've had an item on the backlog for a while to add credential type properties to the Inject/Change nodes for exactly this scenario - FR: Add credential type to Change/Inject nodes · Issue #5063 · node-red/node-red · GitHub

When you edit the subflow template properties, you can pick what type of input should be used.

1 Like

that will be awesome!
to take this idea forward, what are your thoughts around having a vault (just like we have config nodes/context) where we can manage all secrets centrally ?

thanks, I will wrap my function in subflow temporarily.

You can use node-red-contrib-credentials (node) - Node-RED

This will store arbitrary values in the flow credentials and attach them to messages, so they can be used by the function node afterwards (which could then remove them with e.g delete msg.cred before forwarding it on.

That's a creative workaround. You would still need to be aware of the issue. Perhaps the use-case for built-in secrets vault is mainly aimed at new users not familiar with IT security? They will not be aware. And then there's the overload of creating a subflow to get secrets. I much prefer js env.get.

Which issue?

Using credentials in a subflow means that the secret does not exist as plain text anywhere, unlike using an env var.

Sorry to be picky, however, it does exist as plain text in memory if Node-RED is running.

The bottom line is that anyone with access to update flows using the Editor has access to the settings.js file and can read the encryption secret - though you could make that an external reference to protect from that, as long as Node-RED was running under a separate, secured, user id.

But anyone with write access to flows can see the credential simply by dumping it to debug. So Node-RED credential variables only "protect" from flows being exported.

1 Like

Yes, certainly. I meant that it does not exist in plain text in a file anywhere, unlike an env var.

This issue:

The secret is stored in plain text in settings.js file? I don't see how that's any different than storing it in plain text in .env file.