Nodered - hub & spoke - security

Bit of a can of worms - I work for a MSP and am writing a reporting flow in Node-Red which pulls in data from various sources, puts it into a docx-template and allows the user to download it.

The reporting flow runs on a central instance of Node-Red and this handles:

  • Connections to the various external data sources (credentials are stored on the central instance)
  • Web form UI for users to specify the report details (using http nodes and templates NOT Dashboard/UI plugins), which posts to another http node on this same instance to run the report and provide a download button.
  • HTTP "data" connections to other flows on the central Node-Red instance to grab generic data
  • HTTP "data" connections to satellite Node-Red instances, one per customer, to grab customer-specific data (each customer environment is isolated from our network, we can't allow direct access from our central instance)

I need to secure both of the UIs using our internal AD/LDAP as a user/groups source, as well as securing inter-node-red HTTP connections. The admin UI and Form UI need to be accessible to different user groups.

There are 3 areas which need attention (at least) - I will be enabling SSL across the board:

1: Admin UI - currently using GitHub - hardillb/node-red-contrib-ldap-auth: A Node-RED authentication plugin that uses LDAP as the backend user store. which works fine
2: Form UI running on the central instance
3: Inter-node-red HTTP calls from the central instance to itself, and to satellite instances

Mainly stuck on how to differentiate Form UI and "data" HTTP node authentication - I know I can set authentication for all HTTP endpoints using settings.js, but this won't work for the data nodes, unless I can somehow pass credentials/token through from the Form UI nodes to each data HTTP node securely (which might be the way to go - if so, anyone done this before?).

Appreciate any ideas on how to do this - scratchpad of other ideas :

  • Reverse Proxy with authentication in front of each instance
    • How do I pass credentials between node-red instances?
    • How do I log out - it's not built into the application, so there's no "logout" button
  • Split the data and Form UI nodes out to different instances of Express so they listen on different ports, handle authentication differently for each port
  • Split the data and Form UI nodes out to different instances of Node-Red (seems a bit expensive)

Thanks in advance...

Hi, the most common and recommended architecture for this would be to use a reverse proxy for anything that needs to connect to your central instance. You could run this on a separate server (recommended for best overall security) or on the Node-RED server if it has capacity.

Get the proxy to handle the TLS termination and the LDAP authentication and authorisation, passing suitable headers and tokens through to Node-RED as needed.

Outbound security is then a separate issue and depends how the Node-RED based API's on the other Node-RED instances are configured.

In truth, best security practice would probably be to use a secured message broker (MQTT would be sufficient) for all API connections. Then you could choose whether your central service requests updates from the satellites or whether they simply send data periodically (or on update events). Or indeed some mix of the 2.

The main thing to note is that the focus of Node-RED is on being a low-code compute environment and not on authentication and authorisation. This is the "correct" approach, at least from an enterprise perspective. Other tools are better at dealing with the complexities of IDAM.

1 Like

Thanks @TotallyInformation - I'll look into MQTT, hadn't thought of that. Alternatively, may end up dropping the central instance idea and generating the report on the customer instances instead - I can lock down the data responses to a 127.0.0.1 client and use LDAP nodes to authenticate the Form UI.

1 Like

The only thing i would add here over what Julian has recommended (and he is THE security expert on here) - is that i would have the central node red instance fronted by another node red (in a completely diffrent VM/piece of hardware). The job of this VM would be to sanity check data etc coming into the main instance so if anything untoward happens remotely - it will blow up this instance before it has a chance to pass anything onto your central/Master NR

Use a different comms mechanism between the master and the sanitizer than you do between the sanitizer and the data collectors, this making sure that any Zero day protocol based exploit can/will be contained

Craig

2 Likes

Wow, someone even more paranoid than I am! :grinning:

That is certainly an option and, for sure, you MUST validate inputs from outside, that is a fundamental requirement of any interface whatsoever.

But unless this were something you expected to get targeted attacks, I'd probably just do that in the same central instance. There's lots more you could do to harden everything if you think security is likely to be an issue and the data is high value and sensitive. But the most important point is to use the right tools for the right job.

1 Like

Thanks both for the great advice.

I am taking the central instance out of the equation as it adds unnecessary complexity; downside is it means I have to duplicate the report generation flow on each of the customer-specific satellite nodes, but Git/Projects make this doable for the most part.

I will use a reverse proxy for TLS / SSL offload as suggested and see if I can work out how to authenticate/authorise the Form UI too (I'll keep LDAP auth for the admin UI separate).

Couple of outstanding questions:

  • Is it possible to put an ACL in front of HTTP request nodes so they only accept connections from localhost? I can use msg.req.ip and handle it after the node has been hit, but wondering if there's a better way to do it?
  • Using a reverse proxy for auth - how should I manage sessions (if I need to) - and how does Node-Red validate headers/tokens (if it needs to - everything is coming through the proxy)?
    • Specifically, how do I enforce an inactivity timeout and allow a user to log out; assume I clear a cookie for the latter?
    • If there's any best practice documentation you can point me to, that would be great.
  • How do Node-Red Projects (git) handle node credentials? I've got a SQL node which will need its read-only credentials to be deployed on all node-red servers which run the cloned Project. I know that export/import does not copy credentials - do projects do this?

You can usually bind services to a specific network. In Node-RED's case, you can change the binding from the default 0.0.0.0 (all networks) to 127.0.01. However, if you have IPTABLES or similar local firewall, you can simply block inbound traffic for the port. For a production server, you really should be blocking ALL inbound traffic anyway and explicitly allowing only what needs to be used.

If all traffic goes through the proxy, all you need to do in Node-RED is set the proxy trust in settings.js. This is actually a standard Node.js/ExpressJS thing. The proxy should handle the sessions and redirect to a login (and/or account self-service if required) page if the users session is invalid or expired.

All node-red may need is the user-id if you need to process things by user. Maybe some kind of authorisation tags if you need to be able to process by authorisation types. These can be passed as custom headers for HTTP connections or inserted into websocket messages if needed (as websockets doesn't support custom headers).

Doing it all in the proxy means that you don't need to mess with Node-RED for any of the authentication and session stuff.

The proxy's authentication service should handle that at the edge. Cookies cannot be relied on but ideally should be deleted for expired or invalid sessions since you might want to have some front-end code that is session aware. However, since cookies cannot be relied on, this should not be part of your session management which needs to be server-side. The authentication service should take care of everything.

Sorry, I don't use them. I'm actually surprised you are using them in production?

Ideally, these would be distributed using a key management tool. They would be in an independent key store & made available to Node-RED most likely via environment variables.

Fantastic @TotallyInformation - thanks!

Re: NodeRed projects - this seems(seemed) to be a good way to manage flow updates centrally and deploy them without having to edit things on each instance. We would make the change and push to the repo, then pull it down on each instance as required (rolling back to a previous version quickly if needed). If this isn't recommended, do we have a best-practice way to do it?

Re: Credentials - interested in passing these via environment variables per instance (we do this elsewhere) - but this means pulling in the variables to set credential node values per instance, which I can't get to work (I've tried {{env.variablename}} in the Username field here and it is always blank) - do we know if this is supported in Node-Red / what syntax to use?

Thanks again

I'm not an expert here, but I don't actually think you need projects to do this. Yes, it adds some helpers in the Editor UI but in a production environment, that is as likely to be a hinderance rather than a help since you probably don't want Editors to be able to change projects since that could entirely break the system.

The majority of the data controlling Node-RED is already character based rather than binary and so should be fairly straight-forward to handle in GIT. Of course, one issue is that if you update the files outside if Node-RED, you really should take down the instance, make the changes then restart. Otherwise, it is possible that you could end up with data issues.

Unfortunately, it has been a long time since I've used MySQL/MariaDB so I don't really know how the node works. Might need a separate question for that, I expect someone on the forum knows. And if not, then maybe the node's author can comment.

1 Like

There's a lot to be said for "RTFM" - it's in the MSSQL node documentation; env variables can be specified as {{variablename}} in the config node.

Thanks for your help @TotallyInformation

1 Like

With the proposed new architecture and NR at each customers site - why would you not just do a VPN from the NR box and terminate it at the firewall. Restrict traffic as appropriate with Firewall rules to only allow VPN endpoints into the proxy server for Authentication etc

Craig

Hi @craigcurtin - thanks; I should clarify that the NR instances are in our data centre in customer specific network segments rather than on-site at the customer end. All of our users are internal - customer connectivity is required to grab data from our managed systems in their sites.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.