单机版本的WAF还难以承载大规模的业务,即使业务规模不大时,单机版本的WAF在高可用性上也不太好。下面介绍如何搭建分布式架构的WAF,解决性能和高可用的问题。
如图2-12所示,分布式WAF集群主要包括:四层负载均衡、WAF服务、WAF日志处理、WAF配置管理,每个部分均支持集群部署,快速横向扩展。
从基础网络安全的角度讲,应该严格限制直接使用公网IP对外提供服务的形式,因为直接使用公网IP提供服务,攻击面会非常大且不可控。应该把只有经过测试的服务才使用负载均衡的方式对外发布Web服务,其他服务除非必要,都不直接对外发布,这样可以严格控制黑客的攻击面。四层负载的主要作用是:
·四层负载均衡,将用户请求转发给后端WAF服务;
·将后端的WAF服务以公网IP的形式发布出去;
·最好具备一定的抗四层攻击的能力。
图2-12 分布式WAF集群架构
常见的开源解决方案当属LVS。LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统,支持VS-NAT、VS-TUN、VS-DR三种模式:
VS-NAT,如图2-13所示,就是把客户端发来的数据包的IP头的目的地址,在负载均衡器上换成其中一台RS的IP地址,并发至此RS来处理,RS处理完成后把数据交给负载均衡器,负载均衡器再把数据包的源IP地址改为自己的IP,将目的地址改为客户端IP地址即可?期间,无论是进来的流量,还是出去的流量,都必须经过负载均衡器?
VS-TUN,如图2-14所示,把客户端发来的数据包,封装一个新的IP头标记(仅目的IP)发给RS,RS收到后,先把数据包的头解开,还原数据包,处理后,直接返回给客户端,不需要再经过负载均衡器?注意,由于RS需要对负载均衡器发过来的数据包进行还原,所以说必须支持IPTUNNEL协议?所以,在RS的内核中,必须编译支持IPTUNNEL这个选项。
图2-13 VS-NAT网络拓扑
图2-14 VS-TUN网络拓扑
VS-DR,如图2-15所示,负载均衡器和RS都使用同一个IP对外服务,由于负载均衡器要对二层包头进行改换,所以负载均衡器和RS之间必须在一个广播域,也可以简单地理解为在同一台交换机上?
图2-15 VS-DR网络拓扑
由于我们仅希望LVS暴露在公网,后端WAF和Web服务的部署不要有太多物理机柜网段限制,推荐使用VS-NAT模式,虽然全部请求和应答都会过LVS,LVS可能会成为整个系统的瓶颈,但是实际经验是LVS性能足够好,单机性能瓶颈往往是网卡,万兆网卡打满的情况下CPU还有余力。
以图2-16为例,在LVS上配置如下:
/sbin/ipvsadm -C /sbin/ipvsadm -a -t 201.114.5.36:80 -r 192.168.1.100:80 -m -w 1 /sbin/ipvsadm -a -t 201.114.5.36:80 -r 192.168.1.101:80 -m -w 1 /sbin/ipvsadm
图2-16 LVS网络拓扑示例
注意,两台LVS之间可以用VRRP虚拟出VIP,起到高可用的效果。所谓VRRP即虚拟路由器冗余协议,是一种选择协议,它可以把一个虚拟路由器的责任动态分配到局域网上的VRRP路由器中的一台。控制虚拟路由器IP地址的VRRP路由器称为主路由器,它负责转发数据包到这些虚拟IP地址。一旦主路由器不可用,这种选择过程就提供了动态的故障转移机制,这就允许虚拟路由器的IP地址可以作为终端主机的默认第一跳路由器。使用VRRP的好处是有更高的默认路径的可用性,而无需在每个终端主机上配置动态路由或路由发现协议。VRRP包封装在IP包中发送 。更多生产环境的优化请自行补充。
WAF服务与单机版WAF相同,不再赘述。
配置管理其实是整个系统最容易被忽略,但是事实上是非常重要的一个环节。
配置同步最常见的方式有两种:推、拉。推模式最容易实现,但是在大型分布式系统里面无法保证时效性;拉模式性能差。能否兼顾这两种方式呢?
ZooKeeper(简称ZK)是一个开源的分布式应用程序协调服务,是Hadoop和HBase的重要组件。如图2-17所示,它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。ZooKeeper在分布式系统的配置管理方面应用非常广泛。ZooKeeper支持发布订阅模式,该模式可以看成一对多的关系:多个订阅者对象同时监听一个主题对象,这个主题对象在自身状态发生变化时,会通知所有的订阅者对象,使他们能够自动地更新自己的状态。发布订阅模式,可以让发布方和订阅方,独立封装,独立改变,当一个对象的改变需要同时改变其他的对象,而且它不知道有多少个对象需要改变时,可以使用发布订阅模式。
图2-17 ZooKeeper架构(图片来自ZooKeeper官网 )
在最简化设计时,我们可以让每台WAF的配置完全一样,这样的好处是可以随时添加服务器,任何一个服务器宕机都不会影响WAF服务,而且整个系统的架构会非常简洁。每台WAF只要使用Python脚本订阅ZooKeeper中的配置,一旦发生变更,获取最新配置,更新相关配置文件,给Nginx发送信号热加载新配置文件即可。
ZooKeeper的安装使用非常简单,如图2-18所示,在官网下载,解压就可以了。
图2-18 ZooKeeper官网
编辑配置文件conf/zoo.cfg:
tickTime=2000 dataDir=/var/lib/zookeeper clientPort=2181
启动服务:
bin/zkServer.sh start
建议至少使用三个ZooKeeper实例(如图2-19所示),而且分布在不同服务器上,可以和WAF混合部署,因为ZooKeeper对性能消耗很小:
tickTime=2000 dataDir=/var/lib/zookeeper clientPort=2181 initLimit=5 syncLimit=2 server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888
图2-19 基于ZooKeeper的
核心Python伪码为:
#创建zookeeper节点 >>> zookeeper.create(zk,"/zk_waf_rule") #获取节点信息 >>> zookeeper.get(zk,"/zk_waf_rule") #定义一个监听器,订阅配置 >>> def myWatch(zk,type,state,path): ... print "zk:",str(type),str(state),str(path) ... zookeeper.get(zk,path,myWatch) ... >>> data=zookeeper.get(zk,"/zk_waf_rule",myWatch)
日志处理也是基于流行的storm做实时流式处理,基于Spark做离线分析,基于HDFS做离线存储,如图2-20所示。
图2-20 WAF日志处理架构
如果有实时检索原始日志的需求,可以引入Elasticsearch。这部分最基础的功能包括:
·统计实时拦截报表;
·统计实时访问PV/UV;
·离线分析小时/天/周/月的PV/UV;
·离线分析小时/天/周/月的拦截报表;
·离线保存原始日志。
加分功能是:
·运行HMM分析漏报;
·运行语义分析漏报。
日志处理部分会在第9章展开,这里不赘述了。
·WAF上线前至少要保证核心业务在测试环境中经过测试,线上环境初次使用时只检测不阻断;
·WAF的规则要定期更新,好比杀毒软件的病毒库,不更新的话,其功能就打折扣了。