资讯动态

OpenSSH升级后pam_tally2计数不清零?PAM配置排查与修复指南

发布时间:2026/10/15 20:00:58 来源:尧图企业网站定制
最近帮一位朋友处理了一个挺闹心的问题他们的Linux服务器把OpenSSH从旧版本升级到新版本之后原本正常工作的pam_tally2账户失败计数机制突然“失灵”了——明明用户名和密码都输入正确成功登录了可之前积累的失败次数就是不清零等下次输错一次密码就直接被锁住。这个问题折腾了快两天排查下来发现根子不在OpenSSH本身而在PAM配置的碎片化。这篇文章就把完整的排查过程、根因分析、修复方案和预防建议写清楚给遇到类似情况的同行一个可以直接照做的参考。如果你碰到的是“登录成功但pam_tally2计数不清零”或者“升级OpenSSH后账户莫名被锁”那这篇文章就是为你准备的。我会从现象出发逐步拆解pam_tally2的工作机制再给出三套修复思路——紧急解锁、修正配置、迁移到更合理的pam_faillock方案。1. 升级后遇到的现象登录成功计数却不归零随后被锁死先说现象因为很多人卡在这一步就懵了。朋友的这台服务器原来用的是OpenSSH 8.x pam_tally2配置很简单输错3次密码锁定账号10分钟。运维一直很正常。某天他们按安全要求把OpenSSH升到新版本重启sshd服务然后再测试登录问题就来了。第一轮测试故意输错两次密码第三次输对登录成功。这看起来没什么问题但等他退出再试的时候第三次输错一次密码直接提示“Account is locked”。也就是说之前那两次错误计数没有被“成功登录”这个动作清掉加上第三次错误就触发了锁定规则。再进一步观察被锁住之后用pam_tally2 --user 某用户名查看计数pam_tally2 --user testuser Login Failures Latest failure Latest success testuser 3 05/12 10:23:41 05/12 10:05:12注意看Failures是3无论登录成功多少次这个数字纹丝不动。而正常情况下成功登录后Failures应该归零Latest success会更新。这种现象还伴随几个特征手动执行pam_tally2 -r -u 某用户名可以清零但下次输错密码计数又会重新累计并卡住。重启sshd服务也不会让计数归零计数文件持久保存在/var/run/tally2/目录下部分发行版路径可能不同。只有通过SSH登录才出现这个问题本机终端比如控制台登录后计数能正常清零。日志里能看到pam_tally2的报错信息但内容不足以直接指出根因。这套现象组合起来基本可以排除OpenSSH编译本身的问题问题出在“升级后PAM配置发生了什么变化”。在动手改配置之前必须先搞明白pam_tally2的正常工作依赖哪些条件否则容易乱试。2. 先搞清楚pam_tally2在登录里的两个关键介入点auth计数、account清零很多人以为pam_tally2就是“登录失败就加1登录成功就清零”这么简单实际它的行为分散在PAM的两个阶段里缺一个都会出问题。PAM的认证流程大致分四步常用的是auth、account、password、session四个管理组。与计数直接相关的是前两个2.1 auth阶段负责“检查”和“累计”auth required pam_tally2.so这一行会做两件事在用户输入密码之前先检查该用户累计的失败次数是否达到deny阈值。如果达到了直接返回认证失败不管密码对不对都会被拒。如果认证最终失败通常是密码错误它会在用户记录上累加失败次数。注意这里说的“认证失败”是以PAM栈整体的返回结果为标准的。所以配置顺序很关键pam_tally2必须放在pam_unix.so之前或之后取决于你想让它先检查还是后检查。常见做法是放在pam_unix.so之前先拦截锁定的用户减少不必要的密码验证消耗。2.2 account阶段负责“清零”这是最容易被忽略的一环。account required pam_tally2.so这一行作用是在用户认证成功之后、会话建立之前把该用户的失败计数清零。也就是说“登录成功后计数归零”这个逻辑并不在auth阶段而在account阶段。如果PAM配置里只有auth阶段的pam_tally2没有account阶段的pam_tally2那么失败计数只会涨永远不会自动跌。2.3 为什么SSH登录容易“单独踩坑”本地终端登录比如通过login程序时PAM配置走的是/etc/pam.d/login、/etc/pam.d/system-auth或/etc/pam.d/password-auth这套链。SSH登录走的则是/etc/pam.d/sshd而它通常会include上述公共配置文件。问题就出在这个“include”上如果OpenSSH升级后新的/etc/pam.d/sshd模板文件里include了其他配置或者系统公共文件里被塞入了pam_faillock的配置就会出现“auth阶段计数用的是tally2account阶段清零却根本没经过tally2”的错位。用一个生活化的类比pam_tally2像是一个记分牌auth阶段是“裁判判犯规后记一分”account阶段是“比赛结束后归零”。如果记分员只负责加分没人负责清零那比分就会永远停在最后一次犯规的数字上。升级OpenSSH这件事本质上就是换了个记分员但清零的岗位被裁掉了。3. 完整排查链路从现象一步步定位到PAM配置碎片化排查的时候不要上来就改配置先按下面这条链路走一遍每一步都有明确目的。我当时就是靠这条链路花了半小时定位到根因。3.1 确认计数文件到底在哪里、内容是什么pam_tally2的计数默认保存在/var/run/tally2/下文件名就是用户名。先看看文件是否存在、权限是否正常ls -l /var/run/tally2/ cat /var/run/tally2/testuser如果文件存在且内容是一个数字说明计数模块本身是正常工作的。如果文件不存在可能有两种情况一是还没有失败记录二是模块根本没被调用。3.2 查看日志确认PAM栈里到底执行了哪些模块打开/var/log/secure搜与该用户、sshd、pam_tally2相关的记录grep -i pam_tally2\|pam_faillock\|sshd.*testuser /var/log/secure | tail -50正常登录成功时你应该能看到类似这样的记录sshd[12345]: Accepted password for testuser from 192.168.1.10 port 50022 ssh2 sshd[12345]: pam_unix(sshd:session): session opened for user testuser如果登录成功之后日志里完全没有pam_tally2(sshd:account)的记录那就说明account阶段根本没调用tally2。这就解释了为什么计数不清零。反之日志里如果出现了pam_faillock(sshd:auth)的记录说明系统在走另一套计数逻辑pam_tally2可能已经沦为“僵尸模块”——计数器还留在那里但实际生效的锁定策略已经换成pam_faillock了。3.3 检查/etc/pam.d/sshd和公共配置文件这是最核心的一步。分别打开/etc/pam.d/sshd、/etc/pam.d/system-auth、/etc/pam.d/password-auth逐行检查pam_tally2出现的位置和参数。一个典型的错误配置长这样sshd文件auth required pam_tally2.so deny3 unlock_time600 even_deny_root account required pam_faillock.so这种情况下auth阶段还用tally2计数account阶段却只调用了faillock清零。因为两套计数器的数据不互通tally2的计数自然永远不清零。另一个可能的错误配置是account段只有pam_unix.so或pam_permit.so完全没有pam_tally2那就更直接了——清零逻辑缺失。3.4 检查sshd_config里的UsePAM选项pam_tally2能否在SSH登录中生效前提是sshd启用了PAM。在/etc/ssh/sshd_config里确认grep -i usepam\|challengeresponse /etc/ssh/sshd_config正常情况下应该是UsePAM yes。如果被改成no那PAM模块压根不会执行计数不出问题才怪。不过一般升级OpenSSH不会动这个选项还是检查一下比较稳妥。3.5 确认是否存在双计数器并存这一步容易被忽略。新版系统比如CentOS 7及以后的RHEL系默认把pam_faillock作为账户锁定模块而很多老运维习惯手动配置pam_tally2。升级OpenSSH后包的postinstall脚本可能会自动更新system-auth和password-auth的PAM配置模板把pam_faillock加进去于是出现两套计数同时运行的情况。验证方法很简单faillock --user testuser pam_tally2 --user testuser如果两个命令都返回数字说明两套计数器并存。此时你被锁定的原因可能来自pam_faillock而不是pam_tally2。手动重置tally2计数并不能解锁faillock的锁定。这个坑很隐蔽不看日志很容易误判。4. 真正的根因openssh升级带来的PAM配置覆盖与双计数器并存把配置翻完问题基本能定位到以下几类按我实际遇到的频率从高到低排列。4.1 升级包覆盖了sshd的PAM模板这是最常见的。很多发行版的OpenSSH升级包尤其是从老版本大跨度升级到新版本时会覆盖/etc/pam.d/sshd。如果新模板只保留了auth部分的tally2配置或者换成了faillock而account部分没有补齐tally2系统就会变成“只计数、不清零”。我朋友那台服务器就是这么回事升级前sshd文件里手动加过account阶段的tally2配置升级后模板被覆盖account段只剩了faillock和unix模块tally2的计数就永远停在了最后一次失败的数字上。4.2 auth与account两段使用了不同的计数模块这种情况多发生在system-auth或password-auth被修改过、或者升级脚本干预过的机器上。auth段写的是pam_tally2.soaccount段写的是pam_faillock.so或者反过来。因为两套模块的数据文件不共享账就对不上。pam_tally2把计数存在/var/run/tally2/pam_faillock把计数存在/var/run/faillock/。它们各自记录各自的失败次数互不干扰但也互不清零。日志里可能都会出现但最终生效的往往是后执行的那个模块。4.3 PAM栈的include顺序被破坏有些机器的/etc/pam.d/sshd里account段配置是account required pam_tally2.so account include system-auth如果include进来的system-auth里恰好有pam_faillock.so的account行顺序在pam_tally2.so之后那么真正决定“到底清零哪个计数”的就是最后执行的那个模块。如果它只清faillock的计数tally2的计数自然残留。4.4 参数差异导致看起来“没清零”还有一种容易误判的情况pam_tally2配置中用了unlock_time600但even_deny_root只对root用户生效普通用户不受影响。如果你测试的是root账号且配置里漏了even_deny_rootroot根本不会被锁定也就谈不上清零问题。而普通用户登录成功但计数不清零基本还是前面三类配置问题。写到这里我顺手整理了一张对比表方便你对照自己的配置判断属于哪一种现象可能的配置状态根因分类登录成功tally2计数不动account段没有tally2模板被覆盖或配置缺失登录成功tally2计数归零但faillock还锁着双模块并存account段只清faillock双计数器冲突本机登录能清零SSH不能sshd的PAM文件和login走的不同配置链include配置不一致日志里有pam_faillock没有pam_tally2的account记录当前生效的是faillock迁移不彻底5. 三种修复方案应急清零、修正配置、迁移到pam_faillock搞清楚根因之后修复就顺理成章了。根据你的环境和对稳定性的要求可以选下面任意一种。5.1 方案A应急清零先救活账号再说如果服务器上已经有账号被锁定最紧急的是先恢复访问。手动清零tally2计数pam_tally2 -r -u testuser如果你确定是faillock在起作用用faillock清零faillock --user testuser --reset不确定的话两个都执行一遍确保计数都归零然后再测试登录。注意pam_tally2 -r只清tally2的计数faillock --reset只清faillock的计数。应急场景下两个都跑不会出错。5.2 方案B修正PAM配置让account阶段回到tally2如果你暂时不想动大的架构继续用pam_tally2那就把account段的tally2补上并确保authaccount配套。在/etc/pam.d/sshd里至少需要这样两行放在auth段和account段的合适位置auth required pam_tally2.so deny3 unlock_time600 even_deny_root account required pam_tally2.so如果系统用system-auth或password-auth作为公共配置也要检查这两个文件里的auth和account段是否有对应的tally2行。注意pam_tally2.so的auth和account两行都要有缺一不可。修改之前先备份原文件cp /etc/pam.d/sshd /etc/pam.d/sshd.bak.$(date %F)修改完成后不需要重启sshdPAM配置是每次认证时动态读取的。但为了保险可以用sshd -t检查一下配置语法然后重新开一个SSH会话测试不要在当前会话里操作免得把自己锁在外面。5.3 方案C彻底迁移到pam_faillock和系统默认机制统一如果你用的是RHEL/CentOS 7以后的系统或者Ubuntu 18.04以后的系统我建议直接迁移到pam_faillock。原因很简单新系统默认就是faillockOpenSSH升级模板也会优先适配faillock继续手动维护tally2只会不断踩类似的坑。以RHEL系为例迁移步骤大致如下。第一步在/etc/pam.d/system-auth和/etc/pam.d/password-auth的auth段确保有auth required pam_faillock.so preauth silent audit deny3 even_deny_root unlock_time600 auth sufficient pam_unix.so nullok try_first_pass auth [defaultdie] pam_faillock.so authfail audit deny3 even_deny_root unlock_time600account段有account required pam_faillock.so第二步把/etc/pam.d/sshd里残留的pam_tally2.so相关行去掉确保它include的公共配置能走到faillock。如果sshd文件里没有include公共配置就手动加上faillock三件套。第三步清理旧计数rm -f /var/run/tally2/* pam_tally2 --user testuser --reset faillock --user testuser --reset第四步验证登录。故意输错三次密码第四次用正确密码登录观察faillock --user testuser的计数是否在成功登录后归零。迁移之后的好处是日志更清晰配置与发行版模板一致后续再升级OpenSSH模板不会与你手动写的tally2配置发生冲突。5.4 应急与长期方案怎么选我的建议是如果是生产环境先用方案A把账号救活再用方案C做彻底迁移。方案B适合不想动公共配置的临时场景但长远看双模块并存的风险还在。6. 修复后的验证手段以及给后续升级留几条退路配置改完之后一定要按下面的流程做一轮完整验证确认计数真的会“成功即清零”而不是看起来正常。6.1 完整的功能验证流程准备一个测试账号按以下步骤操作用pam_tally2 --user 测试账号确认当前计数是0或先手动清零。故意输错密码两次每次间隔几秒确认两次都认证失败。再用正确密码登录确认能够成功登录。退出登录后立刻执行pam_tally2 --user 测试账号观察Failures是否已经归零。再故意输错三次密码确认第四次被锁定或提示解锁剩余时间。到unlock_time时间后再次尝试登录确认能正常登录。这一套验证下来基本能覆盖auth计数、account清零、锁定后拦截、解锁时间这几个核心行为。如果其中某一步不符合预期回到本文第3、4节的排查链路再走一遍。另外如果服务器是多用户环境建议在业务低峰期操作避免影响其他用户。6.2 升级OpenSSH之前先把PAM配置备份成“免死金牌”经历了这次问题之后我给自己的服务器定了一个固定流程每次升级OpenSSH前必做三件事备份/etc/pam.d/下所有与sshd、system-auth、password-auth相关的文件到独立目录。记录当前计数状态pam_tally2和faillock分别查看一次并且记录哪些用户当前处于锁定状态。查看当前sshd_config里与PAM相关的选项值升级后逐项对比。升级完成后第一时间检查/etc/pam.d/sshd是否有变化。没有变化继续观察有变化马上对照备份文件把权限策略还原回去。这个习惯已经帮我避免了好几次“升级一时爽登录火葬场”的事故。6.3 日常监控里的一个小细节如果你用监控脚本采集登录失败计数注意别把tally2和faillock当成同一个指标。有些脚本只监控pam_tally2 --user的输出但系统实际锁定是用pam_faillock实现的这会导致监控数据永远正常、实际用户却一直被锁的反常现象。我现在的做法是统一用faillock作为账号锁定的唯一数据源脚本里只解析faillock命令的输出。如果哪台机器还有历史遗留的tally2文件只在迁移时清理一次平时不再依赖它。最后再分享一点心得这类问题最折磨人的地方不是“不好修”而是“现象看起来正常”——用户明明能登录计数却不清零不翻日志根本不知道是PAM配置的锅。以后凡是升级OpenSSH之后出现账户异常锁定第一反应别去重编译OpenSSH先去/etc/pam.d/sshd里看auth和account两段模块是不是自洽。把这个习惯练出来能省下大把排查时间。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