首页 存档 技术 查看内容

Erlang通过TLS的分布式

2018-3-30 13:00 |来自: 互联网 308 0

摘要: 什么是Erlang分布式? “分布式协议”的意思是由多个Erlang节点组成的一个集群。当Erlang的节点被组成集群后,任何的进程都可以发送信息去任意节点去执行,并且可以在任意的节点上产生新的进程。 这样就形成了分布式 ...

什么是Erlang分布式?

“分布式协议”的意思是由多个Erlang节点组成的一个集群。当Erlang的节点被组成集群后,任何的进程都可以发送信息去任意节点去执行,并且可以在任意的节点上产生新的进程。 这样就形成了分布式应用的基础,比如Mnesia,数据库的实现分别由Erlang/OTP和消息代理RabbitMQ来进行。

Erlang分布式协议被设计为假定运行在一个可靠的网络。当节点互相联系是需要证明彼此是持有共享密钥的, 称为 "cookie",这样做的主要目的是保证不同的Erlang集群处于同一网络中是不会意外的合并;也不建议依靠cookie机制来防止攻击者。

此外,在一个集群中所有的Erlang节点完全信任彼此。集群中任何节点可以任意的其他节点运行代码,包括运行由os:cmd产生的任意命令。这就是为什么文章the Distribunomicon chapter of Learn You Some Erlang描述的Erlang安全模型时使用了这句话 * this space intentionally left blank *。

在这篇文章内,我将叙述如何通过TLS来进行Erlang分布式协议,以及能够或不能够解决的问题。

为什么是TLS?它能解决什么问题?

比如说在你的数据中心内你已经有了一个Erlang集群,并且你打算升级一下它以支持TLS。(你或许会想使用了TLS意味着你可以在公开的在网络上运行你的Erlang集群,那样的话我想说你是太勇敢了,我很想听听你是经历!)在最简单的可能的配置中,节点之间的通信是加密的,但是节点间并不去验证证书真实性。

这句话是什么意思?它表示当给定两个Erlang节点分别叫做Alice和Bob,如果Eve (一个窃听者)已经加入到你的网络,并且能够监听网络流量,它并不能看到你的两个Erlang节点间发送的内容,也就是你想保护的敏感信息。 这是一个纵深防御的例子:即使攻击者入侵了你的防火墙,在想得到他们想要的东西之前,仍然有很多的障碍。然而,如果另一攻击者Mallory加入到你的网络,他可以通过提供不同的证书来代理不同的节点间的通信,这样就能够执行中间人(MITM)攻击。

验证TLS证书的通常方法是检查它们是否由同一个信任的证书机构签发。这样能够保证Mallory不能够拦截双方的连接,除非他也拥有同一个CA的私钥。然而它依然引出了一个重要的问题:哪一个CA是你信任的? 当任何一个Erlang节点带有一个信任的CA颁发的证书并能访问你的节点的时候,你应该会想要信任尽可能少的CA,或是自己建立单独的CA来签发证书给你集群中的节点,并且只信任自建的那一个。

另一个减少风险的方法是创建信任证书的白名单。此功能并不是开箱即用的,但是你可以通过实现自己的验证功能来做到这一点。

如何使用基于TLS的分布式?

