Node.connect
to Elixir?I've begun tinkering with distributing Elixir across (for now) two different servers.
For example, let's say the server's two IP addresses are:
First, I added new rules to the iptables firewall on both servers, opening up port 4369 (EPMD) and a range of 10 ports between 9000-9010 for nodes. I'm also only allowing incoming connections from the other server's exact IP address.
Example config for 198.51.100.0:
-A INPUT -p tcp -m state --state NEW --dport 4369 -s 203.0.113.0 -j ACCEPT
-A INPUT -p tcp -m state --state NEW --dport 9000:9010 -s 203.0.113.0 -j ACCEPT
Example config for 203.0.113.0:
-A INPUT -p tcp -m state --state NEW --dport 4369 -s 198.51.100.0 -j ACCEPT
-A INPUT -p tcp -m state --state NEW --dport 9000:9010 -s 198.51.100.0 -j ACCEPT
Now I can open up iex
shells on each machine:
198.51.100.0:
$ iex --name [email protected] --cookie secret --erl '-kernel inet_dist_listen_min 9000' --erl '-kernel inedist_listen_max 9010'
203.0.113.0:
$ iex --name [email protected] --cookie secret --erl '-kernel inet_dist_listen_min 9000' --erl '-kernel inedist_listen_max 9010'
I can successfully connect to node two from node one:
iex([email protected])> Node.connect(:'[email protected]')
true
And list nodes from node two:
iex([email protected])> Node.list
[:"[email protected]"]
I've read that :net_kernel.allow/1
can be used to whitelist an exact list of allowed connections. But I can't seem to get it working:
iex([email protected])> :net_kernel.allow([])
:ok
iex([email protected])> Node.connect(:'[email protected]')
true
I would expect that since I've allowed a list of none, no connection would be allowed. Any tips?
I discovered that if I pass at least one value to :net_kernel.allow
, it seems to work:
iex([email protected])> :net_kernel.allow([:'127.0.0.0'])
:ok
iex([email protected])> Node.connect(:'[email protected]')
false
23:38:27.702 [error] ** Connection attempt with disallowed node :"[email protected]" **
iex([email protected])> :net_kernel.allow([:'[email protected]'])
:ok
iex([email protected])> Node.connect(:'[email protected]')
true
Is that the trick?
Whitelisting is based on the VM Cookie, ~/.erlang.cookie
.
Then only authorized Nodes will be in possession of the good cookie to be able to connect.
For the security part, I've set up a Tinc mesh VPN between my servers and my laptop, and it's all the security I need while providing great flexibility.
net_kernel
is a module that creates a gen_server
process. In that process state it has some parameters such as allowed
which holds a list of allowed nodes and at startup was initiated by an empty list.
There is an undocumented feature that if the given node for connection is not a member of allowed nodes but that list is empty, it lets the node to connect. This code snippet from net_kernel.erl
module says this fact:
setup(Node,Type,From,State) ->
Allowed = State#state.allowed,
case lists:member(Node, Allowed) of
false when Allowed =/= [] ->
error_msg("** Connection attempt with "
"disallowed node ~w ** ~n", [Node]),
{error, bad_node};
_ ->
%% set up connection to given node
end.
Another important note is about net_kernel:allow/1
function which is an append-only function. You can check this fact in its source code when the new nodes are added to previous ones with ++
operator:
handle_call({allow, Nodes}, From, State) ->
case all_atoms(Nodes) of
true ->
Allowed = State#state.allowed,
async_reply({reply,ok,State#state{allowed = Allowed ++ Nodes}},
From);
false ->
async_reply({reply,error,State}, From)
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With