pam_google_authenticator.so 加载失败主因是路径错误、权限不足、SELinux 上下文不符、缺失依赖(如 libqrencode)或架构不匹配;SSH 双因子需用 [success=done default=ignore] 避免干扰密钥登录;.google_authenticator 读取失败多因权限非 0400、路径错误或 $HOME 未正确继承。

为什么 pam_google_authenticator.so 加载失败或被忽略
根本原因通常是模块路径不对、权限错误,或没在对应服务的 PAM 配置里正确引用。系统默认不启用 Google Authenticator,哪怕装了包,/lib/security/pam_google_authenticator.so 也可能因 SELinux 上下文、缺失依赖(如 libqrencode)或 32/64 位架构不匹配而静默失败。
- 检查模块是否存在且可读:
ls -l /lib/security/pam_google_authenticator.so;若路径是/usr/lib64/...,需确认你的系统是纯 64 位且 PAM 配置指向正确位置 - 用
ldd /lib/security/pam_google_authenticator.so看是否缺库,常见报错libqrencode.so.4: cannot open shared object file就得装qrencode-libs - SELinux 启用时,模块文件必须有
system_u:object_r:etc_runtime_t:s0类型,否则被拒绝加载;临时验证可setenforce 0,但生产环境要用semanage fcontext修复上下文 - 确保目标服务(如
sshd)的 PAM 配置(/etc/pam.d/sshd)里有类似这行:auth [success=done default=ignore] pam_google_authenticator.so nullok,注意不是写在account或password段
如何让 SSH 登录同时要求密码 + TOTP,且不破坏 root 登录或密钥登录逻辑
关键在控制 PAM 栈中各模块的返回值和跳转逻辑。直接加 auth required 会导致密钥登录也强制要验证码,违背“多重但非强制”的本意。
- 推荐用
auth [success=ok default=bad]跳转组合:先走密钥认证(pam_ssh.so或 OpenSSH 自带逻辑),成功则跳过 TOTP;失败再走密码+TOTP 流程 - 在
/etc/pam.d/sshd中,把 TOTP 行放在auth [success=ok default=bad]密码验证(pam_unix.so)之后,例如:auth [success=ok default=bad] pam_unix.so→auth [success=done default=ignore] pam_google_authenticator.so nullok -
nullok参数允许用户尚未配置 TOTP 时仍能用密码登录(便于 rollout),但上线后应改用secret=/home/${USER}/.google_authenticator并配合脚本批量初始化 - root 用户默认绕过很多 PAM 规则,如需对 root 启用,必须显式在
/etc/pam.d/sshd中添加对应行,并确认PermitRootLogin yes或prohibit-password设置与之兼容
pam_faildelay.so 和 pam_tally2.so 在双因子场景下的实际作用边界
这两个模块管的是传统认证失败计数和延迟,但对 TOTP 验证失败默认不生效——因为 pam_google_authenticator.so 是独立模块,它的失败不触发 pam_tally2 计数,除非你手动把它串进同一 auth 段并指定 deny 条件。
-
pam_faildelay.so delay=3000000只影响 PAM 栈中它所在段的后续模块,若放在 TOTP 行之后,对 TOTP 失败无延迟;建议放最前,统一延缓所有 auth 尝试 -
pam_tally2.so默认只统计pam_unix.so的失败;要统计 TOTP,得在 TOTP 行加onerr=fail并配合audit选项,但实测兼容性差,更稳妥是用 faillog 日志 + 外部脚本解析 - 注意
pam_tally2的 lockout 对 root 无效(安全策略),且与auth [default=die]类跳转冲突,容易导致整个 auth 流程提前终止 - 双因子下真正的防爆破重点不在计数,而在限制 TOTP token 有效期(默认 30 秒)和单次使用性;重放攻击比暴力尝试更值得防
为什么用户配置了 .google_authenticator 却提示 “QR code not found” 或 “No secret key”
本质是 PAM 模块找不到或读不了该文件,和生成流程无关。常见于权限、路径、用户上下文三类问题。
- 文件必须由目标用户拥有,且权限为
0400(chmod 0400 ~/.google_authenticator),组或其他人可读会直接被模块拒绝 - 默认路径是
$HOME/.google_authenticator,但若用户 shell 是/sbin/nologin或 home 目录被 bind mount,getpwuid()返回的pw_dir可能为空或错误;可用secret=/var/lib/google-authenticator/<code>user显式指定 - SSH 登录时 PAM 运行在子进程,某些 systemd-logind 环境下
$HOME未正确继承,此时strace -e openat pam_google_authenticator.so可看到 open 失败的真实路径 - 如果用
su -或sudo -i测试,注意当前 shell 的$HOME是切换前用户的,不是目标用户,容易误判
复杂点在于 PAM 模块行为高度依赖调用它的服务上下文,同一个 .so 文件,在 sshd、login、sudo 里表现可能不同;别指望一套配置全适配,每个服务都得单独验证日志(journalctl -u sshd -f)和模块返回码。










