记一次LVS/Nginx环境下的访问控制

赞助

如果你觉得我写得还行,欢迎付费支持。

偶然间,我发现 Graphite 显示服务器网卡流量呈锯齿状,于是查了一下 Nginx 日志,发现有人在周期性抓我们的接口数据。我这爆脾气自然不能容忍这种行径。

简单分析一下访问日志,很容易就能拿到了可疑的 IP 段,直接用 iptables 封杀:

shell> iptables -A INPUT -s x.y.z.0/24 -j DROP

本以为世界会就此清净,可没想到一点儿用都没有。莫非小偷已经突破锁头的限制?不能够啊!直觉告诉我问题应该和 LVS 有关,可惜我对 LVS 的了解极其匮乏,唯一知道的线索就是项目用的是 FULLNAT 模式,那就以此为切入点开始挖掘:

LVS FULLNAT

LVS FULLNAT

所谓 FULLNAT 模式,是指当用户请求经由 LVS 转发给 RS 服务器的时候,其来源 IP 会从用户 IP 改成 LVS 内网 IP,目标 IP 会从 LVS 的 VIP 改成 RS 服务器的 IP;当 RS 服务器生成响应数据经由 LVS 返回给用户的时候,其来源 IP 会从 RS 服务器 IP 改成 LVS 的 VIP,目标 IP 会从 LVS 内网 IP 改成用户 IP。

说明:关于 LVS 更详细的介绍请参考「从一个开发的角度看负载均衡和LVS」一文。

对于 RS 服务器而言,实际上它看到的是 LVS。可我们明明在 Nginx 日志里看到了客户端的 IP,而不是 LVS 的 IP,这又是什么原因呢?原来 LVS 为了解决 FULLNAT 模式下传递用户 IP 的问题,引入了一个名为 TOA 的补丁机制,在 TCP 的三次握手阶段,通过 TCP 的 options 来传递用户 IP 和端口等信息,继而覆盖 socket 的 IP 和端口数据。

换句话说,在 RS 服务器上,从 iptables 的角度看,因为 NAT 的缘故,来源 IP 都是 LVS 的 IP;而从 Nginx 的角度看,因为 TOA 的缘故,来源 IP 都是用户的 IP。关于这一点也可以通过 tcpdump 命令抓包来印证:

tcpdump

tcpdump

说明:如上图所示那一堆 254 开头的字符串里保存的就是用户 IP 和端口等信息。

于是乎可以得出结论:在 RS 服务器上通过 iptables 来封杀用户 IP 无疑是没有意义的,实际情况是我无权操作 LVS 服务器,只能在 RS 服务器上想办法。既然 Nginx 能拿到用户 IP,那么我们就可以在 Nginx 上解决问题,有 AccessGEO 等模块可供选择,这里我们选择的是 GEO 模块:

geo $bad {
    default 0;
    x.y.z.0/24 1;
}

location / {
    if ($bad) {
        return 403;
    }
}

关于 GEO 模块的例子,有一些不错的资料可供参考,这里我就不多说了。

记一次LVS/Nginx环境下的访问控制》上有6条评论

    • Access 模块太简单了,无法实现一些复杂的判断,所以我选择使用 GEO 模块,具体案例可以参考我文章后面给出的参考资料链接。

  1. Pingback引用通告: 技术晨读_2015_2_6 | 一世浮华一场空

  2. 通过iptables匹配字符串功能,应该可以

    iptables -I INPUT 1 -p tcp –dport 80 -m string –algo bm –string ‘254 开头的字符串’ -j DROP
    手头没环境测试

发表评论

电子邮件地址不会被公开。 必填项已用*标注