Hello,
as i understand when two erlang nodes connect to each other, they can do operations like spawning a process or rpc call on each other. Is there a way for an erlang node to connect to another node but only allow this operations (spawning a process, rpc call, … ) to be perform by one node and not another? for example nodeA connects to nodeB and executes some operations on nodeB meanwhile nodeB cannot execute any operation on nodeA.
if not possible, is there any other erlang modules to allow this kind of relation between two nodes?
if not possible, is there any other erlang modules to allow this kind of relation between two nodes?
gen_rpc
comes to mind. It’s an Erlang RPC library that follows client-server model. It’s independent from Erlang distribution. I think one can use it in client-only mode, without starting the server, although personally I haven’t tried that. Original project was abandoned, but we maintain a fork here: GitHub - emqx/gen_rpc: A scalable RPC library for Erlang-VM based languages Disclaimer: we consider this library legacy code.
But I can’t help but wonder if this is a case of XY problem. What you’ve described is, essentially, a client-server application. Would it make sense to create e.g. a REST API instead? The simplicity of RPC approach is deceptive: once you start dealing with upgrades, it arguably becomes trickier than rolling a REST API. In EMQX we had to create a complicated static check framework (reliant on reverse-engineered dialyzer PLT format) to make sure upgrades don’t break RPC.
Thanks for the reply,
The problem scenario is like the following:
We want a central node to be able to run code and monitor processes on some worker node but the worker node is behind a firewall that only allows outgoing connections to be made, so we cannot send request to it.
First i thought using erlang distribution can help by connecting the worker node to central node (initiating connection from worker) so we can monitor processes and issue rpc calls if needed from central node. The only problem with this approach is that it makes it possible for the worker node to execute code on central node which is not desired.
Hello!
When two Erlang nodes connect, they establish a peer-to-peer relationship, meaning both nodes have equal privileges to perform operations like spawning processes or making RPC calls on each other. By default, Erlang’s distributed nature doesn’t provide a way to enforce one-sided operations where only one node can perform actions on the other. However, there are several approaches you can take to achieve this kind of behavior.
One option is to use the -connect_all false
setting. This prevents Erlang nodes from automatically connecting to all other known nodes, allowing you to explicitly control which nodes connect. For instance, you can set -connect_all false
on nodeB
, ensuring that it does not automatically connect back to nodeA
. This way, if nodeA
initiates a connection to nodeB
using net_adm:ping(Node)
, nodeA
can perform operations like RPC calls or spawning processes on nodeB
, but nodeB
will not be able to do the same on nodeA
unless it explicitly connects to it. This approach provides a basic way to establish a one-sided communication relationship.
If stricter control is required, you can implement custom communication protocols using tools like gen_tcp
or gen_udp
. These allow you to define your own message-passing logic and restrict the kinds of operations that can be performed. For example, you could use term_to_binary
and binary_to_term
for encoding and decoding messages securely, ensuring that only specific operations are permitted.
Alternatively, you can use the rpc
module with added access control logic. By defining a process on nodeB
that acts as a gateway for incoming requests, you can filter and restrict the operations allowed from nodeA
. This approach ensures that even though nodeA
has access to nodeB
, it can only perform approved actions.
Other methods include using libraries like Cowboy
or grpcbox
to build APIs for controlled interaction or using Erlang ports for communication, where only one node exposes its functionality. While these approaches aren’t native to Erlang’s distributed model, they provide robust mechanisms for achieving one-sided interaction.
It’s important to note that while -connect_all false
is useful for controlling automatic connections, it doesn’t inherently enforce security or strict one-sided privileges. For production systems, combining this setting with access controls, custom logic, and network-level security measures like TLS or firewalls is recommended to prevent unauthorized operations.
If I understand you correctly, you are saying that you cannot fully trust nodeB? Then Erlang, or more precisely, standard distributed Erlang is likely not the answer to your problem. Any node that is connected via the Erlang distribution can execute any code on any other connected node.
Similar topic context: Why is `net_kernel:hidden_connect_node/1` undocumented?