Elixir 分布式安全和白名单允许节点
Elixir distributed security and whitelisting allowed nodes
TL;DR
- 如何将可以
Node.connect
加入 Elixir 的节点列入白名单?
- 还有其他安全建议吗?
设置
我已经开始尝试在(目前)两个不同的服务器上分发 Elixir。
例如,假设服务器的两个IP地址是:
- 198.51.100.0
- 203.0.113.0
首先,我向 iptables firewall on both servers, opening up port 4369 (EPMD) 添加了新规则,并为节点添加了 9000-9010 之间的 10 个端口范围。我也只允许来自其他服务器的确切 IP 地址的传入连接。
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
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
现在我可以在每台机器上打开 iex
个外壳:
198.51.100.0:
$ iex --name one@198.51.100.0 --cookie secret --erl '-kernel inet_dist_listen_min 9000' --erl '-kernel inedist_listen_max 9010'
203.0.113.0:
$ iex --name two@203.0.113.0 --cookie secret --erl '-kernel inet_dist_listen_min 9000' --erl '-kernel inedist_listen_max 9010'
我可以从节点一成功连接到节点二:
iex(one@198.51.100.0)> Node.connect(:'two@203.0.113.0')
true
并列出来自节点二的节点:
iex(two@203.0.113.0)> Node.list
[:"one@198.51.100.0"]
我的问题:
我读到 :net_kernel.allow/1
可用于将允许连接的确切列表列入白名单。但我似乎无法让它工作:
iex(one@198.51.100.0)> :net_kernel.allow([])
:ok
iex(one@198.51.100.0)> Node.connect(:'two@203.0.113.0')
true
我希望,因为我允许 none 的列表,所以不允许连接。有什么建议吗?
更新:
我发现如果我将至少一个值传递给 :net_kernel.allow
,它似乎有效:
iex(one@198.51.100.0)> :net_kernel.allow([:'127.0.0.0'])
:ok
iex(one@198.51.100.0)> Node.connect(:'two@203.0.113.0')
false
23:38:27.702 [error] ** Connection attempt with disallowed node :"two@203.0.113.0" **
iex(one@198.51.100.0)> :net_kernel.allow([:'two@203.0.113.0'])
:ok
iex(one@198.51.100.0)> Node.connect(:'two@203.0.113.0')
true
这是技巧吗?
白名单基于 VM Cookie,~/.erlang.cookie
。
然后只有授权的节点才能拥有良好的 cookie 才能 connect.
对于安全性部分,我在我的服务器和我的笔记本电脑之间设置了一个 Tinc mesh VPN,这就是我需要的所有安全性,同时提供了极大的灵活性。
net_kernel
是一个创建 gen_server
进程的模块。在该进程状态下,它有一些参数,例如 allowed
,它包含一个允许的节点列表,并且在启动时由一个空列表启动。
有一个未记录的功能,如果给定的连接节点不是允许节点的成员但该列表为空,它允许节点连接。来自 net_kernel.erl
模块的这段代码说明了这个事实:
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.
另一个重要的注意事项是关于 net_kernel:allow/1
函数,它是一个 append-only 函数。当使用 ++
运算符将新节点添加到以前的节点时,您可以在其源代码中检查这一事实:
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;
TL;DR
- 如何将可以
Node.connect
加入 Elixir 的节点列入白名单? - 还有其他安全建议吗?
设置
我已经开始尝试在(目前)两个不同的服务器上分发 Elixir。
例如,假设服务器的两个IP地址是:
- 198.51.100.0
- 203.0.113.0
首先,我向 iptables firewall on both servers, opening up port 4369 (EPMD) 添加了新规则,并为节点添加了 9000-9010 之间的 10 个端口范围。我也只允许来自其他服务器的确切 IP 地址的传入连接。
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
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
现在我可以在每台机器上打开 iex
个外壳:
198.51.100.0:
$ iex --name one@198.51.100.0 --cookie secret --erl '-kernel inet_dist_listen_min 9000' --erl '-kernel inedist_listen_max 9010'
203.0.113.0:
$ iex --name two@203.0.113.0 --cookie secret --erl '-kernel inet_dist_listen_min 9000' --erl '-kernel inedist_listen_max 9010'
我可以从节点一成功连接到节点二:
iex(one@198.51.100.0)> Node.connect(:'two@203.0.113.0')
true
并列出来自节点二的节点:
iex(two@203.0.113.0)> Node.list
[:"one@198.51.100.0"]
我的问题:
我读到 :net_kernel.allow/1
可用于将允许连接的确切列表列入白名单。但我似乎无法让它工作:
iex(one@198.51.100.0)> :net_kernel.allow([])
:ok
iex(one@198.51.100.0)> Node.connect(:'two@203.0.113.0')
true
我希望,因为我允许 none 的列表,所以不允许连接。有什么建议吗?
更新:
我发现如果我将至少一个值传递给 :net_kernel.allow
,它似乎有效:
iex(one@198.51.100.0)> :net_kernel.allow([:'127.0.0.0'])
:ok
iex(one@198.51.100.0)> Node.connect(:'two@203.0.113.0')
false
23:38:27.702 [error] ** Connection attempt with disallowed node :"two@203.0.113.0" **
iex(one@198.51.100.0)> :net_kernel.allow([:'two@203.0.113.0'])
:ok
iex(one@198.51.100.0)> Node.connect(:'two@203.0.113.0')
true
这是技巧吗?
白名单基于 VM Cookie,~/.erlang.cookie
。
然后只有授权的节点才能拥有良好的 cookie 才能 connect.
对于安全性部分,我在我的服务器和我的笔记本电脑之间设置了一个 Tinc mesh VPN,这就是我需要的所有安全性,同时提供了极大的灵活性。
net_kernel
是一个创建 gen_server
进程的模块。在该进程状态下,它有一些参数,例如 allowed
,它包含一个允许的节点列表,并且在启动时由一个空列表启动。
有一个未记录的功能,如果给定的连接节点不是允许节点的成员但该列表为空,它允许节点连接。来自 net_kernel.erl
模块的这段代码说明了这个事实:
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.
另一个重要的注意事项是关于 net_kernel:allow/1
函数,它是一个 append-only 函数。当使用 ++
运算符将新节点添加到以前的节点时,您可以在其源代码中检查这一事实:
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;