具体内容已经在官方文档中有描述(http://erlang.org/doc/apps/ssl/ssl_distribution.html),因此,这里我将会只给出一些提示和例子以便能够帮助你开始。

首先,由于这里需要输入很多较长的命令行参数到erl,我建议写一个恰当的shell脚本来启动erl,这样你就不需要每次都反复的在终端内鼓捣参数了。

文档写道你需要在你的启动脚本中包含SSL应用或是明确的在代码路径中包含SSL ebin的目录。 最终你可能会想要按照前一种方法来做,使用喜欢的工具直接生成,但是当你尝试后你会选择后一种方法。下面就是保存为正确目录的脚本参数的一个片断:

SSL_DIR=$(erl -noinput -eval 'io:format("~s~n",
  [filename:dirname(code:which(inet_tls_dist))])' -s init stop

这涉及到额外调用Erlang虚拟机,会让启动变的有点慢,但从另一方面来说,你也不再需要担心手动的去查找对应的目录了。

在shell脚本的最后, 使用需要的参数来启动erl:

erl -pa $SSL_DIR -proto_dist inet_tls -ssl_dist_opt $SSL_DIST_OPT "$@"

至于还需要什么样的SSL_DIST_OPT变量呢?这取决于你想要使用什么样的验证。

只加密,不验证

在服务器端你至少需要一个证书和一个私有密钥。“客户端”并不需要提供证书。

注意“服务端”和“客户端” 在Erlang分布式中是外来的专有名词。在Erlang中,当两个节点连接后,它并不关心是哪个节点初始化的连接,但是当使用TLS连接时,我们设置不同的选项给两“边”。

证书和私有密钥会以PEM的格式存储。它们也可以串联成一个文件,在这种情况下你只需要server_certfile选项,或者存储为两个独立的文件,这时你也需要设置server_keyfile:

SSL_DIST_OPT="server_certfile erl-dist.pem server_keyfile erl-dist.key"

在这一步我们并不会去验证证书,因此自签名的证书是有效的。

由CA列表来验证服务器证书

如果你有一组可信任的证书机构,并要求“客户端”验证“服务端”的证书是否由他们签署,可通过选项client_cacertfile实现。 同时需要设置client_verify和verify_peer选项来让客户端执行验证:

SSL_DIST_OPT="server_certfile erl-dist.pem server_keyfile erl-dist.key \
       client_cacertfile ca.pem client_verify verify_peer"

记住客户端也不会提供证书,所以把CA列表放到服务端是没有意义的。

通过CA列表校验客户端证书

不管怎么说,只验证服务端证书,而不验证客户端证书,是有点犯傻的。这是因为,原则上,一个随机节点最终都会链接到另一个节点上,并且两者之间可以互访,而不需要考虑方向(互为C/S)。因此,我们需要为每个节点配置相应的证书、密钥、CA列表等参数,同时通过server_fail_if_no_peer_cert选项,让服务端要求客户端提供证书。

SSL_DIST_OPT="server_certfile  erl-dist.pem client_certfile  erl-dist.pem \
       server_keyfile  erl-dist.key client_keyfile  erl-dist.key \
       server_cacertfile ca.pem    client_cacertfile ca.pem    \
       server_verify   verify_peer client_verify   verify_peer \
       server_fail_if_no_peer_cert true"

使用定制的校验函数(版本19.0)

为了在校验证书时获得更多的灵活性,例如:需要定制日志信息,或者需要实现一个证书白名单,我们需要实现一个定制的校验函数。在Erlang/OTP的19.0版本中,已经支持此功能。我们可以通过“客户端”和“服务端”的verify_fun选项来定义。此选项的使用,在官方的SSL模块文档中有类似的描述(http://erlang.org/doc/man/ssl.html):

SSL_DIST_OPT="server_certfile  erl-dist.pem client_certfile  erl-dist.pem \
       server_keyfile  erl-dist.key client_keyfile  erl-dist.key \
       server_cacertfile ca.pem    client_cacertfile ca.pem    \
       server_verify   verify_peer client_verify   verify_peer \
       server_verify_fun {my_module,my_function,my_state}      \
       client_verify_fun {my_module,my_function,my_state}      \
       server_fail_if_no_peer_cert true"

注意,当一个Erlang程序创建了一个TLS链接时,verify_fun选项是一个有两个元素的元组:一个函数,一个初始化状态术语。然而,从命令行中解析出来的Erlang术语,是无法创建函数对象的。因此,我们传递模块名和函数名用于原子替换,在这种情况下,functionmy_module:my_function/3将被调用。

这个校验回调函数将在多个验证环节中被调用:验证过程遇到错误时(所有错误)、验证未知的证书扩展、验证证书链中每个有效证书。针对每种情况,都要由该函数决定验证是成功或失败。函数还可以用于更新状态数据--元组的第三个元素是初始化状态。一个校验回调函数的实现,类似于下面的代码:

my_function(Cert, valid, State) -
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部