Secrets
The Problem
Throughout your code, you'll need to reference sensitive data such as usernames, passwords, API keys, etc. This is problematic as you may want to share your code with others, backup to Github, etc. While Home Assistant provides an easy way to redact secrets from your configuration files, Node-RED does not.
Previous Solution
One solution is to use a special node called node-red-contrib-credentials. While this approach initially seemed promising, it came with too many drawbacks:
- Must add a node everywhere you want to access a secret (this quickly makes a mess of your flows)
- No centralized secrets management - the secrets added in one node are not available to another
- Copy/paste of nodes causes their secrets to be erased
Current Solution
My current solution is easy to setup, easy to use, and leverages built-in Node-RED features.
How it works
Context is a way you can share data between nodes and flows without using the msg object. My solution leverages our own custom, persistent context storage we'll call "secrets". By using the global
keyword whenever we read/write secrets, we are able to access our secrets across all nodes and flows.
Ultimately, all secrets are stored, in plain text, in /config/node-red/secrets/global/global.json
.
warning
Be sure to exclude the /config/node-red/secrets path in your .gitignore file (since the secrets are stored in plain text).
Setup
- Add the following section to your settings.js:
contextStorage: { default : { module: "memory" }, secrets: { module: "localfilesystem", config: { dir: "/config/node-red", base: "secrets" } } },
- Restart Node-RED
Adding / Editing Secrets
You can manually create and or edit the secrets file (/config/node-red/secrets/global/global.json
):
{ "first_secret": "123", "second_secret": "abc"}
note
While immediately available in memory, secrets modifications through Node-RED (i.e. the methods below) will take a few seoncds to write the changes to the secrets file.
You can also create and or edit each secret by running the below in a function node (replacing your_key
and your_value
appropriately):
global.set("your_key", "your_value", "secrets");
And you can even create and or edit secrets with change nodes:
[{"id":"bf2ad73a.23bdb8","type":"change","z":"977bc9ad.687238","name":"Save Secret","rules":[{"t":"set","p":"#:(secrets)::some_secret","pt":"global","to":"some_value","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":290,"y":260,"wires":[[]]},{"id":"5c5c19b4.549de8","type":"inject","z":"977bc9ad.687238","name":"Press","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":260,"wires":[["bf2ad73a.23bdb8"]]}]
Accessing Secrets
You can access secrets through any node that can access context (be sure to select the "secrets" context storage).
ex. the inject node:
ex. the change node:
ex. the switch node:
You can also access through the function node:
var secret = global.get("your_key", "secrets");