分页: 1 / 1

《18. OpenBSD PF用户指南之附属议题——使用CARP和pfsync构建冗余防火墙》

发表于 : 2010-01-21 10:13
leo
PF: 使用 CARP 和 pfsync 构建冗余防火墙

--------------------------------------------------------------------------------

目录
CARP介绍
CARP操作
CARP配置
CARP范例
pfsync介绍
pfsync操作
pfsync配置
pfsync范例
结合CARP和pfsync完成故障切换和冗余
操作问题
启动时配置CARP和pfsync
强制切换主力机
规则集技巧
其它参考

--------------------------------------------------------------------------------

CARP介绍
CARP是通用地址冗余协议。它的主要目的是允许位于用以网段的多台主机共享一个IP地址。相对于 虚拟路由冗余协议(VRRP) 和 热备份路由协议(HSRP) 来说, CARP是一个安全、自由的替代品。

CARP是通过允许位于同一网段的一组住主机共享一个IP地址, 这个组被称为"冗余组"。冗余组成员间共享一个被分派的IP地址。在组内一台主机被指定为"主力机", 而其余的作为"热备份"。主力机平时"持有"共享IP地址的;它应答所有外来的通讯或ARP请求。一台主机可以同时属于几个冗余组。

CARP常用来构建一组冗余的防火墙。冗余组配置了虚拟IP作为客户端计算机的默认网关, 一旦主力机失效或未连线, 这个IP将移到一台备份的防火墙上, 服务将继续而不会受影响。

CARP 支持 IPv4 和 IPv6.

CARP操作
主力机对本地网络发送定期的公告所以备份机知道它仍在正常工作。如果备份机在一个设定的时间间隔内没有收到公告, 那么它们其中一台会接替主力机的工作(advbase及advskew值设置的最低的那台)。

有可能在同一网段存在多个CARP组, CARP的公告包含了虚拟主机ID, 可以让组成员分辨出公告属于哪个冗余组。

为了防止此网段内的恶意用户发送虚假的CARP公告, 每个组可以被指一个密码, 每个发到该组的CARP数据包会采用SHA1 HMAC加密算法进行保护。

因为CARP采用它自己的协议, 所以需要在过滤规则里添加明确放行规则:

pass out on $carp_dev proto carp keep state
$carp_dev 是CARP通讯经过的物理接口。

CARP配置
每个carp(4) 虚拟网络接口表示一个冗余组。 CARP也使用 ifconfig(8) 来配置。

代码: 全选

ifconfig carpN create
 
ifconfig carpN vhid vhid [pass password]
[carpdev carpdev] \
[advbase advbase] [advskew advskew]
[state state] ipaddress \
netmask mask


carpN
carp(4) 虚拟接口的名称, 这里的 N 是一个整数, 它表示这个虚拟接口的接口号(例如 carp10)。
vhid
虚拟主机ID。这是一个唯一的号码, 用它来区分这个冗余组与网络上的其它节点。有效值从1到255。
password
认证密码。用来与同组的CARP主机通讯。组内所有成员的认证密码吗必须一致。
carpdev
这个可选项指定了一个属于此冗余组的物理网络接口。默认情况下, CARP会在同一网段上寻找一个物理接口提供给carp(4)接口前, 尝试指定使用哪个接口。
advbase
这个可选参数指定了向冗余组内成员公告的频率, 以秒为单位。默认值是1秒, 有效值从1到255。
advskew
这个可选参数指定了发送CARP公告的误差(延迟)。利用 advskew, 可以选择CARP主力机。这个数值越大, 则越不可能被选为主力机。默认值是0, 有效值从0到254。
state
强制一个carp(4)接口进入特定的状态。有效的状态是init, backup, 和 master。
ipaddress
这是分配给冗余组的共享IP地址。这个IP地址不是必须和物理接口(如果存在)处于同一个子网内。然而, 组内的所有主机这个地址必须相同。
mask
共享IP的子网掩码。
CARP的更多行为可以通过 sysctl(8) 来控制。

