登录后能工作、登录前却失败的连接,通常意味着开机时的尝试拿不到密钥,而不是服务器拒绝了密钥。凭据是存在的,索取它的上下文不存在。仅这一点区别就能省下一次不必要的密码重置。

顺着请求走:有东西在桌面会话出现之前就启动了连接,而平时负责应答的密钥库尚未解锁。两个上下文对密钥归谁所有意见不一,配置文件则记录了应由哪一方提供。

开机路径到底在要什么

开机时,NetworkManager 作为系统服务启动,没有用户会话,没有会话 D-Bus,也没有已解锁的钥匙环。连接配置文件仍可被拉起,但只能用服务自己够得到的密钥。任何属于密钥代理的东西都要等到有人登录、代理出现。服务完全按配置行事;需要改的是配置文件。

故障写在连接里,而不是藏在钥匙环里。

读取连接上的密钥标志

要问连接期待什么,而不是桌面记得什么。标志列直接回答这个问题,而且它会随磁盘上的配置文件一起熬过重启。

先看配置文件列表,确认哪个连接被设为自动拉起。然后导出单个连接并读取密码标志:

nmcli -f NAME,UUID,TYPE,AUTOCONNECT connection show
nmcli connection show "Work VPN" | grep -i -E "password|secret|key"
journalctl -b -u NetworkManager --grep "secret"

第一条命令确认存在哪些配置文件、是否有哪一个设了自动连接,无人值守的尝试正是这样开始的。第二条暴露标志取值,第三条则显示服务在抱怨:针对某个密钥没有任何代理应答。一行日志把某个密钥点名为代理所有,就是一句话的完整诊断。

Flag valueWhere the secret livesBehaviour before login
0Stored in the connection profileAvailable to the system service
1Owned by a secret agentBlocks until the agent is unlocked
2Never storedPrompts on every activation
4Not requiredNever requested at all

为什么把连接移到系统作用域会改变答案

属于用户的连接在该用户的代理下激活,所以桌面一启动它就工作得完美。移到系统作用域后代理被移出路径,于是同一个配置文件在 VPN 配置一行不改的情况下表现不同。

这种移动是正当设计,但它带来一个要求:密钥必须能被系统服务取到。把它存进配置文件、通过系统作用域的凭据提供,或在恰当的时刻接受交互式提示,都是有效答案。留下标志 1 然后指望它,则不是。

带独立口令的私钥又多了一层。即便是已保存的账户密码,也解不开需要口令的私钥,所以在改动任何东西之前,先核实失败的阶段真正要的是哪一个密钥。

不该做什么,以及该做什么

把每个凭据文件都设成所有人可读,或者干脆关掉认证以免出现提示,是用永久的暴露换掉开机时的一点不便。两者也只是把依赖藏起来,而不是解决它,下一次镜像更新就会把同样的故障带回来。

在那个阶段使用你的发行版为无人值守激活所记录的机制,然后确认配置文件的标志与之一致。要从干净开机去检查结果,而不是从已经带着代理的 shell 里检查。把连接所有者、密钥来源和必须工作的阶段写下来,这样以后改动自动启动时,就不会悄悄重新引入「得先有人解锁桌面」的依赖。文档记录,正是修好的服务与下个季度再次坏掉的服务之间的差别。

要在受控的干净开机上测试,而不是在登录后手动重试。重试之所以成功,原因恰恰是开机尝试失败的那个原因,而这正是快速测试会毁掉的证据。

相关文章