根本原因是PAM配置顺序或控制标志错误,导致模块被跳过;须确保pam_google_authenticator.so位于pam_unix.so之后、未被[success=done]终止,且正确配置于/etc/pam.d/sshd而非sudo文件。

为什么 pam_google_authenticator 模块加载后仍不触发二次验证
根本原因通常是 PAM 配置顺序或控制标志(control flag)写错,而不是模块没装好。Linux 的 PAM 是按栈式顺序执行的,auth [success=ok default=ignore] 这类跳转逻辑一旦写反,后续模块直接被跳过。
-
auth [success=1 default=ignore]表示验证成功就跳过下 1 行(即跳过后面的auth required pam_permit.so类兜底规则),但若下一行是关键模块,就等于禁用了它 - 必须确保
pam_google_authenticator.so出现在pam_unix.so之后、且未被[success=done]提前终止流程 - 常见错误现象:
ssh登录只校验密码,sudo却触发了 Google Authenticator——说明模块被加在了sudo的/etc/pam.d/sudo而非/etc/pam.d/sshd - 调试方法:临时在
/etc/pam.d/sshd开头加一行auth [default=debug] pam_echo.so msg="PAM stack reached google_auth",再用ssh -o PubkeyAuthentication=no user@host触发密码登录观察日志
pam_faildelay.so 和 fail_delay 在 SSH 登录中的真实作用
它不控制“输错密码后等待多久才能再试”,而是控制 PAM 层返回失败响应前的休眠时间,目的是拖慢暴力破解节奏。但这个延迟只对单次认证生效,且仅当整个 PAM 栈最终返回失败时才起效。
- 如果
pam_unix.so已经成功通过密码验证,后续pam_google_authenticator.so失败,整个认证结果仍是失败,此时fail_delay才会生效 - 参数写法必须是
auth [default=die] pam_faildelay.so delay=3000000(单位微秒),写成delay=3不会生效 - 注意和 SSH 自身的
LoginGraceTime和MaxAuthTries冲突:前者控制连接建立后允许认证的总时长,后者限制最大尝试次数,它们在 PAM 外层起作用 - 实际效果受限于系统负载——高负载时
delay可能被内核调度器拉长,不能当作精确防爆破手段
如何让 pam_u2f.so 和 pam_google_authenticator.so 同时工作而不互相干扰
关键不是“都加上”,而是明确划分职责:U2F 做硬件凭证强绑定,TOTP 做备用通道。PAM 默认把所有 auth 行当成“全都要满足”,必须用控制标志拆解逻辑分支。
- 典型错误配置:
auth required pam_u2f.so+auth required pam_google_authenticator.so→ 两者都被视为必需,用户必须同时插 U 盘又输 TOTP 码 - 正确做法是用
sufficient让任一路径成功即可退出:auth [success=ok default=ignore] pam_u2f.so,再接auth [success=ok default=die] pam_google_authenticator.so - 注意
pam_u2f.so的authfile参数必须指向用户家目录下的.config/Yubico/u2f_keys,且该文件权限需为600,否则模块静默失败 - 兼容性坑:OpenSSH 8.2+ 才原生支持
sk-*密钥类型,旧版本需依赖pam_u2f.so+libu2f-host,而后者在 CentOS 7 上默认不带,得手动编译
为什么修改 /etc/pam.d/common-auth 后 sudo 仍不走多因子
因为 Ubuntu/Debian 系发行版中,sudo 默认不 include common-auth,而是直连 pam_group.so 和 pam_succeed_if.so。改错文件等于白改。
- 检查实际加载链:
grep -r "include common-auth" /etc/pam.d/,你会发现su、login有,但sudo没有 - 正确操作是在
/etc/pam.d/sudo第一行插入:auth [success=ok default=ignore] pam_google_authenticator.so secret=/home/${USER}/.google_authenticator - 变量展开风险:
${USER}在 PAM 中不自动解析,必须用user=root这类静态值,或改用auth requisite pam_exec.so expose_authtok /usr/local/bin/get_totp_for_user.sh动态取路径 - 最隐蔽的坑:SELinux 或 AppArmor 可能阻止
pam_google_authenticator.so读取用户家目录,audit.log里会出现avc: denied { read } for comm="sshd" name=".google_authenticator",此时要补策略而非调 PAM

