代码: 全选

net.inet.carp.allow


是或否允许CARP进站数据包。默认值是1 (是).
net.inet.carp.preempt
允许主机在一个更容易抢占主力机位置的冗余组(更好的advbase和advskew)。另外, 如果一个接口出现故障这个选项会在所有的接口上启用故障切换。如果一个启用CARP的物理接口出现故障, CARP将把所有其它启用CARP的接口的advskew调整为240, 其实, 就是切换成自己。这个选项默认是0(未启用)。

代码: 全选

net.inet.carp.log


记录损坏的CARP数据包。默认是0 (未启用)。
net.inet.carp.arpbalance
在多个冗余组主机间通讯负载均衡。默认是0 (未启用)。参参阅 carp(4) 以获得更多的信息。
CARP范例
这里有一个CARP配置的例子:

代码: 全选

# sysctl -w net.inet.carp.allow=1
# ifconfig carp1 create
# ifconfig carp1 vhid 1 pass mekmitasdigoat carpdev em0 \
advskew 100 10.0.0.1 netmask 255.255.255.0


它完成了如下设置:

启用接收CARP数据包 (这是默认设置)。
创建一个carp(4)接口carp1。
为虚拟主机#1配置carp1, 启用一个密码, 将em0设置为属于这个组的接口, 将这台主机设置为热备份, 因为 advskew 设置成了100 (当然, 这里假设主力机的 advskew 值小于100)。指派给这个组的共享IP是10.0.0.1/255.255.255.0.
在carp1上运行ifconfig来显示这个接口的状态。

代码: 全选

ifconfig carp1
carp1: flags=8802<UP, BROADCAST, SIMPLEX, MULTICAST> mtu 1500
carp: BACKUP carpdev em0 vhid 1 advbase 1
advskew 100
groups: carp
inet 10.0.0.1 netmask 0xffffff00 broadcast
10.0.0.255 


pfsync介绍
pfsync(4) 网络接口显示 pf(4) 状态表的确切变化。通过使用 tcpdump(8) 监视这个设备, 状态表的变化可以实时显示。此外, pfsync(4)接口能将这些状态变化信息发到这个网络外面的其它节点上, 上面运行的PF能将这些变化并入自己的状态表内。同样, pfsync(4)也能监听网络上的进站信息。


pfsync操作
默认情况下, pfsync(4)不在网络上发送和接收状态表更新; 然而, 更新仍可在本机计算机上使用tcpdump(8)监视更新。
当pfsync(4)设置好并在网络上发送和接收更新, 默认行为是在本地网络上组播更新, 所有更新的发送不需要认证。通常的最优方法有下面两种:

用一根交叉电缆背靠背的连接两个交换更新的节点, 并用那个接口作为同步设备syncdev(看下面)。
用ifconfig(8)的syncpeer选项(看下面)以便将信息直接单播至对方, 然后在两台主机间配置 ipsec(4) 以保护pfsync(4)的通讯。
当在网络上发送和接收更新时, pfsync的数据包应该被主规则集放行:

代码: 全选

pass on $sync_if proto pfsync


$sync_if 应该是 pfsync(4) 通讯采用的物理接口。


pfsync配置
因为pfsync(4)是一个虚拟网络接口, 所以用 ifconfig(8) 配置:
ifconfig pfsyncN syncdev syncdev [syncpeer syncpeer]
pfsyncN
pfsync(4)接口的名。使用GENERIC内核时pfsync0默认存在。
syncdev
用来发出 pfsync 更新的物理接口名。
syncpeer
这个可选项指定了与之交换 pfsync 更新的对方主机IP地址。默认情况下, 在本地网络上pfsync更新是组播。这个选项调整组播的行为, 将其取代为用单播直接将更新发送到指定的syncpeer 。
pfsync范例
这是一个配置 pfsync 的例子:

