把配置文件复制到平板,连上去,笔记本就掉线了。加上 duplicate-cn,两台都保持连接,问题看似解决,直到两台设备争抢同一个隧道地址,或者丢了一台平板就把整个账号拖下线。这个选项只改变一件事,而且仅此一件:服务器是否允许在同一台已经见过的名字下再开一个会话。人们期待它解决的所有问题——设备独立性、按设备分配地址、选择性吊销——仍然由身份来完成,而这里的身份就是证书。

误区:第二个会话就是第二个身份

直觉上,两条连接就该是两个客户端,两个客户端就该是两台各有权限的设备。服务器不是这样建模的。它看到的是一个公共名;启用 duplicate-cn 后,它接受不止一个携带该名字的活动会话,每个会话在守护进程里各有一份状态。

这种接受与证书校验毫无关系。同一张证书仍然是凭证,同一把密钥仍然是私钥,任何以证书主体为键的策略仍然两次解析到同一个值。第二个会话是第二个套接字,不是第二个身份。

一切正常时这种区别看不出来。一旦需要区分两台设备,它就变得非常明显——而那通常正是其中一台丢失的那天。

两个会话共用一个名字时,真正改变的是什么

没有这个选项时,同一个已连接的公共名下的新连接会把先前的会话顶掉。平板一连上笔记本就掉线,原因就在这里,这是刻意设置的歧义防护,不是缺陷。有了这个选项,两个会话都活着,服务器按会话分别跟踪,而不是按设备。

每个会话仍然有自己的外部连接和自己协商出来的密钥,所以并发吞吐确实是并发的。它们共享的是由凭证派生的一切:策略查找、客户端专属配置、日志身份和吊销。会话状态属于连接,随连接消亡;而凭证层面的事实对两者都成立。正因如此,状态输出可以把同一个名字列两次,而计数器仍然各自独立。

在围绕它做设计之前,先确认你的构建实际做了什么,因为这个选项的效果由选项本身决定,而不是由口耳相传决定:

grep -n 'duplicate-cn\|client-config-dir\|username-as-common-name' /etc/openvpn/server.conf

你以为已经分配了的静态地址

按客户端做的配置是按名字查找的,陷阱就在这里。一个以公共名命名的client-config-dir 文件会作用于所有使用该名字的设备,于是里面的 ifconfig-push 给两台设备发同一个隧道地址。第二个会话要么建不起来,要么以看起来像路由故障的方式发生冲突。

动态地址池反而误打误撞地表现更好,因为每个会话独立地从池中分配地址。但这仍然给不了你按设备固定的地址,更给不了与那个地址绑定的按设备策略。

如果部署使用 username-as-common-name,查找键就变成通过认证的用户名而不是证书主体,任何登录两次的人都会遇到同样的冲突。驱动配置的名字必须按设备唯一,按设备的配置才有意义。

共用身份在移除时做不到的事

吊销作用于证书,既不看显示名,也不看会话。吊销那张证书,所有持有副本的设备立刻失去访问权,包括办公室里那台没人想去打扰的。保留它,丢失的设备就继续能用,因为协议里没有任何东西把它和已批准的副本区分开。

日志继承了同样的模糊。状态输出显示一个公共名和一个真实地址,两者都可能属于任意一台设备。需要弄清哪台机器做了什么的事故复盘,光靠 VPN 自己的记录回答不了,日志级别给再多细节也不行。

这件事没有密码学上的绕行办法。两台出示同一张证书的设备,在服务器眼里就是同一个参与者出现了两次;任何假装不是这样的方案都只是命名约定,而非控制手段。

什么时候共享是对的,以及如何划定边界

共享有正当用途:由多台测试机共用的实验室账号,或者设备统一管理、吊销粒度无关紧要的家庭。这些情况下,请有意启用该选项,把共享凭证排除在按设备策略之外,并给地址池留出余量,让会话不会在地址上撞车。

凡是需要独立地址、独立日志或独立移除的,就通过正常注册流程签发独立证书。这样每个下游系统都有一个可依托的独立对象,选项也就不再重要,因为名字已经唯一了。

无论选哪条路,要测的是管理模式而不是登录。把两台设备都连上,确认它们拿到不同地址,然后模拟一次丢失,检查你是否能只移除其中一台。openvpn(8) 手册界定了该选项的作用范围;共享是否真的可接受,取决于你的移除流程。

相关文章