为什么改 .ovpn 文件并不能开启服务器端 MFA
客户端的提示只能说明客户端提出了要求。服务器必须登记身份并校验验证码,而错误的验证码必须先失败,才谈得上 MFA。
你在配置里加上 auth-user-pass,重新连接,客户端便索要用户名和密码。看上去 MFA 已经生效。可随后你输入另一个账户的验证码,或者十分钟前就过期的验证码,隧道照样建立。这就是症状:客户端变了,服务器没变。只有服务器端的验证方判断某串一次性密码是否属于声称它的那个身份时,它才算一个因素。
提示只能证明客户端提出了要求,仅此而已
.ovpn 文件是客户端侧的文件。它可以要求客户端索取凭据、缓存凭据或停止缓存,却无法登记用户、安装 PAM 模块,也无法让服务器强制要求它现在并不校验的第二因素。
在手机上装一个验证器应用同样不构成这种关系。Google Authenticator PAM 项目是 OTP 校验组件,可以部署在 OpenVPN 之后;但它不是把 Google 账户登录塞进导入配置的办法。
登记正是配置文件做不到的那一环
TOTP 需要验证器与其验证方共享登记材料。手机上的六位数字是输出,它背后的种子才是秘密,而种子只属于一个身份。
因此运维方需要一套登记流程,把正确的种子绑定到正确的 VPN 身份上,同时还要有 手机丢失后经过验证的补发路径。允许用户上传一个以自己名字命名的文件,等于把登记变成接管账户的机会;把上传内容加密也改变不了这一点。
基于 PAM 的设计不必为每个 VPN 用户单独建一个 Unix 账户。模块文档支持备用的密钥路径,以及一个专用于文件访问的账户;后者是文件系统层面的身份,而不是被校验的登录身份。
常见错误是从单用户示例里抄来一条以某个用户名结尾的固定密钥路径。那只是单身份的演示,不是按用户查找;对每个请求都用它,结果是谁都没有独立登记的验证器。请把身份映射写下来,保护种子文件,并把口令、证书和账户检查放在同一个认证栈里。
读一读 PAM 栈,看真正被要求的是什么
像 account required pam_permit.so 这样的一行并没有实现账户资格判定,也没有增加任何因素。它只是放行了 PAM 的账户管理阶段,那是对阶段的陈述,不是对你用户的陈述。
宽松的登记选项也是同理。接受没有登记密钥的用户,可能是刻意选择的灰度上线方式,但它不能证明 MFA 是强制的,应当记为有结束日期的临时例外。
让客户端的交互方式对上服务器的设计
auth-user-pass
这条指令要求输入用户名和口令。它不配置 PAM,不建立登记记录,也不告诉服务器口令字段里装的是 TOTP 值。服务器端集成与客户端必须就部署真正支持的交互方式达成一致:挑战应答、有文档的组合凭据格式,或产品专属的流程。
不要因为客户端只显示一个字段,就往口令后面拼验证码。那只在服务器插件正好期望这种格式时有效,其他地方会以令人困惑的方式失败。
把种子和二维码材料挡在共享配置与日常诊断日志之外。通过已认证登录通道提交的验证码,与控制登记时下发的种子不是同一个对象;把两者混在一张工单里,秘密就是这样流出去的。
重连、令牌,以及一锤定音的测试
要为首次成功登录之后的情况做计划。先前被接受的验证码,在下一次认证时可能已过期,或被当作重放而拒绝。auth-nocache 管的是凭据保留,不安装 MFA;reneg-sec 0 也不是支持 TOTP 的定义,无论它在论坛帖子里出现多少次。
有些部署会在首次校验后签发认证令牌,让重连不再重新询问。那是一项有自身有效期与吊销策略的设计决策,而不是你继承来的默认值。
然后用人们真正在用的客户端去测准入策略。已登记的用户,凭正确的口令、证书和当前验证码,应当能连上。错误的验证码、没有登记的用户、被禁止的账户,都应当各自失败,并在服务器日志里看到原因。在你亲眼见到这些拒绝之前,你拥有的只是提示,不是策略。