代码: 全选

# ifconfig pfsync0 syncdev em1

这是在em1接口上启用pfsync。出站更新将在网络上组播, 允许任何运行pfsync的主机接收它们。


结合CARP和pfsync完成故障切换
通过结合CARP和pfsync的功能, 一组两台以上的防火墙能被用来创建一个高可用性、完全冗余的防火墙集群。
CARP:
负责从一个防火墙到另一个防火墙的故障切换。
pfsync:
负责在所有防火墙之间同步状态表。在故障切换时, 通讯通过经新的主力防火墙而不停顿。
一个例子, 两个防火墙, fw1 和 fw2。

+----| WAN/Internet |----+
| |
em2| |em2
+-----+ +-----+
| fw1 |-em1----------em1-| fw2 |
+-----+ +-----+
em0| |em0
| |
---+-------Shared LAN-------+---

这两个防火墙用一根交叉线背靠背连接在em1。全通过em0连接到LAN;通过em2连接到WAN/Internet。 IP地址如下:

fw1 em0: 172.16.0.1
fw1 em1: 10.10.10.1
fw1 em2: 192.0.2.1
fw2 em0: 172.16.0.2
fw2 em1: 10.10.10.2
fw2 em2: 192.0.2.2
LAN shared IP: 172.16.0.100
WAN/Internet shared IP: 192.0.2.100
网络策略是fw1是首选的主力机。

配置 fw1:

! enable preemption and group interface failover

代码: 全选

# sysctl -w net.inet.carp.preempt=1

! configure pfsync

代码: 全选

# ifconfig em1 10.10.10.1 netmask 255.255.255.0
# ifconfig pfsync0 syncdev em1
# ifconfig pfsync0 up

! configure CARP on the LAN side

代码: 全选

# ifconfig carp1 create
# ifconfig carp1 vhid 1 carpdev em0 pass lanpasswd \
172.16.0.100 netmask 255.255.255.0

! configure CARP on the WAN/Internet side

代码: 全选

# ifconfig carp2 create
# ifconfig carp2 vhid 2 carpdev em2 pass netpasswd \
192.0.2.100 netmask 255.255.255.0


配置 fw2:

! enable preemption and group interface failover

代码: 全选

# sysctl -w net.inet.carp.preempt=1

! configure pfsync

代码: 全选

# ifconfig em1 10.10.10.2 netmask 255.255.255.0
# ifconfig pfsync0 syncdev em1
# ifconfig pfsync0 up

! configure CARP on the LAN side

代码: 全选

# ifconfig carp1 create
# ifconfig carp1 vhid 1 carpdev em0 pass lanpasswd \
advskew 128 172.16.0.100 netmask 255.255.255.0

! configure CARP on the WAN/Internet side

代码: 全选

# ifconfig carp2 create
# ifconfig carp2 vhid 2 carpdev em2 pass netpasswd \
advskew 128 192.0.2.100 netmask 255.255.255.0


操作问题
一些使用 CARP/pfsync 时常见的操作问题。


启动时配置CARP和pfsync
因为 carp(4) 和 pfsync(4) 全是网络接口类型, 可以通过创建一个 hostname.if(5) 文件以便在启动时配置它们。 netstart 启动脚本可以完成创建接口和配置接口的工作。
例如:

/etc/hostname.carp1
inet 172.16.0.100 255.255.255.0 172.16.0.255 vhid 1 carpdev em0 \
pass lanpasswd
/etc/hostname.pfsync0
up syncdev em1
强制切换主力机
这可能发生在故障切换或有目的的降级主力机节点。例如包括为了维护关闭主力机或者发现并处理一个问题。这里的目的是在用户丝毫没有察觉的情况下, 平稳地完成切换。
切换到一个指定的CARP组, 关闭主力节点上的carp(4)接口, 将导致主力机公告:自己带有一个"无限大"的dvbase和advskew。备份机(们)将看见这个公告并立即担任主力机的角色。

