erlang的epmd指定端口范围验证及端口权限配置
1,简介
erlang的原理与linux系统非常像,有进程的概念,有进程调度等。今天要验证的就是类似于DNS的功能:epmd。epmd是Erlang Port Mapper Daemon的缩写,用于Erlang集群中的节点互通。比如在ip1上面启动了一个节点 nodeA@ip1,在ip2上面启动了一个节点nodeB@ip2,如果nodeA要访问nodeB,那么首先会去connect nodeB节点上的epmd服务的端口:4369 端口,他会告诉nodeA,nodeB@ip2是在哪个端口,然后nodeA直接connect该端口,与nodeB进行通信。如果nodeB想要与nodeA通信,由于nodeA已经于nodeB建立了链路,那么直接使用该链路进行通信,否则也要像nodeA一样,先访问nodeA的4369端口,获取nodeA的监听端口,然后访问该端口。关于epmd的原理和使用,有很多写的很好的文章,比如[Erlang 0123] Erlang EPMD,Erlang epmd的角色以及使用,建议读者可以先看一下这篇文章:[Erlang 0123] Erlang EPMD,本文只是单纯的验证-kernel inet_dist_listen_min PortMin inet_dist_listen_max PortMax的正确性,然后讲解一下遇到的防火墙配置问题,最后总结一下在生产环境应该如何开通访问权限。因为生产环境遵循最小权限的原则,所以需要对端口权限控制的非常精准。在如rabbitmq、couchbase这样的erlang应用中都会用到。
2,结论
我们先说一下结论:
首先在192.168.3.142机器上面启动一个节点'test142@192.168.3.142',然后在另外一台机器192.168.3.140上面启动一个节点'test140@192.168.3.140',上面部署了一个使用erlang代码编写的web监控程序,需要监控节点'test142@192.168.3.142'的运行情况。此时就需要这两个节点之间能够连通。显然局域网中是很容易实现的,没有太多的端口限制。但是如果'test142@192.168.3.142'是部署在生产环境内的局域网,'test140@192.168.3.140'是部署在DMZ区,他们之间的访问就涉及到端口权限的开通。首先需要140申请访问142的epmd-4369端口,这样才能查到test142节点的监听端口。(为保障生产环境的安全,除非必要,一般不会反向开通142到140的4369端口。)然后142的4369端口会告诉140,节点'test142@192.168.3.142'监听的端口,通常这是一个随机端口。这样140还需要再申请到142的随机端口的访问,这显然是不现实的。所以erlang提供了一个解决办法:固定test142节点的监听范围,而不让他变成随机端口。
erl -kernel inet_dist_listen_min 44000 inet_dist_listen_max 44002 -name test142@192.168.3.142 -setcookie test
在192.168.3.142机器上面执行该命令,设置该节点启动之后,监听的端口为44000,如果44000被占用,那么监听44001,如果依然被占用,那么监听44002,如果还被占用,那么报错。这样140只需要开通到142上44000~44002的端口权限就可以了。所以申请的端口列表是:
src:192.168.3.140 to:192.168.3.142 port:4369
src:192.168.3.140 to:192.168.3.142 port:44000
src:192.168.3.140 to:192.168.3.142 port:44001
src:192.168.3.140 to:192.168.3.142 port:44002
那么从'test140@192.168.3.140'访问'test142@192.168.3.142'的链路是通的,但是从'test142@192.168.3.142'到'test140@192.168.3.140'的链路是否也通呢?如果你在142机器上面执行
net_adm:ping('test140@192.168.3.140').
得到的结果是"pang",也就是不通。难道必须开通反向的从142到140的端口吗?其实不用,我们先在140机器上面执行
net_adm:ping('test142@192.168.3.142').
得到的结果是"pong",这是正常的,因为我们已经开通了从140到142的4369和44000的权限。此时再去142机器上执行net_adm:ping('test140@192.168.3.140'). 会发现得到的结果是"pong",居然通了!我们不需要再开通反向的端口权限就解决了这个问题。这样能最大限度的减少端口的开通。所以在生产环境中我们只需要开通上面4个端口权限即可。
到这里结论已经出来了,如果读者愿意继续看,下面是我的验证过程,涉及到防火墙的配置,如果没兴趣,到这里就可以结束了。
3,验证过程
192.168.3.140和192.168.3.142都是我的Centos虚拟机。为了将192.168.3.142模拟成生产环境,我将142机器上面的所有端口都屏蔽:
- iptables -P INPUT DROP
- iptables -P FORWARD DROP
- iptables -P OUTPUT DROP
关于iptables 防火墙的操作,大家可以参考这个:linux IPtable防火墙 禁止和开放端口,讲得非常详细。如果iptables命令不可用,出现类似于这样的错误
The service command supports only basic LSB actions (start, stop, restart, try-restart, reload, force-reload, status). For other actions, please try to use systemctl.
或者出现异常,可以参考这个解决:关于centos 7 中service iptables save 指令使用失败的结局方案 。如果读者是在xshell这样的ssh软件里面执行上面的操作,那么执行到中途就会发现ssh连接断开了,因为ssh的22号端口已经被防火墙屏蔽了,所以建议大家直接在虚拟机中执行上面三条命令。然后,为了方便输入,我们可以打开22号端口,输入以下命令:
- iptables -A INPUT -p tcp --dport 22 -j ACCEPT
- iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
第一条准入命令,表示允许其他机器准入,协议是tcp,目的端口是22,注意这个是单向的,即只允许其他机器向142的22端口发送数据,但是不允许22端口回复数据,所以此时ssh其实还是不可用,我们还需要加上下面那一条,允许准出:允许本机从22端口发出tcp数据包。这样我们就可以使用xshell这样的软件方便使用了。
- 首先允许140访问142的4369端口,执行如下命令:
-
- iptables -A INPUT -p tcp -s 192.168.3.140 --dport 4369 -j ACCEPT
- iptables -A OUTPUT -p tcp -d 192.168.3.140 --sport 4369 -j ACCEPT
第一条是准入命令:允许源ip地址为192.168.3.140的机器,向本机的4369端口发送tcp的数据包,同样这也是单向的,所以必须加上第二条准出命令:允许本机的4369端口先目的ip地址为192.168.3.140的机器发送tcp数据包,这样才能保证顺畅的访问4369端口。此时在140机器上面telnet 142 的4369 端口是通的。
- 由于我们不知道将来142节点启动之后会是44000~44002中的哪一个(因为其中的端口有可能被其他应用程序占用),所以正常情况下我们会开通44000~44002之间的所有端口
-
- iptables -A INPUT -p tcp -s 192.168.3.140 --dport 44000 -j ACCEPT
- iptables -A OUTPUT -p tcp -d 192.168.3.140 --sport 44000 -j ACCEPT
- iptables -A INPUT -p tcp -s 192.168.3.140 --dport 44001 -j ACCEPT
- iptables -A OUTPUT -p tcp -d 192.168.3.140 --sport 44001 -j ACCEPT
- iptables -A INPUT -p tcp -s 192.168.3.140 --dport 44002 -j ACCEPT
- iptables -A OUTPUT -p tcp -d 192.168.3.140 --sport 44002 -j ACCEPT
- 此时我们尝试在142机器上面启动test142节点:
erl -kernel inet_dist_listen_min 44000 inet_dist_listen_max 44002 -name test142@192.168.3.142 -setcookie test
你会惊讶的发现启动不了,命令一直卡在那里不动,什么原因呢?因为142机器上面的端口权限,只开通了上面几个,其他所有的端口都是禁止的,包括142访问142自己的端口,也同样是禁止的,无法访问!erlang在启动的时候,需要访问本地的端口的,所以应该允许142机器拥有访问本身的权限:
- iptables -A INPUT -s 127.0.0.1 -j ACCEPT
- iptables -A OUTPUT -d 127.0.0.1 -j ACCEPT
同样,也是两条命令,一条准入,一条准出,一条都不能少。按照理解,第一条准入命令与第二条准出命令是等价的,好像只有一条就可以。但是我试过删除第二条准出命令,只留下第一条准入命令,依然是卡在那里不动,所以两条命令一条都不能少。在142上面执行
-
iptables -L -n
查看一下当前的防火墙配置,可以看到如下的防火墙规则:
-
执行如下命令查看本机当前的所有erlang节点所监听的端口
-
epmd -names
可以看到"name test142 at port 44000"的提示,说明test142节点已经监听在了44000端口
-
在142机器的erl界面里执行ping 命令用以测试是否与140节点连通,可以看到结果为"pang",是通不了的。
-
net_adm:ping('test140@192.168.3.140').
-
然后在140机器上面启动一个erlang节点,
-
erl -name test140@192.168.3.140 -setcookie test
然后测试与142节点是否连通,可以看到结果是"pong",是可以通的
-
此时再在142机器的erl界面里执行ping 命令用以测试是否与140节点连通,可以看到结果为"pong",已经连通,因为上一步test140节点已经建好了一条链路,所以可以连通。
至此,在满足最小端口权限的原则下,已经打通了两个节点之间的通信链路。