当一个描述文件在一台 Mac 上顺利安装、在另一台上却被拒绝时,网络其实还没被触到,所以证书、网关和密码都不该背锅。安装器停在它不愿接受的某个载荷上,而且通常会记录是哪一个。于是只剩描述文件本身和生成它的工具这两个值得动手的地方,而在客户端上清空设置只是销毁证据,不是修复。

读描述文件,而不是重置 Mac

导出 .mobileconfig,在碰客户端之前看看它究竟装了什么:

plutil -p profile.mobileconfig | head -60

VPN 描述文件实际上是承担不同工作的两个载荷:com.apple.vpn.managed 承载连接,com.apple.dnsSettings.managed 承载解析器配置。安装会在安装器拒绝的第一个载荷处停止,拒绝信息连同该载荷的名字写进系统日志,所以日志才告诉你该打开哪一节。留一份最后成功导入的描述文件,因为那个文件就是你比对差异的基准。

生成工具悄悄加了什么

Apple Configurator 2.15 的 7A23 构建在其 DNS 载荷中输出了下面这段:

<key>DNS</key>
<dict>
  <key>SupplementalMatchDomainsNoSearch</key>
  <integer>0</integer>
</dict>

在 macOS 12.1 上,该构建写出的描述文件在导入时被拒绝。用 Configurator 2.11.1 建立的连接则毫无怨言地进去了,因为那个版本根本不写这个键。删掉整个 DNS 字典或只删有问题的键,重新保存,然后在同一台机器上重试,再去改别的东西。通常这一处修改就是全部修复。

这个工具有一个值得在信任它之前知道的陷阱。键被删掉之后,再保存同一个连接并没有把它放回去,只有从头新建连接时它才重新出现。把每个新生成的描述文件都当成可疑对象来检查,尤其当一整批连接是一次性建好的时候。

MDM 这条路在别处失败

推送同一描述文件的管理服务可能在另一个环节失败:客户端抱怨根本没有创建 VPN 服务。在报告的案例中,为证书认证配置的载荷却仍然要求填写密码字段;填一个占位值就能让描述文件生效,而没有任何东西用那个值做过认证。

如果走这条路,就存一个假字符串,绝不要存真实凭据,并把真正的秘密留在描述文件正文之外。带可用密码的描述文件会变成一个必须像密钥一样保护的文件,这比一开始那次导入失败严重得多。在分发之前就确定这个占位值归谁所有,免得日后有人把它当成值得轮换的值。写明它为什么存在只要一行,却能省下半年后的一场争论。

确认描述文件真的落地了

导入成功不等于服务可用,所以按这个顺序检查:

profiles show -type configuration
scutil --nc list
scutil --nc start "Your VPN Service"
scutil --nc status "Your VPN Service"
scutil --dns | head -20

第一条命令列出已安装的载荷;第二条说明到底有没有 VPN 服务。最后一条在连接之后运行,显示系统实际会用的解析器。按这个顺序读,并在链子断掉的地方停下,因为缺了服务,任何关于解析器的问题都没有意义。描述文件可以被列为已安装,却什么都不真正可用,而这正是这套顺序要暴露的状态。

如果服务条目还没有可用名字,隧道却起来了,那是导出时丢了显示名字段,解法是重新生成描述文件,而不是在客户端改名。如果解析器一直指向本地那个,说明 DNS 载荷被删得比你打算的更彻底。

分阶段推进,一次一台 Mac

在一台运行同一系统构建的受管 Mac 上安装,然后分开检查三件事:服务出现、解析器改变、一个真实的内部请求成功。三件都成立之后才该扩大范围。

这是三种以不同方式失败的不同结果,也正是这一点让一台测试机值那十分钟。能导入的描述文件不是能用的描述文件,而第一阶段的那台机器会在整个机群看到任何一种失败之前把它们都抓住。

相关文章