点一次 Connect 本应只弹出一个登录窗口。在 Mac 上往往弹出三个,而且它们很少属于同一个所有者:钥匙串负责本地的凭据提示,VPN 网关负责身份认证,客户端负责自己的通知。与其寻找一个让所有弹窗都沉默的开关,不如把每个窗口当作有各自修复方式的独立缺陷。下面的步骤会走一遍有意的连接尝试,并以一个可以重复的检查收尾。

改动设置之前先给每个对话框的归属命名

第一步是记录,而不是配置。做一次连接尝试,对出现的每个窗口记下四项:对话框中显示的应用名、去掉任何机密后的原文、它出现的阶段,以及取消时发生了什么。这样的三行记录几乎涵盖我看过的所有报告。

归属决定正确的修复方式,而错误的修复往往正是把一个提示变成三个的原因:

WindowWho owns itCorrect fixWhat not to do
“wants to use your confidential information stored in…”The item's access control list in your login keychainApprove the specific client helper, once, after checking the nameResetting the login keychain, or granting Always Allow to every application
“Sign in to <organization>” or an MFA pushThe gateway's identity providerUse the client's supported session renewal, or re-authenticateScripting a fixed password or code into the client
“Connection failed”, “Update required”, a policy bannerThe client or your organizationRead the first error and fix its causeHiding notices by editing a preference file the client rewrites

在同一次尝试里重新出现的提示,与在下次尝试里重新出现的提示是不同信号。前者通常意味着连接在你脚下重启了;后者通常意味着又在索要已保存的凭据。在碰钥匙串之前先记录是哪一种,因为两者几乎没有共同点。

搞清楚有多少东西在启动隧道

Mac 上有四种机制可以启动同一个 VPN:菜单栏操作、登录项、On Demand 规则,以及脚本或代理。当其中两个同时触发时,第二次启动可能在第一次仍在等待认证时到达,从而产生重复窗口且毫无进展。先列出已配置的内容:scutil --nc list 会打印系统设置已知的 VPN 服务及其当前状态。自带网络扩展的客户端会把配置文件保存在应用内部,可能不会出现在那里,所以也要检查客户端自己的连接列表。

然后寻找相互竞争的启动项。 scutil --nc show "Work VPN" 会打印内置服务的配置字典,包括 On Demand 规则;任何在接口变化时重连的规则,都会在 Wi-Fi 漫游或显示器唤醒网络栈时重启隧道——并重新打开认证提示。在系统设置 > 通用 > 登录项 下检查登录项,并用以下命令列出每个用户的代理 ls ~/Library/LaunchAgents。由 MDM 管理的安全栈所拥有的东西不要动;移除它通常会在下次检查时被推回来。

想看一次尝试中究竟在运行什么:ps -Ao pid,comm | grep -iE 'vpn|tunnel|extension'。在只期望一个客户端辅助进程的地方出现两个,往往比任何凭据问题都更能解释“为什么我收到两个提示”。

在不重置钥匙串的情况下修复 Keychain 访问

提示来自所存条目的访问控制列表,而不是 VPN 协议。每个条目记录哪些应用可以在不被询问的情况下读取它。客户端更新后,发起询问的辅助程序可能换了名字或签名,而条目仍列着旧的,于是 macOS 每次连接都会再问。只针对那个条目批准新辅助程序就是全部修复;批准所有应用则不是。

不碰 VPN 也能确认 ACL 就是原因:security find-generic-password -s "service-name" -g 会从终端读取同一个条目。如果该命令也弹出提示,那么这个对话框属于钥匙串,隧道只是触发条件。Apple 关于三个按钮的说明——仅允许一次、始终允许、拒绝——值得读一遍,因为正是“拒绝”让提示立刻再次出现,而不是等到下次尝试。

如果你批准了错误的辅助程序,在 Keychain 访问 中打开该条目,切到“访问控制”,删除那条记录;这就是回滚。删除登录钥匙串,或运行重建它的修复工具,也会丢掉无关的密码,是比问题大得多的改动。

把登录与策略步骤留在它们各自的流程里

浏览器登录或 MFA 挑战属于网关。如果你的组织提供会话保持或基于证书的认证,就用它,因为这是受支持的降低认证频率的方式。把固定验证码输入客户端,或把密码存进脚本让提示永不出现,等于用静态秘密替换交互因素,下一次策略轮换时就会失败。

组织通知是唯一不该压制的类别。它们通常强制执行状态检查或可接受使用确认,隐藏它们可能让设备在隧道仍然可用时就不合规。错误对话框是另一类:保留第一条错误文本,因为第二个对话框往往只是重试后报告的同一个故障。

用一次尝试验证,然后再重启验证一次

去掉重复的启动项并修好钥匙串条目后,只做一次尝试:退出包括菜单栏辅助程序在内的每个客户端实例,连接一次,并数窗口数量。你要的是(如果条目被重建)钥匙串批准,以及一个认证步骤。仅此而已。 scutil --nc status "Work VPN" 应为内置服务报告 Connected。

然后重启一次并重复。只有在重启后才回来的提示指向登录项或 On Demand 规则,而不是凭据;在会话内回来的提示指向 ACL 或第二个启动项。如果两轮之后仍在重复,交给管理员的实用材料是首次尝试的三行表格——所有者、原文、阶段——而不是对话框截图。

目标是更少的提示,而不是静默。隐藏授权步骤的连接是你再也无法审计的连接,下一次证书轮换会让你在不知道哪个组件失败的情况下撞上问题。

相关文章