代码: 全选

# ifconfig carp1 down


也可以将主力机的advskew值增大到高于备份机的advskew值。这将导致切换但仍允许主力机参与到CARP组中。

另一个故障切换的方法是调整CARP的demotion counter。 demotion counter用来衡量一台备机成为主机的"预备"情况如何, 例如一台启动中的主机不太可能成为CARP主力机, 只能等到所有接口已经配置完毕、所有网络进程已经启动等。那些公告大demotion值的主机成为主力机的机会更小。

demotion counter储存在属于CARP接口的每个接口组中。默认情况下, 所有的CARP接口全是属于"carp"接口组的成员。可以用 ifconfig(8) 查看目前的demotion counter数值:

代码: 全选

# ifconfig -g carp
carp: carp demote count 0


这个例子中显示了与"carp"接口组相关的counter。当一个CARP主机在网络上公告自己时, 它得到所有接口组的demotion counters总和, 它将这个总和作为自己的demotion值公告。

现在假设下面的例子, 两个防火墙运行CARP带有如下的CARP接口:

carp1 -- 财务
carp2 -- 普通职员
carp3 -- Internet
carp4 -- DMZ
目标是故障切换时, 仅将carp1和carp2组切换到第二个防火墙上。

首先, 将它们全部指派到一个新的接口组, 本例中被称为"internal":

代码: 全选

# ifconfig carp1 group internal
# ifconfig carp2 group internal
# ifconfig internal
carp1: flags=8843<UP, BROADCAST, RUNNING, SIMPLEX, MULTICAST> mtu 1500
carp: MASTER carpdev em0 vhid 1 advbase 1 advskew 100
groups: carp internal
inet 10.0.0.1 netmask 0xffffff00 broadcast 10.0.0.255
carp2: flags=8843<UP, BROADCAST, RUNNING, SIMPLEX, MULTICAST> mtu 1500
carp: MASTER carpdev em1 vhid 2 advbase 1 advskew 100
groups: carp internal
inet 10.0.1.1 netmask 0xffffff00 broadcast 10.0.1.255 
现在用 ifconfig(8) 增大 "internal" 组的demotion counter:

代码: 全选

# ifconfig -g internal
internal: carp demote count 0
# ifconfig -g internal carpdemote 50
# ifconfig -g internal
internal: carp demote count 50

这个防火墙在carp1和carp2上被平稳地切换为防火墙集群内的其它防火墙, 但是这个防火墙还是carp3和carp4的主力机。如果那个其它的防火墙开始公告自己有一个高于50的demotion值, 或者完全停止公告, 那么这个防火墙会重新担当carp1和carp2的主力防火墙。

如果则合格防火墙不能返回主力位置, 做相反的变化:

代码: 全选

# ifconfig -g internal -carpdemote 50
# ifconfig -g internal
internal: carp demote count 0

网络进程诸如 OpenBGPD 和 sasyncd(8) 利用demotion counter来确保确保这个防火墙没有变成主力机, 直到建立了BGP会话和IPsec SAs已经被同步。

规则集技巧
过滤物理接口. 至于和PF有关的, 网络通讯来自物理接口, 并非CARP虚拟接口(例如, carp0), 所以, 参照词条编写规则。别忘了在PF规则中一个接口名可以使用物理接口名也可以使用这个接口被分配的IP地址, 例如:下面的规则是正确的:
pass in on fxp0 inet proto tcp from any to carp0 port 22
但是如果用carp0替换fxp0就不会如你所愿正常工作了。
别忘记 放行carp协议和pfsync协议!


其它参考
请参阅这里的其它资源你获得更多的知识:
carp(4)
pfsync(4)
ifconfig(8)
hostname.if(5)
pf.conf(5)
ifstated(8)
ifstated.conf(5)