原文地址:http://www.kernel-panic.it/openbsd/carp/index.html
感谢原作者的辛勤劳动。
译文仅供在JR社区学习讨论之用,谢绝修改、转发,多谢!
[email="leo@jr"]leo@jr[/email]
1. 介绍
防火墙是网络里最关键的部分, 因此一旦它们失效可能导致整组的机器都出故障。破坏的范围可能从你无法管理自己公众服务器 (web, mail等) 到外部世界无法访问你的web站点!
使用防火墙集群可以显著地降低这样的风险, 某台防火墙已经失效对用户来说是完全透明的。而且, 当存在一台备份机器时,也可以让维护工作 (打补丁, 升级, 重新启动...) 变得更轻松和快捷, 从而间接地提升了系统的安全性和可靠性。
另一方面, 冗余确实需要花费了更多的设备投资,而且也无法解决所有的问题,像系统之间特定协议 (例如SSH或者IRC)的透明传输、或者同步集群内的机器 (事实上, 我们会用两种不同的协议完成故障转移和数据同步)。
我们用的构建故障转移集群的工具是:
OpenBSD
[INDENT]绝大多数人认为最安全的操作系统之一, 在很长的时间内OpenBSD默认安装后只发现过“两个远程漏洞”!”;
[/INDENT]Packet Filter (PF)
[INDENT]OpenBSD系统自带的工具,用来过滤TCP/IP通讯和进行网络地址转换;
[/INDENT]CARP (通用地址冗余协议)
[INDENT]这个协议可以通过用多台计算机组成一个虚拟网络接口来实现系统冗余;
[/INDENT]pfsync
[INDENT]这个协议允许在多台防火墙之间同步PF的状态表。
[/INDENT]这里假设你已经熟知OpenBSD和PF, 因为我们不会解释太多的PF如何维护和其语法。 不过, 附录里包含的一些有用的链接可以帮助你了解这些知识。
用OpenBSD组建冗余的防火墙, CARP和pfsync
2. 网络布局
2. 网络布局
首先, 看一下防火墙的工作环境。这是一个非常简单和 "典型" 网络, 有以下几部分组成:
这种拓扑结构最大的好处是需要两组防火墙, 它允许我们考虑两组略有不同集群配置,开玩笑了,:D; 它的主要长处是:
首先, 看一下防火墙的工作环境。这是一个非常简单和 "典型" 网络, 有以下几部分组成:
- 一个DMZ (172.16.240.0/24), 包含了从Internet可以访问的机器(例如 web 和mail服务器) 和入侵检测传感器;
- 一个LAN (172.16.0.0/24), 包含了客户端以及无法从Internet上访问的服务器 (file server, DHCP server, internal DNS server...);
- 一个路由器, 在一个小的子网内 (172.16.250.0/24), 连接到通过Internet的网络。
这种拓扑结构最大的好处是需要两组防火墙, 它允许我们考虑两组略有不同集群配置,开玩笑了,:D; 它的主要长处是:
- 一组防火墙有问题时, LAN还受到另一层过滤的保护 (尽管最好使用不同的防火墙平台, 这样可以防止使用同样的技术再次攻击内部防火墙 [MISC17]);
- 单独的防火墙(集群的), 即过滤LAN也过滤DMZ通讯, 其本身就是一个故障点;
- 在每组防火墙上的过滤规则仅应用于LAN或者DMZ通讯, 这样可以使PF规则清晰和容易维护;
- 除了其本身的通讯外, DMZ还必须承受从内部网络到Ineternet的网络流量;
- 双层过滤使LAN通讯提升了安全,不过也 (稍许) 影响一些性能;
- 额外的硬件投入也不容忽视。
3. 基本配置
3. 基本配置
我们简要介绍一下基本系统配置, 这将应用到防火墙上。
我们不涉及操作系统的安装, 更多的信息请参考 OpenBSD FAQ 中文版。唯一的 (很显然) 要求是你应该只安装一个最基本的系统, 这样防火墙的安全性和可靠性不会被其它不需要的软件破坏。因此, 在安装过程中你只需选择那些文档中标记为 必需的 那些组件, 也就是:
在首次重新启动后, 我们就可以设置一些配置文件了; OpenBSD默认仅通过inetd(8)开启了少量的服务:
尽管开启了这些服务,但是系统还是被认为是安全的 (参考[ABSO]); 不过, 禁用它们也没有什么害处。
编辑 /etc/motd 文件,尽量减少系统和警告信息也是不错的办法, 无法是否合法,所有的访问信息将被记录及追究 (参 [PUIS]).
你应该在安装时已经配置好了网络; 不过, 如果你需要一些修正, 下面这些是可能需要修改的文件:
/etc/hostname.if(5)
[INDENT]包含了每个网络接口的配置 (地址, 掩码等);
[/INDENT]/etc/mygate(5)
[INDENT]包含了网关主机的地址;
[/INDENT]/etc/myname(5)
[INDENT]包含了机器的主机名 (FQDN);
[/INDENT]/etc/resolv.conf(5)
[INDENT]包含了解析程序的设置 (域名服务器, 本地域名等).
[/INDENT]考虑到有大量基于DNS的攻击, 不依赖DNS来解析关键系统的域名和地址也是很好的方案,尤其是对防火墙来说,我们应该将这些关键的系统放到文件 /etc/hosts(5) 里。要确保 /etc/hosts(5) 文件比DNS有更高的优先权, 你只需保证 /etc/resolv.conf(5) 文件的第一行是:
文件 /etc/resolv.conf
系统默认已经启用了,而且从默认的配置文件 /etc/pf.conf(5) 里读取了规则; 如果你想使用不同的配置文件,可以在 /etc/rc.conf.local(8)文件里设置pf_rules变量。
文件 /etc/rc.conf.local
你也可以通过变量pflogd_flags设置 pflogd(8) 选项。最后, 被忘了通过下面的命令启用IP转发:
然后注释掉 /etc/sysctl.conf(5) 里的下列行使系统在重新启动后仍旧有效:
文件 /etc/sysctl.conf
我们简要介绍一下基本系统配置, 这将应用到防火墙上。
我们不涉及操作系统的安装, 更多的信息请参考 OpenBSD FAQ 中文版。唯一的 (很显然) 要求是你应该只安装一个最基本的系统, 这样防火墙的安全性和可靠性不会被其它不需要的软件破坏。因此, 在安装过程中你只需选择那些文档中标记为 必需的 那些组件, 也就是:
- bsd, the kernel;
- baseXX.tgz, the base system;
- etcXX.tgz, the configuration files in /etc.
在首次重新启动后, 我们就可以设置一些配置文件了; OpenBSD默认仅通过inetd(8)开启了少量的服务:
代码: 全选
$ grep -v ^# /etc/inetd.conf
ident stream tcp nowait _identd /usr/libexec/identd identd -el
ident stream tcp6 nowait _identd /usr/libexec/identd identd -el
127.0.0.1:comsat dgram udp wait root /usr/libexec/comsat comsat
[::1]:comsat dgram udp6 wait root /usr/libexec/comsat comsat
daytime stream tcp nowait root internal
daytime stream tcp6 nowait root internal
time stream tcp nowait root internal
time stream tcp6 nowait root internal
$
编辑 /etc/motd 文件,尽量减少系统和警告信息也是不错的办法, 无法是否合法,所有的访问信息将被记录及追究 (参 [PUIS]).
你应该在安装时已经配置好了网络; 不过, 如果你需要一些修正, 下面这些是可能需要修改的文件:
/etc/hostname.if(5)
[INDENT]包含了每个网络接口的配置 (地址, 掩码等);
[/INDENT]/etc/mygate(5)
[INDENT]包含了网关主机的地址;
[/INDENT]/etc/myname(5)
[INDENT]包含了机器的主机名 (FQDN);
[/INDENT]/etc/resolv.conf(5)
[INDENT]包含了解析程序的设置 (域名服务器, 本地域名等).
[/INDENT]考虑到有大量基于DNS的攻击, 不依赖DNS来解析关键系统的域名和地址也是很好的方案,尤其是对防火墙来说,我们应该将这些关键的系统放到文件 /etc/hosts(5) 里。要确保 /etc/hosts(5) 文件比DNS有更高的优先权, 你只需保证 /etc/resolv.conf(5) 文件的第一行是:
文件 /etc/resolv.conf
代码: 全选
lookup file bind
文件 /etc/rc.conf.local
代码: 全选
pf_rules=/new/path/to/pf.conf
代码: 全选
# sysctl net.inet.ip.forwarding=1
net.inet.ip.forwarding: 0 -> 1
#
文件 /etc/sysctl.conf
代码: 全选
net.inet.ip.forwarding=1
4. CARP 协议
4. CARP 协议
CARP (通用地址冗余协议) 是一个实现系统冗余的协议, 它的原理是让处于同一网段的一组主机(冗余组)共享一个IP地址, 这样在其中某台主机出现故障时,冗余组内的另一台主机可以马上接替它的工作。CARP还允许在系统间有一定程度的 负载共享 。尽管CARP最广泛的用处之一是创建冗余的防火墙, 但是CARP并非是仅能应用在防火墙上的协议。它还可以用来确保服务的连续性和/或网络服务的负载均衡。
起初, OpenBSD团队想推出一款免费的IETF标准协议, VRRP (Virtual Router Redundancy Protocol), 定义在 [RFC3768], 和 HSRP (Hot Standby Router Protocol), 定义在 [RFC2281]; 但是Cisco宣称对它们拥有专利权, 并且严正地通知OpenBSD社区Cisco将捍卫自己的VRRP专利 (参 [CARP] 以获取更多的细节), 因此这就强迫OpenBSD开发者开发出了一个完全不同的、全新的、与VRRP竞争的协议。CARP是一个组播协议, 把几台物理计算机组合在一起,使用一个或几个虚拟地址。当然一个系统充当主力机并负责处理所有前往该(冗余)组的数据包; 其它系统(备份) 仅处于备用状态, 等着主力机一旦出现任何问题就取代其位置 (就像工作搭档一样...)。
在可配置的间隔周期内, 主力机在IP protocol number 112上广告它自己正常工作。 如果主力机出故障了, 冗余组内的其他主机将会开始广告。广告最频繁的主机就会成为主力机。当原主力机的故障解除后, 尽管可以尝试通过配置让它回来后仍旧是主力机,但是默认情况下它回来后会变成备用机 。
如你所见, CARP只创建和管理虚拟网络接口; 系统管理员可以选择用pfsync(4) (我们将在后面讨论), rsync 或者不管什么协议同步组内的数据。
4.1 配置参数
CARP配置可以通过 sysctl(8) 和 ifconfig(8) 命令完成。有三个 sysctl(3) 相关的变量:
net.inet.carp.allow
[INDENT]定义了该主机是否处理CARP数据包。默认处理;
[/INDENT]net.inet.carp.log
[INDENT]定义了是否记录CARP错误。有效范围是0~7, 与 syslog(3) 的优先权一致, 默认值是2 (也就是只记录CARP状态变化);
[/INDENT]net.inet.carp.preempt
[INDENT]如果设置为0 (默认), 当接收到其它主力机的广告后,这台主机不会尝试成为主力机。否则, 如果它的广告频率高于目前的主力机,它会尝试成为主力机。启用这个选项后,则会在一个接口出现故障时由其它接口接替其工作。事实上, 如果一个启用了CARP的物理接口出现故障, CARP会将所有该接口所属组的demotion counter加上1 (看下面) , 这样会允许在所有子网段选出新的主力机。
[/INDENT]用 ifconfig(8) 配置CARP的语法是:
carpN
[INDENT]carp(4) 虚拟接口的名称。
[/INDENT]advbase, advskew
[INDENT]这些值决定两个CARP广告之间的时间间隔。间隔(以秒计)由公式(advbase + (advskew / 255)) 计算出来; 加大advbase (默认是1秒) 会减少网络通信,但是会推迟选举出新的主力机。更小的advskew值使主机广告的更频繁, 增加了其成为主力机的可能性。advbase的值必须在1到255之间, advskew值在0(默认值)和254之间;
[/INDENT]balancing
[INDENT]设置负载均衡模式 (我们将在后面讨论); 有效的模式是 arp, ip, ip-stealth 和 ip-unicast;
[/INDENT]carpnodes
[INDENT]用逗号分隔的一份vhid名单:advskew对实际上定义了在配置的CARP节点上如何均衡负载(参看 below 以获取更多的信息);
[/INDENT]carpdev
[INDENT]指定属于此冗余组的物理接口。默认情况下, CARP使用处于同一子网的物理接口作为虚拟接口;
[/INDENT]carppeer
[INDENT]允许你指定其它的CARP对的IP地址, 而不是使用默认的组播组;
[/INDENT]pass
[INDENT]与冗余组内其它启用了CARP的主机通讯时使用的密码。在所有成员的设置里这个密码必须是一致的;
[/INDENT]state
[INDENT]强制一个 carp(4) 接口进入一个指定的状态 (init, backup or master);
[/INDENT]vhid
[INDENT]虚拟主机ID。这是一个唯一的数值 (范围是1到255) ,用来分辨冗余组和网络上的其它节点。
[/INDENT]4.1.1 The demotion counter
除了基本的配置以外, 以还可以利用 ifconfig(8) 命令来调整CARP的demotion counter, 它用来衡量冗余组内的某台主机是否更胜任主力机的工作 (数值越高则说明准备越不足).我们看一起细节。
CARP接口以组划分 (默认所有的 carp(4) 接口都属于 "carp" 接口组的成员) 且每个组分配到一个demotion counter, 这个值可以通过下面的命令查到:
demotion counter可提供方便地提供以下功能:
4.1.2 负载均衡
CARP用两种不同的方法完成CARP的主机间进站通讯的负载均衡: ARP balancing 和 IP balancing.
这两种方法都需要你先建立一个负载均衡组, 方法是对均衡组内的每台主机上的 carp(4) 接口进行设置; 每个VHID上的 advskew 都需要配置以便每台主机都可能成为一个独立的WHID的主力机 (请参阅下面的实例)。
ARP balancing的工作原理是将一个哈希函数应用到发送ARP请求的源MAC地址来来验证哪个VHID应该处理这个请求。这个ARP请求将由该VHID里 carp(4) 接口是主力的那台主机来回应。要启用ARP负载均衡可以通过使用 ifconfig(8) 命令在所有的主机上将balancing 选项设置为 "arp" 来实现; 例如:
IP负载均衡的工作原理和ARP负载均衡很类似, 但是,它是使用IP数据包的源地址和目标地址的哈希来验证哪个 VHID (和因而哪台主机) 应该接受这个数据包。
IP均衡需要到达CARP的地址的这个通讯被所有CARP主机接收。要启用IP负载均衡可以通过使用 ifconfig(8)命令将balancing选项设置为 "ip" 来实现; 这会导致CARP使用一个组播MAC地址, 强制交换机把进站通讯发送到冗余组内的所有节点上。例如:
或者, 你也可以将balancing选项设置为 "ip-stealth" (stealth模式), 这样可以防止主机以它们的虚拟MAC地址作为源来发送数据包; 这会防止交换机知道这个虚拟的MAC地址, 强迫其发送这个数据包到其所有的端口。最后, 如果你使用一个提供某些监视模式的集线器(hub)或者交换机(switch), 你可以将balancing设置为"ip-unicast"。
两种负载均衡方式的选择和取舍取决于系统网络环境: ARP均衡只能为本地网络的客户端工作,并不能跨越路由器实现通讯均衡, 因为路由的通讯总是将路由器的MAC地址作为其源地址。因此, 如果客户端在远程网络上, IP均衡是唯一的选择; IP均衡的唯一缺陷是发送到负载均衡的IP地址的那些通讯会被所有启用CARP的主机接收, 这回导致很大的网络负载。
4.2 参数配置
现在是在防火墙上配置CARP的时候了。为了试验两个略有不同的CARP配置, 我们将两个内部的防火墙 (Mickey和Minnie, 在LAN和DMZ之间) 设置为 active/stand-by 模式, 这种模式下只有一个系统过滤整个网络的通讯,另一个处于热备份状态; 两台外部的防火墙 (Donald和Daisy, 分开DMZ和internet)的工作模式则为 active/active 模式, 均衡负载。
我们瞄一眼防火墙地址, 就像我们在 network diagram 中已经看过的那样:
[table] |Mickey|Minnie|Virtual address
LAN|172.16.0.200|172.16.0.201|172.16.0.202
DMZ|172.16.240.200|172.16.240.201|172.16.240.202
pfsync|192.168.2.200|192.168.2.201|[/table]
[table] |Donald|Daisy|Virtual address
DMZ|172.16.240.100|172.16.240.101|172.16.240.102
Internet|172.16.250.100|172.16.250.101|172.16.250.102
pfsync |192.168.1.100|192.168.1.101|[/table]
4.2.1 Active/standby 配置
我们先从Mickey和Minnie开始: 首先, 我们需要创建 carp* 设备,然后用ifconfig(8) 配置它们:
我们创建了接口、分配了一个IP地址、一个虚拟主机ID (LAN是1, DMZ是2) 以及一个用于认证的密码 (也许这个密码不太安全...) 。 我们决定, 只要可能,无论何时Mickey都充当主力机; 这可以通过给Minnie设置一个高一些的 advskew 值(100)来实现,这样Minnie的广告间隔 (1 + 100 / 255) 高于Mickey的广告间隔 (1 + 0 / 255)。结果正像我们 前面 看到的, 广告最频繁的那台主机可以成为主力机。
而且, 通过在Mickey上将 net.inet.carp.preempt 设置为 "1" , 我们确保了Mickey会总是尝试成为主力机:
要使上面的设置重新启动系统后永久有效, 我们只需要编辑Mickey上的 /etc/hostname.carp* 和 /etc/sysctl.conf 文件:
文件 /etc/hostname.carp0
文件 /etc/hostname.carp1
文件 /etc/sysctl.conf
而在Minnie:
文件 /etc/hostname.carp0
文件 /etc/hostname.carp1
注意: 为了使CARP可以简单地应用到已经存在的网络上, CARP允许使用一台主机的物理地址作为整个冗余组的虚拟地址。
4.2.2 Active/active 配置
现在我们设置Donald和Daisy,先从其所在的DMZ接口开始。和从前一样, 我们将在每台机器上创建carp0设备, 不过这次, 为了确保负载均衡, 我们将使用 carpnodes 选项来指定两个不同的虚拟主机ID给接口 (VHIDs 3 和 4).
在VHID 3, 我们分别将Donald和Daisy的 advskew 设置为0和100: 这将确保 Donald成为i这个VHID的主力机; 而在VHID 4, 正好相反, 我们分别将Donald和Daisy的 advskew 设置为100和0, 这样是为了强制Daisy成为VHID4的主力机:
我们现在有两个带有同一IP地址的冗余组, 但是每个冗余组的主力机不同:
要确保重新启动后设置仍有效, 我们需要编辑Donald的启动文件:
文件 /etc/hostname.carp0
文件 /etc/sysctl.conf
and Daisy:
文件 /etc/hostname.carp0
文件 /etc/sysctl.conf
现在我们将在外部的网络接口上做同样的工作,也就是针对另两个Virtual Host IDs (VHIDs 5 and 6):
然后编辑Donald上的启动文件:
文件/etc/hostname.carp1
然后是Daisy:
文件 /etc/hostname.carp1
尽管上面的配置仅包含了几台机器, 不过它可以轻易地扩展到32台主机。 最后的注意事项: 负载均衡不可能在两台主机间实现理想的 50/50 负载均摊, 因为CARP使用一个源和目标IP地址的哈希来决定哪个系统接收此数据包, 而不是根据系统的实际负载。
CARP (通用地址冗余协议) 是一个实现系统冗余的协议, 它的原理是让处于同一网段的一组主机(冗余组)共享一个IP地址, 这样在其中某台主机出现故障时,冗余组内的另一台主机可以马上接替它的工作。CARP还允许在系统间有一定程度的 负载共享 。尽管CARP最广泛的用处之一是创建冗余的防火墙, 但是CARP并非是仅能应用在防火墙上的协议。它还可以用来确保服务的连续性和/或网络服务的负载均衡。
起初, OpenBSD团队想推出一款免费的IETF标准协议, VRRP (Virtual Router Redundancy Protocol), 定义在 [RFC3768], 和 HSRP (Hot Standby Router Protocol), 定义在 [RFC2281]; 但是Cisco宣称对它们拥有专利权, 并且严正地通知OpenBSD社区Cisco将捍卫自己的VRRP专利 (参 [CARP] 以获取更多的细节), 因此这就强迫OpenBSD开发者开发出了一个完全不同的、全新的、与VRRP竞争的协议。CARP是一个组播协议, 把几台物理计算机组合在一起,使用一个或几个虚拟地址。当然一个系统充当主力机并负责处理所有前往该(冗余)组的数据包; 其它系统(备份) 仅处于备用状态, 等着主力机一旦出现任何问题就取代其位置 (就像工作搭档一样...)。
在可配置的间隔周期内, 主力机在IP protocol number 112上广告它自己正常工作。 如果主力机出故障了, 冗余组内的其他主机将会开始广告。广告最频繁的主机就会成为主力机。当原主力机的故障解除后, 尽管可以尝试通过配置让它回来后仍旧是主力机,但是默认情况下它回来后会变成备用机 。
如你所见, CARP只创建和管理虚拟网络接口; 系统管理员可以选择用pfsync(4) (我们将在后面讨论), rsync 或者不管什么协议同步组内的数据。
4.1 配置参数
CARP配置可以通过 sysctl(8) 和 ifconfig(8) 命令完成。有三个 sysctl(3) 相关的变量:
net.inet.carp.allow
[INDENT]定义了该主机是否处理CARP数据包。默认处理;
[/INDENT]net.inet.carp.log
[INDENT]定义了是否记录CARP错误。有效范围是0~7, 与 syslog(3) 的优先权一致, 默认值是2 (也就是只记录CARP状态变化);
[/INDENT]net.inet.carp.preempt
[INDENT]如果设置为0 (默认), 当接收到其它主力机的广告后,这台主机不会尝试成为主力机。否则, 如果它的广告频率高于目前的主力机,它会尝试成为主力机。启用这个选项后,则会在一个接口出现故障时由其它接口接替其工作。事实上, 如果一个启用了CARP的物理接口出现故障, CARP会将所有该接口所属组的demotion counter加上1 (看下面) , 这样会允许在所有子网段选出新的主力机。
[/INDENT]用 ifconfig(8) 配置CARP的语法是:
代码: 全选
ifconfig carpN create
ifconfig carpN [advbase n] [advskew n] [balancing mode] \
[carpnodes vhid:advskew,vhid:advskew,...] [carpdev iface] \
[[-]carppeer peer_address] [pass passphrase] [state state] [vhid host-id]
[INDENT]carp(4) 虚拟接口的名称。
[/INDENT]advbase, advskew
[INDENT]这些值决定两个CARP广告之间的时间间隔。间隔(以秒计)由公式(advbase + (advskew / 255)) 计算出来; 加大advbase (默认是1秒) 会减少网络通信,但是会推迟选举出新的主力机。更小的advskew值使主机广告的更频繁, 增加了其成为主力机的可能性。advbase的值必须在1到255之间, advskew值在0(默认值)和254之间;
[/INDENT]balancing
[INDENT]设置负载均衡模式 (我们将在后面讨论); 有效的模式是 arp, ip, ip-stealth 和 ip-unicast;
[/INDENT]carpnodes
[INDENT]用逗号分隔的一份vhid名单:advskew对实际上定义了在配置的CARP节点上如何均衡负载(参看 below 以获取更多的信息);
[/INDENT]carpdev
[INDENT]指定属于此冗余组的物理接口。默认情况下, CARP使用处于同一子网的物理接口作为虚拟接口;
[/INDENT]carppeer
[INDENT]允许你指定其它的CARP对的IP地址, 而不是使用默认的组播组;
[/INDENT]pass
[INDENT]与冗余组内其它启用了CARP的主机通讯时使用的密码。在所有成员的设置里这个密码必须是一致的;
[/INDENT]state
[INDENT]强制一个 carp(4) 接口进入一个指定的状态 (init, backup or master);
[/INDENT]vhid
[INDENT]虚拟主机ID。这是一个唯一的数值 (范围是1到255) ,用来分辨冗余组和网络上的其它节点。
[/INDENT]4.1.1 The demotion counter
除了基本的配置以外, 以还可以利用 ifconfig(8) 命令来调整CARP的demotion counter, 它用来衡量冗余组内的某台主机是否更胜任主力机的工作 (数值越高则说明准备越不足).我们看一起细节。
CARP接口以组划分 (默认所有的 carp(4) 接口都属于 "carp" 接口组的成员) 且每个组分配到一个demotion counter, 这个值可以通过下面的命令查到:
代码: 全选
$ ifconfig -g carp
carp: carp demote count 0
demotion counter可提供方便地提供以下功能:
- 你想临时防止一台主机成为主力机: 例如, 系统重新启动后在启用网络以前, rc(8) 脚本会将 demotion counter数值在原来的基础上加上128,而在所有接口初始化完毕和启动后,再将这个数值在目前的基础上减掉 (demotion counter 不能被设置为一个绝对值, 而只能通过增加或减少其数值来控制):
- 文件/etc/rc
代码: 全选
ifconfig -g carp carpdemote 128 [ ... ] ifconfig -g carp -carpdemote 128
- 你只想在一台主机的几个 carp(4) 接口(不是所有的, 因为这发生在一个接口出现故障而且已经启用了preempt)完成平滑的故障切换。下例中, 我们将故障切换设置到carp1和carp2接口,而对其它接口不做修改:
代码: 全选
# ifconfig carp1 group morituri # ifconfig carp2 group morituri # ifconfig morituri carp1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 carp: MASTER carpdev sis0 vhid 1 advbase 1 advskew 100 groups: carp morituri inet 1.2.3.4 netmask 0xffffff00 broadcast 1.2.3.255 carp2: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 carp: MASTER carpdev sis1 vhid 2 advbase 1 advskew 100 groups: carp morituri inet 2.3.4.5 netmask 0xffffff00 broadcast 2.3.4.255 # ifconfig -g morituri morituri: carp demote count 0 # ifconfig -g morituri carpdemote 50 # ifconfig -g morituri morituri: carp demote count 50
4.1.2 负载均衡
CARP用两种不同的方法完成CARP的主机间进站通讯的负载均衡: ARP balancing 和 IP balancing.
这两种方法都需要你先建立一个负载均衡组, 方法是对均衡组内的每台主机上的 carp(4) 接口进行设置; 每个VHID上的 advskew 都需要配置以便每台主机都可能成为一个独立的WHID的主力机 (请参阅下面的实例)。
ARP balancing的工作原理是将一个哈希函数应用到发送ARP请求的源MAC地址来来验证哪个VHID应该处理这个请求。这个ARP请求将由该VHID里 carp(4) 接口是主力的那台主机来回应。要启用ARP负载均衡可以通过使用 ifconfig(8) 命令在所有的主机上将balancing 选项设置为 "arp" 来实现; 例如:
代码: 全选
# ifconfig carp0 balancing arp carpnodes 1:0,2:100
IP均衡需要到达CARP的地址的这个通讯被所有CARP主机接收。要启用IP负载均衡可以通过使用 ifconfig(8)命令将balancing选项设置为 "ip" 来实现; 这会导致CARP使用一个组播MAC地址, 强制交换机把进站通讯发送到冗余组内的所有节点上。例如:
代码: 全选
# ifconfig carp0 balancing ip carpnodes 1:0,2:100
两种负载均衡方式的选择和取舍取决于系统网络环境: ARP均衡只能为本地网络的客户端工作,并不能跨越路由器实现通讯均衡, 因为路由的通讯总是将路由器的MAC地址作为其源地址。因此, 如果客户端在远程网络上, IP均衡是唯一的选择; IP均衡的唯一缺陷是发送到负载均衡的IP地址的那些通讯会被所有启用CARP的主机接收, 这回导致很大的网络负载。
4.2 参数配置
现在是在防火墙上配置CARP的时候了。为了试验两个略有不同的CARP配置, 我们将两个内部的防火墙 (Mickey和Minnie, 在LAN和DMZ之间) 设置为 active/stand-by 模式, 这种模式下只有一个系统过滤整个网络的通讯,另一个处于热备份状态; 两台外部的防火墙 (Donald和Daisy, 分开DMZ和internet)的工作模式则为 active/active 模式, 均衡负载。
我们瞄一眼防火墙地址, 就像我们在 network diagram 中已经看过的那样:
[table] |Mickey|Minnie|Virtual address
LAN|172.16.0.200|172.16.0.201|172.16.0.202
DMZ|172.16.240.200|172.16.240.201|172.16.240.202
pfsync|192.168.2.200|192.168.2.201|[/table]
[table] |Donald|Daisy|Virtual address
DMZ|172.16.240.100|172.16.240.101|172.16.240.102
Internet|172.16.250.100|172.16.250.101|172.16.250.102
pfsync |192.168.1.100|192.168.1.101|[/table]
4.2.1 Active/standby 配置
我们先从Mickey和Minnie开始: 首先, 我们需要创建 carp* 设备,然后用ifconfig(8) 配置它们:
代码: 全选
mickey# ifconfig carp0 172.16.0.202/24 vhid 1 pass password1 advbase 1 advskew 0mickey
# ifconfig carp1 172.16.240.202/24 vhid 2 pass password2 advbase 1 advskew 0
代码: 全选
minnie# ifconfig carp0 172.16.0.202/24 vhid 1 pass password1 advbase 1 advskew 100minnie# ifconfig carp1 172.16.240.202/24 vhid 2 pass password2 advbase 1 advskew 100
而且, 通过在Mickey上将 net.inet.carp.preempt 设置为 "1" , 我们确保了Mickey会总是尝试成为主力机:
代码: 全选
mickey# sysctl net.inet.carp.preempt=1
net.inet.carp.preempt: 0 -> 1
文件 /etc/hostname.carp0
代码: 全选
inet 172.16.0.202 255.255.255.0 172.16.0.255 vhid 1 pass password1 advbase 1 advskew 0
代码: 全选
inet 172.16.240.202 255.255.255.0 172.16.240.255 vhid 2 pass password2 advbase 1 advskew 0
代码: 全选
[...]
net.inet.carp.preempt=1
文件 /etc/hostname.carp0
代码: 全选
inet 172.16.0.202 255.255.255.0 172.16.0.255 vhid 1 pass password1 advbase 1 advskew 100
代码: 全选
inet 172.16.240.202 255.255.255.0 172.16.240.255 vhid 2 pass password2 advbase 1 advskew 100
4.2.2 Active/active 配置
现在我们设置Donald和Daisy,先从其所在的DMZ接口开始。和从前一样, 我们将在每台机器上创建carp0设备, 不过这次, 为了确保负载均衡, 我们将使用 carpnodes 选项来指定两个不同的虚拟主机ID给接口 (VHIDs 3 和 4).
在VHID 3, 我们分别将Donald和Daisy的 advskew 设置为0和100: 这将确保 Donald成为i这个VHID的主力机; 而在VHID 4, 正好相反, 我们分别将Donald和Daisy的 advskew 设置为100和0, 这样是为了强制Daisy成为VHID4的主力机:
代码: 全选
donald# ifconfig carp0 172.16.240.102/24 balancing ip carpnodes 3:0,4:100 \
> pass password3
donald# sysctl net.inet.carp.preempt=1
net.inet.carp.preempt: 0 -> 1
代码: 全选
daisy# ifconfig carp0 172.16.240.102/24 balancing ip carpnodes 3:100,4:0 \
> pass password3
daisy# sysctl net.inet.carp.preempt=1
net.inet.carp.preempt: 0 -> 1
我们现在有两个带有同一IP地址的冗余组, 但是每个冗余组的主力机不同:
代码: 全选
donald# ifconfig carp0
carp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
lladdr 01:00:5e:00:01:01
carp: carpdev rl1 advbase 1 balancing ip
state MASTER vhid 3 advskew 0
state BACKUP vhid 4 advskew 100
groups: carp
inet 172.16.240.102 netmask 0xffffff00 broadcast 172.16.240.255
inet6 fe80::2c0:a8ff:fe8e:b112%carp0 prefixlen 64 scopeid 0x5
代码: 全选
daisy# ifconfig carp0
carp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
lladdr 01:00:5e:00:01:01
carp: carpdev rl1 advbase 1 balancing ip
state BACKUP vhid 3 advskew 100
state MASTER vhid 4 advskew 0
groups: carp
inet 172.16.240.102 netmask 0xffffff00 broadcast 172.16.240.255
inet6 fe80::219:d2ff:fe02:6469%carp0 prefixlen 64 scopeid 0x5
文件 /etc/hostname.carp0
代码: 全选
inet 172.16.240.102 255.255.255.0 172.16.240.255 balancing ip carpnodes 3:0,4:100 pass password3
代码: 全选
[...]
net.inet.carp.preempt=1
文件 /etc/hostname.carp0
代码: 全选
inet 172.16.240.102 255.255.255.0 172.16.240.255 balancing ip carpnodes 3:100,4:0 pass password3
代码: 全选
[...]
net.inet.carp.preempt=1
代码: 全选
donald# ifconfig carp1 172.16.250.102/24 balancing ip carpnodes 5:0,6:100 \
> pass password5
代码: 全选
daisy# ifconfig carp1 172.16.250.102/24 balancing ip carpnodes 5:100,6:0 \
> pass password5
文件/etc/hostname.carp1
代码: 全选
inet 172.16.250.102 255.255.255.0 172.16.250.255 balancing ip carpnodes 5:0,6:100 pass password5
文件 /etc/hostname.carp1
代码: 全选
inet 172.16.250.102 255.255.255.0 172.16.250.255 balancing ip carpnodes 5:100,6:0 pass password5
尽管上面的配置仅包含了几台机器, 不过它可以轻易地扩展到32台主机。 最后的注意事项: 负载均衡不可能在两台主机间实现理想的 50/50 负载均摊, 因为CARP使用一个源和目标IP地址的哈希来决定哪个系统接收此数据包, 而不是根据系统的实际负载。
5. pfsync 协议
5. pfsync 协议
Pfsync是 Packet Filter 用来管理和更新状态表的协议, 状态表可以应用于状态话检测和NAT。默认情况下, 可以使用IP组播数据包将状态变化信息发送到同步化的接口上。 这个协议属于IP protocol 240,而使用的组播组是224.0.0.240。我们将使用它在同一个冗余组同步状态表, 并且在发生故障转移(failover,这里也可以理解为故障切换)时, 可以不中断地让一个新的主力防火墙来处理网络通讯。
pfsync(4) 也是PF状态表变化传递中的一个伪设备(pseudo-device)的名字 (除非状态由标注的关键字是"no-sync"的规则创建,或者由 pfsync(4) 数据包创建)。 为了整合多个防火墙上的状态表,可以用一个物理的同步化接口来配置 pfsync(4) 。
可以通过 ifconfig(8) 加上 syncdev 参数来设置物理的同步化接口; 例如, 在我的防火墙上, 我们可以这样写:
这里假设 rl2 接口在每台主机上 (看 图), 这个接口在子网 192.168.1.0/24 上 (用于Mickey和Minnie) 或者 192.168.2.0/24 (用于Donald和Daisy) 以及交叉电缆的 "beloved" 防火墙上。
之所以推荐交叉电缆是因为 pfsync 协议不提供任何的加密和认证机制; 如果你没有使用一个安全的网络, 例如交叉电缆的, 那么一个攻击者可以通过伪造pfsync数据包来改变状态表,从而绕过防火墙规则。
或者你可以通知使用关键字 syncpeer 来指定要同步的防火墙地址。这个系统将使用这个地址, 而不是组播, 因为pfsync(4)信息的目的地可以使用 IPsec 来保护通讯。在这种情况下, syncdev 必须设置成 enc(4) 伪设备(pseudo-device), 这个伪设备可以封装/解封 ipsec(4) 通讯,例如:To make these settings permanent after reboot, we need to edit the /etc/hostname.pfsync0 file on each firewall:
文件 /etc/hostname.pfsync0
(leo: 呵呵,这里读者自行斟酌吧)
Pfsync是 Packet Filter 用来管理和更新状态表的协议, 状态表可以应用于状态话检测和NAT。默认情况下, 可以使用IP组播数据包将状态变化信息发送到同步化的接口上。 这个协议属于IP protocol 240,而使用的组播组是224.0.0.240。我们将使用它在同一个冗余组同步状态表, 并且在发生故障转移(failover,这里也可以理解为故障切换)时, 可以不中断地让一个新的主力防火墙来处理网络通讯。
pfsync(4) 也是PF状态表变化传递中的一个伪设备(pseudo-device)的名字 (除非状态由标注的关键字是"no-sync"的规则创建,或者由 pfsync(4) 数据包创建)。 为了整合多个防火墙上的状态表,可以用一个物理的同步化接口来配置 pfsync(4) 。
可以通过 ifconfig(8) 加上 syncdev 参数来设置物理的同步化接口; 例如, 在我的防火墙上, 我们可以这样写:
代码: 全选
# ifconfig pfsync0 syncdev rl2
之所以推荐交叉电缆是因为 pfsync 协议不提供任何的加密和认证机制; 如果你没有使用一个安全的网络, 例如交叉电缆的, 那么一个攻击者可以通过伪造pfsync数据包来改变状态表,从而绕过防火墙规则。
或者你可以通知使用关键字 syncpeer 来指定要同步的防火墙地址。这个系统将使用这个地址, 而不是组播, 因为pfsync(4)信息的目的地可以使用 IPsec 来保护通讯。在这种情况下, syncdev 必须设置成 enc(4) 伪设备(pseudo-device), 这个伪设备可以封装/解封 ipsec(4) 通讯,例如:
代码: 全选
# ifconfig pfsync0 syncpeer 192.168.1.101 syncdev enc0
文件 /etc/hostname.pfsync0
代码: 全选
up syncdev rl2
PF规则
6. PF规则!
CARP和pfsync给PF规则上造成的影响微乎其微。首先, 你需要允许PFSYNC和CARP 协议通过它们的接口:
然后是编写防火墙规则, 别忘了,从 pf(4)的视角看, 所有通讯通过物理接口。因此这种情况下:
你可以仍旧指定物理接口而不是虚拟接口。
另一方面, 虚拟地址是关系到CARP接口的; 因此, 如果防火墙在其虚拟地址上提供任何服务,你都需要设置一下:
或者在一个NAT后面的服务器上, 重定向所有通讯:
在所有其它的情况下, CARP对 pf(4) 来说都是透明的, 因为防火墙在其物理地址上提供服务:
作为一个例子, 我们看一下外部防火墙的基本的PF规则, Donald和Daisy:
文件 /etc/pf.conf
CARP和pfsync给PF规则上造成的影响微乎其微。首先, 你需要允许PFSYNC和CARP 协议通过它们的接口:
代码: 全选
pass quick on rl2 proto pfsync keep state (no-sync)
pass on { rl0, rl1 } proto carp keep state (no-sync)
代码: 全选
pass in on $ext_if [...]
另一方面, 虚拟地址是关系到CARP接口的; 因此, 如果防火墙在其虚拟地址上提供任何服务,你都需要设置一下:
代码: 全选
# SSH on the virtual interface
pass in on $int_if inet proto tcp from $int_if:network to carp0 port ssh
代码: 全选
# Mail server accessible from the internet
pass in on $ext_if inet proto tcp from any to carp2 port $mail_ports rdr-to $mail_srv
代码: 全选
# SSH on the physical address
pass in on $int_if inet proto tcp from $int_if:network to $int_if port ssh/CODE]
或者对正常过滤来说:
[CODE]# External DNS
pass in on $int_if inet proto { tcp, udp } from $int_if:network to $dns_srv \
port domain
pass out on $ext_if inet proto { tcp, udp } from $ext_if to $dns_srv \
port domain
文件 /etc/pf.conf
代码: 全选
################################################################################
# Macros and lists #
################################################################################
ext_if = rl0 # External interface
int_if = rl1 # DMZ interface
pfs_if = rl2 # Pfsync interface
carp_if = carp1 # External CARP interface
mail_srv = "mail.kernel-panic.it" # Mail server
web_srv = "{ www1.kernel-panic.it, www2.kernel-panic.it }" # Web servers
dns_srv = "{ dns1.isp.com, dns2.isp.com }" # DNS servers
int_fw = "{ mickey.kernel-panic.it, minnie.kernel-panic.it }" # Internal fw
mail_ports = "{ smtp, imap, imaps }" # Mail server ports
web_ports = "{ www, https }" # Web server ports
# Allowed incoming ICMP types
icmp_types = "{ echoreq, timex, paramprob, unreach code needfrag }"
# Private networks (RFC 1918)
priv_nets = "{ 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 }"
################################################################################
# Options, scrub and NAT #
################################################################################
set block-policy drop
set loginterface $ext_if
set skip on lo
# NAT outgoing connections
match out on $ext_if from !$ext_if to any nat-to $ext_if
# Redirect web services (with load balancing)
match in on $ext_if inet proto tcp from any to $carp_if port $web_ports \
rdr-to $web_srv round-robin sticky-address
# Redirect mail services
match in on $ext_if inet proto tcp from any to $carp_if port $mail_ports \
rdr-to $mail_srv
################################################################################
# Filtering rules #
################################################################################
block all # Default deny
block in quick from urpf-failed # Spoofed address protection
# Scrub incoming packets
match in all scrub (no-df)
pass quick on $pfs_if proto pfsync keep state (no-sync) # Enable pfsync
pass on { $int_if, $ext_if } proto carp keep state (no-sync) # Enable CARP
block in quick on $ext_if from $priv_nets to any
block out quick on $ext_if from any to $priv_nets
# Mail server
pass in on $ext_if inet proto tcp from any to $mail_srv port $mail_ports
pass out on $int_if inet proto tcp from any to $mail_srv port $mail_ports
pass in on $int_if inet proto tcp from $mail_srv to any port smtp
pass out on $ext_if inet proto tcp from $ext_if to any port smtp modulate state
# Web servers
pass in on $ext_if inet proto tcp from any to $web_srv port $web_ports \
synproxy state
pass out on $int_if inet proto tcp from any to $web_srv port $web_ports
# ICMP
pass in inet proto icmp all icmp-type $icmp_types
pass out inet proto icmp all
# DNS
pass in on $int_if inet proto { tcp, udp } from $int_if:network to $dns_srv \
port domain
pass out on $ext_if inet proto { tcp, udp } from $ext_if to $dns_srv \
port domain
# Internet web servers
pass in on $int_if inet proto tcp from $int_fw to any port $web_ports
pass out on $ext_if inet proto tcp from $ext_if to any port $web_ports \
modulate state
回复: Redundant firewalls with OpenBSD, CARP and pfsync
7. Appendix
7.1 References
7.1 References
- [MISC17] - Filtrage applicatif : le cas des clients web, mail et p2p (MISC Nº17)
- [PUIS] - Practical UNIX and Internet Security, Simson Garfinkel and Gene Spafford, O'Reilly, 2003
- [ABSO] - Absolute OpenBSD, Michael W. Lucas, No Starch Press, 2003
- [CARP] - "CARP License" and "Redundancy must be free"
- [PFFAQ] - PF: The OpenBSD Packet Filter
- [RFC3768] - RFC 3768, Virtual Router Redundancy Protocol (VRRP)
- [RFC2281] - RFC 2281, Cisco Hot Standby Router Protocol (HSRP)
- The Common Address redundancy Protocol (CARP)
- Firewall Failover with pfsync and CARP
- Firewalling with OpenBSD's PF packet filter, Peter N. M. Hansteen, 2008
- The Book of PF, 2nd Edition, Peter N. M. Hansteen, No Starch Press, 2010
- The OpenBSD PF Packet Filter Book, Jeremy C. Reed, Reed Media Services, 2006
在线用户
正浏览此版面之用户: 没有注册用户 和 2 访客