阻止 NetworkManager 显示已保存的 VPN 密码
每次都询问、交给密钥环,或保留仅 root 可读的文件。每种选择的风险不同,密码标志也应与之匹配。
NetworkManager 可以保存 VPN 密码,使连接在无人输入的情况下建立,并且能通过编辑器或 nmcli --show-secrets 再次显示该值。它有三种归属模型,显示行为只是你所选模型的症状。先选模型,再设置与之匹配的标志,而不是用一个会让下一个人困惑的占位符把字段藏起来。
三种归属模型
第一种模型每次都询问。什么都不保存,密钥只在激活期间存在,任何启动连接的人都必须知道密码。它最不方便,也最容易辩解。
第二种把密钥交给用户拥有的密钥环。代理在会话开始时解锁,并按需提供该值,这使它不进入连接文件,却把连接绑定到该用户的会话。由此有两个条件:代理必须在运行,而且必须已解锁。
第三种为系统连接保存受保护的凭据。它能承受重启,在任何登录之前就可用,代价是值以文件权限而非加密方式守在磁盘上。
每种模型在恰当的语境中都合理。错误在于混用,这样笔记本上就会出现两处密钥,而且没有明确答案说明哪一处是权威。记录某个配置文件用的是哪种模型。团队手册里的一行,能省下下一个人再去发明第四个查找地点。
先读当前状态再改动
以管理连接的用户身份查看配置文件与密钥状态。第二条命令才能告诉你该值是否真的可读。
nmcli connection show "Office VPN"
nmcli --show-secrets connection show "Office VPN"
sudo stat -c '%U %a %n' /etc/NetworkManager/system-connections/*.nmconnection
该目录中的密钥文件通常属于 root,模式为 600。这挡住了普通用户,却挡不住 root;当同一台机器被共享,或备份以 root 运行时,这点很重要。
文件权限是边界,不是加密。能以 root 读取文件的人就持有明文密码。对无人值守的服务器这是可以接受的交换,对共享工作站则很糟糕。写下来一次,就能避免关于该值是否受保护的漫长争论。
每个标志值的作用
VPN 密钥带有一个 flags 属性,而这些值并不能只从数字看出来。
| Value | Meaning | Practical effect |
|---|---|---|
| 0 | No special flag | Secret is typically saved with the connection |
| 1 | Agent-owned | A keyring or secret agent supplies it |
| 2 | Not saved | Prompted at each activation |
| 4 | Not required | Connection proceeds without asking |
实际行为还取决于插件以及是否有代理在运行,所以把表格当作契约,把你观察到的行为当作要验证的对象。在某个桌面上有效的值,在没有会话的服务器上可能表现不同。大多数令人困惑的工单就住在这道缝隙里。
明确设置该属性,而不是删掉一行然后指望它。缺失的标志不是策略,下一次软件包更新可能用它没打算的值把它填上。
让模型与连接启动的时机相匹配
如果连接只在用户登录时才启动,代理归属很合适,并能把密钥留在文件之外。如果它在启动时、任何会话存在之前就启动,代理就帮不上忙。
对大多数机器来说,全部决定就在这里。这也解释了一类令人困惑的报告:连接在交互方式下能用,重启后却失败。标志从未改变,改变的是上下文。
对无人值守的情形,实际答案是受限制的 root 文件或经批准的凭据来源。如果该配置文件将来会被导出或复制到其他机器,就把它留在连接配置文件之外。
如果该值已经暴露过,就更换它
改标志并不会动密码本身。出现在截图、shell 历史、发给支持的压缩包,或其他用户能打开的文件里的值,都应视为已泄露。
在服务器上更换它,然后修好客户端,并终止任何用旧值通过认证的会话。删除本地连接并不能在对面撤销什么,而这正是人们常漏掉的部分。
然后别再把手输密码放到命令行上。它会落进 shell 历史,也可能出现在进程列表里;改用交互式提示或代理。
通过重新连接来验证
重复那条显示密钥的命令,确认该字段不再打印。然后断开再重连;如果连接会自动启动,就重启,因为真正有趣的故障只在会话上下文改变时才出现。
如果密钥仍然出现,那是另一个配置文件或另一个代理在提供它。检查活动连接与密钥环,而不是不断删文件直到症状转移。