两个客户端组,一台服务器:在哪里执行策略
子网只是给分组贴标签,并不能隔离它们。先确定哪条转发路径拥有规则,再写出实现必须执行的规则矩阵。
把两个客户端组放在不同子网上看起来像隔离,其实不是。地址描述的是数据包表面上来自哪里,而许可是由转发它的组件做出的决定。回答这个问题的是配置而不是掩码,所以在写任何规则之前,先确定由哪个组件转发对等流量。
子网是标签,不是规则
为每个组分一个地址池,只会给你可读的地址,别的什么也没有。接受额外路由的客户端获得了可达性,而可达性不等于授权。通信许可存在于转发决定中,这个决定可能位于守护进程里,也可能位于内核里,取决于服务器的配置方式。
地址归属才让前缀可以作为分组选择器。每个通过认证的身份都必须映射到可预测的地址或范围,而一旦多台设备共用一份凭据和一次分配,这种映射就会失效。在依赖源前缀之前先解决身份与并发问题,因为靠猜测哪台机器在呼叫的策略,会在最糟的时刻给错误的一方授权。
选择承载对等流量的路径
当守护进程在自己的进程内转发对等数据包时,这些数据包永远不会到达主机的转发钩子,因此内核规则看不到它们。关闭这种内部转发,内核就成为转发点,普通转发规则在那里生效。
# peer forwarding inside the daemon: enforce with per-group policy instead of FORWARD rules
client-to-client
# kernel forwarding path: remove the line above, then filter in the forward chain
卸载的数据通道和产品托管的服务器会发布各自的执行模型,所以要确认你运行的是哪一种,而不是假定社区版本的行为。值得避免的失败,是在评审中看起来正确、运行时却从未被查询的规则。
先写矩阵,再写规则
短矩阵比整套规则更容易评审,它也是实现必须满足的契约:同组对等方允许,跨组对等方拒绝,两个组都允许访问某个指定的共享服务,其余一律拒绝。在打开防火墙编辑器之前,先把这四行写下来。不读规则语法的评审者仍然可以检查矩阵。实现随后只需与这些行保持一致。
| Source | Destination | Decision |
|---|---|---|
| Group A address | Another Group A address | Allow |
| Group A address | A Group B address | Deny |
| Either group | The shared internal service | Allow |
| Either group | Anything not listed | Deny |
写的时候把三类目的地分开。VPN 主机上的服务是本地输入,另一台客户端是对等转发,网关后面的机器则是另一条转发路径。一条宽松的规则可能意外地同时授予三者,组策略就这样变成多绕几步的扁平网络。在每一行旁边写上类别,让意图在下次编辑后仍然成立。
把规则放在能存活的地方
在维护防火墙其余部分的同一位置添加这些决定,并放在任何会吞掉它们的放行规则之前。规则顺序是策略的一部分,放在宽泛允许之后的正确规则什么也执行不了。记录修改前后的规则编号。只存在于编辑器、不在运行规则集里的策略只是计划,不是控制。
决定策略变化时已存在的流会怎样,因为变更前打开的会话可能在变更后继续。如果离开的成员必须立即失去访问,规则集需要有办法终止该状态,而不是等连接自行关闭。
通过拥有防火墙其余部分的机制让规则持久化,并在旁边记录矩阵。没有记录的策略会在下一次事件中被人凭记忆重新推导,而且通常是在匆忙之中。
从两侧证明
从每个组的一台客户端测试同组可达性、跨组失败和共享服务。只从一台客户端测一次,只能证明矩阵的一半,而漏掉的那一半通常正是错的那一半。把拒绝方向重复两次,因为缓存会话可能掩盖执行错误。记录你测过哪一对,避免下一个人重复。
如果隧道承载 IPv6,就在同一协议上重复检查,并保留常规的应用层认证。源前缀不是账号,所以通过网络策略并不意味着服务应当信任调用方。