一个能登录两台 VPN 节点中任意一台的账户,早在成为软件问题之前就是设计问题。账户视图、每个节点自有的网络,以及已连接客户端持有的会话,是三种不同的状态,把它们四处复制时会以不同方式失效。把三者都复制进同一套系统,是丢掉其中之一的常见做法。

按顺序走过下面三本账。每一本都会问:什么是权威的、什么是本地的、另一个节点消失时会发生什么,而这些答案并不能互相推出。

谁能连接:一个权威,多个节点

从准入这本账开始:哪个身份源是权威的、信任哪些证书颁发者、哪些账户有资格、适用哪种第二因素,以及每个账户能到达哪里。然后写下每个节点如何得知变更,以及多快得知。

共享数据库只是那个答案的一种可能组件。它不能证明所有相关策略都住在那里,也不能证明每个节点都在同一刻应用变更。账户在节点 A 上已被禁用、在节点 B 上却仍被接受,意味着离职流程没有走完。

决定权威不可达时节点该怎么做。故障期间接受缓存凭据,是有安全代价的策略选择;拒绝它们,是有可用性代价的策略选择。两者都站得住脚;不写文档则站不住脚。

也要把颁发者权威与账户数据分开。多个网关可以信任同一个 CA 却不持有它的签名密钥,而每个节点仍然需要自己的服务器证书和自己的客户端侧信任关系。

节点拥有什么:地址与路由

第二本账是每个节点本地的:监听地址、服务器身份、地址池、通往私有资源的路径、解析器策略,以及流量如何离开去往互联网。同一个账户可以由任何一个节点提供服务,而这些对象保持各自独立。

回程路径是最容易被忘掉的部分。如果两个节点都从同一个地址池发地址,私有网络就无法判断某个客户端属于哪个节点,回应可能被发到错误的地方。不同的地址池同样需要路径和权限,所以仅仅区分号段并不是完整设计。

要有意识地把客户端导向某个节点。DNS 选择、客户端端点列表和前端服务是不同机制,健康检查和故障切换行为也不同。选其中一种没问题;把“负载均衡”当作设计本身,就会让回程路径和故障行为悬空。

一个有文档的产品例子在这里有帮助。Pritunl 的复制文档把 VPN 网络当作每个副本各自的对象,不同副本上的客户端需要额外的路径和连通性才能互相到达。那是产品特有的安排,不是 Community OpenVPN 的配方,但它说明了为什么增加一个副本会改变网络,而不只是改变账户存储。

会话是什么:活的状态,不是一行记录

第三本账是实时会话。已连接的客户端在接受它的那个节点上有协议状态和网络分配。账户在另一个节点上已知,并不会给那个节点会话、密钥或继续转发报文的能力。

要明确节点故障时会发生什么。受支持的结果可能是用新的认证和新的地址重新连接到另一个节点,之后应用按自己的方式恢复。如果要求不中断交接,这个要求需要明确的实现支持,而不是从数据库复制推断出来。把答案写在值班工程师能找到的地方。

容量规则也需要同样的处理。每个账户两个并发会话的上限,只有在某个权威对已占用位置有一致视图时,才能跨节点执行。节点本地列表和历史账户记录加起来并不构成那个视图。

检验三本账

每一项都分开演练。先经节点 A 登录,再经节点 B 登录,确认两者都能用预期的地址段成功。撤销一个身份,然后检查两个节点,而不只是碰巧测过的那个。再停掉一个节点,观察客户端和私有应用实际会做什么。

把回程路径也放进验收测试。一个能连上 B、却收不到 A 后面资源回应的客户端,通过了准入检查却没过网络检查,这个区别应该出现在报告里。

只有当三本账都有明确的所有者、变更路径和故障行为时,多节点账户设计才算完整。把配置文件在节点之间复制,回答不了其中任何一个问题。

相关文章