
开工前先聊聊改密这件事为什么值得说道做运维和开发的朋友几乎每天都在跟 Linux 打交道但说起 passwd 命令很多人第一反应是不就是改个密码吗有什么好讲的。可实际工作里围绕密码修改翻车的案例一点都不少有人批量改密把 root 锁了有人在脚本里明文传密码被审计揪出来还有人忘记了 passwd 命令在非交互模式下根本不吃标准输入这一茬导致自动化任务静默失败。这些坑我这些年都踩过也看身边的同事踩过。这篇文章就围绕 passwd 命令本身把它的参数、交互逻辑、非交互用法、常见报错、安全建议一条条拆开讲透。适合刚接触 Linux 的运维新人也适合那些写惯了自动化脚本、却从没深究过 passwd 底层行为的开发者。读完之后你不仅能手动把密码改利索还能在脚本里安全、稳定地完成批量改密遇到锁账户、密码过期这类问题也能从容排查。先说个基本认知passwd 是一条 setuid 程序它修改的是 /etc/shadow 文件里的密码哈希字段。这个文件普通用户读不了但 passwd 能以 root 身份帮你完成写入。理解了这一层后面所有参数和行为就都顺理成章了。1. 命令基础与核心参数拆解1.1 passwd 到底做了什么passwd 命令的全称是 password它的核心职责就是更新用户的认证信息。在传统 Linux 系统中用户密码并不是明文存储在系统里的而是经过哈希算法处理之后存放在 /etc/shadow 文件中。这个文件每一行对应一个用户字段之间用冒号分隔其中第二个字段就是密码哈希值形如$6$salt$hash这样的字符串。$6$表示使用 SHA-512 算法这是大多数现代发行版的默认选择。当你执行passwd修改密码时系统会先验证当前用户的旧密码如果当前用户是 root则可以跳过这一步然后要求输入两次新密码确认一致后passwd 会调用底层的 crypt 库函数生成新的哈希值并写回 /etc/shadow。整个过程对外表现是交互式问答但本质上是一次读取-验证-哈希-写入的完整事务。理解这个流程对排错特别重要。为什么我改了密码但 SSH 登录还是提示密码错误这种问题99% 是因为写入环节没成功或者写入的哈希算法与系统认证配置不匹配。这不是玄学是机制。1.2 常用参数逐个说先列一个速查表把高频参数和用途摆出来后面再展开讲容易踩坑的点。参数功能典型场景-S查看账户密码状态快速确认账户是否锁定、密码是否过期-l锁定账户临时禁用某个账户登录-u解锁账户解除锁定恢复登录-d删除密码使账户变为无密码状态仅建议用于特殊测试环境-e强制密码过期下次登录时必须先修改密码-x设置密码最大有效天数密码到期前必须更换-n设置密码最小修改天数两次改密之间的最小间隔-w设置到期前告警天数提前提醒用户密码即将过期-i设置宽限期密码过期后仍允许登录的天数--stdin从标准输入读取密码脚本和非交互改密的核心参数这里重点提醒一下--stdin。这个参数在绝大多数发行版中默认是不包含的需要额外确认。它的作用是让 passwd 直接从标准输入读取一行作为新密码而不是走交互式提示。正因为这个特性它成了自动化脚本的宠儿但也正因为它是从标准输入读密码如果使用时不注意管道和进程列表的可见性密码就可能在命令行参数或 shell 历史中暴露。具体防泄漏方案我在第四节专门聊。1.3 不带参数的交互流程日常手动改密直接敲passwd就行。系统会让你先输入当前密码非 root 用户然后输入新密码再重复一次确认。有一个细节很多人没注意新密码输入时终端不会回显任何字符连星号都不显示。这不是卡住了而是设计如此防止旁人偷窥密码长度。如果你是在 root 下执行passwd 用户名则可以跳过旧密码验证直接设置新密码。这个差异背后是 Linux 权限模型的基本逻辑root 拥有对 /etc/shadow 的写权限因此不需要证明自己是原密码持有者。实际操作中我建议所有人在首次登录一台新机器时做一次空跑演练用passwd -S看一眼自己的账户状态用passwd -e强制让自己下次登录改密然后退出重登。这套动作做完你对密码过期和密码状态查看这两个概念就有了肌肉记忆。2. 核心原理影子文件与密码存储机制2.1 /etc/shadow 的结构每个字段都别放过很多人知道 /etc/shadow 是存密码的但没仔细看过它的结构。为了后面排查问题方便我在这里拆开讲一遍。每一行由九个冒号分隔的字段组成以 root 用户为例root:$6$abc123$def...:19000:0:99999:7:::字段含义依次是用户名密码哈希值如果是!或!!开头表示账户被锁定或无密码最后一次修改密码的日期单位是从 1970-01-01 起的天数两次修改密码之间的最小间隔天数密码最大有效天数99999 表示永不过期密码过期前告警天数密码过期后的宽限天数账户失效日期留空表示不失效保留字段通常为空当你在脚本里或排障过程中发现密码改不动时第一件事就应该是查看这九个字段确定是哈希值没写进去还是过期策略字段出了问题。用awk或者cut就能快速提取没必要非用专门的工具。2.2 哈希算法与 $6$、$5$、$y$ 前缀上文提到/etc/shadow中的哈希值带有算法前缀这是 passwd 能否正常工作的关键。常见的前缀包括$1$MD5老系统还在用安全性已经不足$5$SHA-256部分系统默认$6$SHA-512多数现代 Linux 发行版的默认选项$y$yescrypt一些新发行版已经切换到这个算法不同发行版对默认哈希算法的选择不同例如某些新版本系统默认采用 yescrypt而另一些仍停留在 SHA-512。如果你手动生成哈希并写入 /etc/shadow必须确保算法与系统认证配置一致否则会出现密码看起来改了但登录总失败的诡异现象。更稳妥的做法是永远使用 passwd 命令来改密而不是手动编辑 /etc/shadow。手动编辑文件也许能绕过一些限制但也很容易把哈希格式写错或者破坏文件的权限和 SELinux 上下文给自己挖一个更大的坑。2.3 权限问题为什么普通用户能改自己的密码这个问题是我刚入行时一直没想明白的/etc/shadow 权限明明是 640 或 600普通用户连读都读不了怎么还能改自己的密码答案在于 passwd 命令本身的 setuid 位-rwsr-xr-x中的s表示这个程序在运行时会以文件属主root的身份运行而不是以调用者的身份运行。也就是说普通用户执行 passwd实际是让 passwd 这个程序临时获得了 root 权限然后由它来更新 shadow 文件。这个设计是出于安全考虑的最小授权用户只能通过 passwd 这个受控入口来修改自己的密码无法直接读取或篡改其他用户的哈希值。这也解释了为什么你不能直接修改其他用户的密码普通用户执行passwd 用户名系统会明确提示只有 root 才能指定用户名。这条权限边界是内核和程序共同维护的不要试图用sudo以外的办法去绕过它。如果你确实需要为其他用户改密请在 root 或 sudo 环境下操作。3. 实操全流程从手动改密到批量脚本落地3.1 手动修改密码的标准流程手动操作看似简单但步骤不能乱。我建议按这样的顺序执行减少误操作的概率登录系统后先用whoami确认当前身份。执行passwd修改自己的密码或sudo passwd 用户名修改指定用户密码。根据提示输入当前密码如果是 root 改别人则可跳过。输入新密码系统提示强度不够时会警告但不会强制拒绝取决于 PAM 配置。再次输入新密码确认一致后系统会输出类似passwd: all authentication tokens updated successfully的信息。这里有一个值得养成的习惯改完密码后立刻开一个新 SSH 会话用新密码登录验证一次确认无误后再关闭旧会话。因为一旦密码改错或遗忘旧会话又断了你就只能通过控制台或带外管理来恢复了。这个习惯帮我避免过至少三次改完密码把自己锁外面的事故。3.2 非交互改密脚本中如何使用 passwd自动化脚本里没法人工输密码最常见的做法是使用--stdin参数。基础写法如下echo NewPassword123 | passwd --stdin zhangsan这种写法能跑通但密码会出现在 shell 历史记录、进程列表和其他用户的临时文件中安全风险很高。更稳妥的改进方案是把密码存放在一个权限受限的文件里然后通过重定向传入passwd --stdin zhangsan /root/.secret/.passwd_zhangsan把密码文件放在 root 目录下权限设为 600这样进程列表里不会暴露密码历史记录也干净了。如果你使用的是 Debian/Ubuntu 系系统passwd默认可能不支持--stdin需要借助chpasswd命令来实现同样的目标echo zhangsan:NewPassword123 | chpasswdchpasswd 从标准输入读取用户名:密码格式的文本逐行处理非常适合批量场景。3.3 批量修改多个用户密码批量场景下推荐用 chpasswd 一次性处理多个用户效率远高于循环执行 passwd。准备一个文本文件每一行是用户名:新密码例如zhangsan:Passw0rd2024 lisi:NewPass123 wangwu:Welcome2024然后执行chpasswd /root/user_passwd.txt命令执行完毕后可以用下面的循环验证每个账户的状态while read user; do echo $user passwd -S $user done user_list.txt批量操作最大的风险是一刀切如果其中某个用户名写错了或者密码包含特殊字符在读取时被转义可能导致部分账户改密失败却没有任何提示。因此批量执行后必须逐一核对状态。我的做法是执行前先打印一份待处理清单执行后再对比前后状态确保没有漏网之鱼。3.4 强制过期与登录策略联动很多企业安全策略要求新员工首次登录时强制改密这个需求用passwd -e就能优雅实现passwd -e zhangsan这条命令会把该用户 shadow 文件中最后一次修改密码日期字段归零下次该用户登录时系统会提示密码已过期必须先设置新密码才能继续操作。等新员工设置完密码这个过期状态就会被自动清除。与passwd -e配套的策略参数还有# 设置密码最长使用90天提前7天告警 passwd -x 90 -w 7 zhangsan # 设置两次改密至少间隔3天 passwd -n 3 zhangsan # 设置密码过期后2天内仍可登录但会警告 passwd -i 2 zhangsan这些参数本质是在修改 /etc/shadow 中的第三、四、五等字段。好好利用它们你就能把密码生命周期管理做得像企业级目录服务一样规整而不需要额外安装任何管理软件。4. 实战排雷高频报错与排查实录4.1 报错password for user is not changed这句报错常见于非交互模式。可能是因为新旧密码完全相同也可能是 PAM 策略拒绝了这次修改比如密码长度不足、包含用户名、连续字符过多等。处理思路先用passwd -S 用户名查看当前状态和最后修改日期检查 PAM 配置文件通常位于 /etc/pam.d/passwd 和 /etc/security/pwquality.conf确认新密码符合复杂度要求后再重试我遇到的一个真实案例是某自动化任务连续一个月失败就是因为密码词典中包含了用户名片段被 pwquality 模块拦截。检查日志时才发现系统完全没有报错只是 passwd 返回了非零退出码而脚本没有捕获这个退出码。4.2 报错authentication token manipulation error这个报错通常发生在写入 /etc/shadow 阶段失败。可能的原因包括磁盘空间已满导致文件写入失败/etc/shadow 文件被意外修改过权限或属主passwd 无法写入文件系统处于只读挂载状态排查时先执行df -h确认磁盘空间再看/etc/shadow权限应当仅 root 可写最后用mount | grep / 检查根分区挂载选项。这三个方向基本能覆盖绝大多数情况。4.3 报错Cannot open file: /etc/shadow如果连 root 都遇到这个报错多半是系统环境出了问题比如容器内权限不足、SELinux 拦截、或者 shadow 文件被误删。在容器中运行某些基础镜像时shadow 文件可能不存在或为空需要先用pwconv生成对应的 shadow 条目。在物理机或虚拟机环境中这种情况极少见一旦出现建议立即检查文件完整性和系统日志。4.4 排查工具与速查表为了让大家遇到问题时少走弯路我把常用的查看命令整理成一个速查表需求命令查看自己密码状态passwd -S查看指定用户密码状态需 rootsudo passwd -S 用户名查看密码哈希算法awk -F: /用户名/ {print $2} /etc/shadow查看密码过期时间chage -l 用户名锁定账户sudo passwd -l 用户名解锁账户sudo passwd -u 用户名chage -l是一个容易被忽略但极其有用的命令它能以人类可读的格式展示密码过期时间最小间隔最大间隔告警天数等信息比直接看 shadow 文件的数字字段直观得多。我强烈建议排查密码策略问题时优先用 chage 做第一轮分析。5. 安全加固让 passwd 用得再稳一点5.1 密码强度与 PAM 配置默认情况下很多发行版的密码强度策略相对宽松。如果你管理的是一台生产服务器建议检查 /etc/security/pwquality.conf 中的几个关键参数minlen 12 dcredit -1 ucredit -1 lcredit -1 ocredit -1这几个参数的含义分别是最小长度12位新密码至少包含 1 个数字、1 个大写字母、1 个小写字母和 1 个其他字符。负数表示至少需要多少个正数表示最多允许多少个。把这些配置好后即使员工自己用 passwd 改密也会被强制要求遵守强度规则。5.2 避免在命令行暴露明文密码这是我最想强调的一点。网上能找到大量类似echo password | passwd --stdin user的示例但不少人忽略了进程列表的安全问题。当你执行这样的命令时虽然密码没有出现在命令行参数中但管道字符本身不会把密码暴露到 /proc 里。相对安全。但如果用下面这种写法密码就会暴露在进程列表中passwd --stdin zhangsan PlainTextPassword注这种用法本身就是错误的passwd 并不接受密码作为位置参数我只是用它来强调不要把密码写在命令行参数里的风险。脚本中用--stdin 重定向文件的方式配合chmod 600限定文件权限才是稳妥方案。5.3 警惕弱哈希与旧算法如果你手头维护的是老系统或者手动生成的哈希使用了$1$这种 MD5 前缀建议尽快规划升级。现代系统默认使用 SHA-512 或 yescrypt抗暴力破解能力强很多。判断当前系统默认算法最简单的方法是修改一次密码后查看/etc/shadow中哈希值的前缀。如果发现是$1$说明系统配置可能还停留在旧时代需要检查/etc/pam.d/system-auth或/etc/login.defs中的加密算法设定。5.4 root 密码丢失的救急思路如果你把 root 密码改了之后忘记了又没有任何免密通道只能走单用户模式或救援模式。不同发行版的处理方法略有差异但核心思路一致在引导过程中进入救援模式把根分区挂载为可写然后直接修改 shadow 文件或使用 chroot 环境执行 passwd。这些操作需要物理或带外控制台访问远程 SSH 是救不回来的。所以再次强调改完密码立刻验证别等会话断了才后悔。6. 自动化场景中的进阶用法与思考6.1 云主机批量初始化时的密码设置在云主机或容器平台的初始化脚本中经常需要为新用户设置初始密码。有些镜像自带 cloud-init它会调用类似 chpasswd 的工具来处理用户密码。如果你需要在自己构建的镜像里做同样的操作建议在脚本中显式调用 chpasswd而不是 passwd --stdin因为 chpasswd 在大多数发行版中都是标配还能避免 passwd 对--stdin支持不一致的问题。批量初始化时还有一个小技巧先用openssl passwd -6生成哈希再直接把哈希写入 /etc/shadow。这种方式更隐蔽也不会触发 PAM 的交互流程HASH$(openssl passwd -6 MySecret123) useradd -m -p $HASH zhangsanopenssl passwd -6中的-6表示生成 SHA-512 哈希生成的哈希值可以直接放到 useradd 的-p参数后面。这样做的好处是密码不会出现在 shell 历史中也不会被 passwd 命令的进程列表捕获。6.2 密码轮换任务的容错设计公司内部经常有每90天强制改密的合规要求运维同学通常会用 cron 或定时任务配合 chpasswd 批量轮换密码。这类任务必须设计好容错生成密码时使用openssl rand -base64 12确保强度记录每个用户改密前的状态和执行结果改密失败的要自动告警改密后立即用新密码执行一次 SSH 登录探测如果允许的话把所有日志集中存储避免改密后无法追溯我见过一个翻车案例脚本里用date %s生成随机种子导致所有用户的密码在一个特定时间段内完全相同。排查了一整天才发现问题是随机种子可控。密码生成一定要用足够随机的方式openssl rand是靠谱的别自己拼字符串。6.3 与集中身份认证系统的衔接在引入 LDAP 或企业级身份认证系统之后本地 passwd 命令的作用会弱化但依然有存在的必要至少 root 密码和紧急救援账户的密码还是要靠本地管理。两类密码体系并存时一个重要原则是本地账户作为应急通道密码必须足够复杂且定期更新不要与统一身份平台使用相同密码。否则一旦本地密码泄漏攻击者就拿到了一个绕过统一认证的后门。7. 我的实操心得与一些容易被忽略的细节写到这里该讲的机制和命令都讲得差不多了。最后分享几个我自己踩坑总结出来的小经验不一定写在哪本手册里但非常实用。第一个心得是改密后一定要看退出码。很多脚本里 pipeline 处理不当passwd 执行失败了但退出码被管道后面的命令覆盖导致任务显示成功。正确做法是设置set -o pipefail或者在执行后立刻检查$?。尤其是用 chpasswd 批量操作时直接看退出码比看输出靠谱得多。第二个心得是尽量不要直接手动编辑 /etc/shadow。即使在救援模式下我仍然优先用 chroot passwd 而不是 vi 去改哈希字段。原因很简单手抖改错一个字符账户就废了而找问题的时间远比执行一条命令要长。如果你是在应急状态下不得不手改至少先备份一份 shadow 文件。第三个心得是密码策略要设但别设死。有些企业把minlen改成 20 位并启用所有复杂度要求结果员工只能把密码写在便利贴上。密码策略的合理性需要平衡安全与可用性12位以上加常规复杂度要求已经能挡住绝大多数暴力破解过度限制只会催生反模式。第四个心得是关注 /etc/login.defs 里的全局默认值。你可以通过passwd -x给单个用户设置密码有效期但如果希望全系统默认生效就要改 /etc/login.defs 中的PASS_MAX_DAYS、PASS_MIN_DAYS、PASS_WARN_AGE。这个文件影响的是 useradd 新建用户时的默认值对已有用户不生效注意区分。最后想说的是passwd 看起来是个小命令但它是 Linux 账户安全最重要的入口之一。把这个入口的机制理解透再配合合理的策略和脚本容错你的系统和你的睡眠质量都会好很多。遇到问题别急着删库重装先看一眼 /etc/shadow 和日志多半能找到答案。