三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Linux用户密码永不过期设置:从chage命令到login.defs配置详解

Linux用户密码永不过期设置:从chage命令到login.defs配置详解

1. 项目概述:从一次深夜告警说起

那天凌晨两点,我被一阵急促的短信提示音吵醒。监控系统显示,一台核心业务服务器的某个应用服务账号登录失败。睡眼惺忪地连上跳板机,ssh过去一看,熟悉的提示跳了出来:“Your password has expired”。得,又是一个用户密码过期了。这已经不是第一次了,尤其是在一些默认开启了密码过期策略的Linux发行版(比如某些CentOS、RHEL的默认配置,或者一些安全基线要求严格的镜像)上新建的用户,默认密码有效期可能就是90天。对于个人学习环境、测试服务器,或者一些跑着无人值守服务的系统账号来说,这种定期强制改密码的策略不仅没必要,还可能成为运维的“暗雷”——想象一下,一个定时备份脚本因为执行账号密码过期而突然失效,或者像开头那样,凌晨告警把你叫起来就为了改个密码。

所以,今天我们就来彻底解决这个问题:如何将Linux新用户的默认90天密码过期策略,修改为永不过期。这不仅仅是运行一两条命令,更重要的是理解Linux背后那套用户密码管理体系是如何运作的。我们会从最直观的命令行操作chage讲起,然后深入到配置文件/etc/login.defs和影子文件/etc/shadow,最后再聊聊如何一劳永逸地修改默认模板,让以后新建的用户都“天生”永不过期。无论你是刚接触Linux的新手,还是被这个问题困扰过的运维,这篇内容都能给你一个清晰、彻底的解决方案。

2. 密码过期策略的底层原理与核心命令

在动手修改之前,我们得先搞清楚Linux系统是怎么管理用户密码生命周期的。这就像你要调整一个机器的运行规则,总得先看懂它的说明书。

2.1 密码信息的存储地:/etc/shadow文件

所有用户密码(当然是加密后的)及其相关属性,都存放在/etc/shadow这个文件里。这个文件普通用户无权查看,只有root权限才能读取。我们可以用sudo cat /etc/shadow命令看一眼某个用户的记录,它的格式通常长这样:

username:$6$salt$hashedpassword:18659:0:99999:7:::

这一串由冒号分隔的字段,每个都有其特定含义,其中直接控制密码过期策略的主要是第5、6、7字段:

  • 字段1: 用户名。
  • 字段2: 加密后的密码(如果以!*开头,表示账号被锁定)。
  • 字段3: 上次修改密码的日期(从1970年1月1日算起的天数)。
  • 字段4: 密码最短有效天数(0表示随时可改)。
  • 字段5: 密码最长有效天数(也就是多少天后过期,99999是很多系统的默认值,表示永不过期)。
  • 字段6: 密码过期前多少天开始警告用户。
  • 字段7: 密码过期后,账号还能宽限几天不被禁用(-1表示永不过期后立即禁用?不,通常表示无限宽限)。
  • 字段8: 账号失效的绝对日期(从1970年1月1日算起的天数)。
  • 字段9: 保留字段。

我们的核心目标,就是修改第5个字段(密码最长有效天数)。把它改成99999这样的极大值,在人类尺度上就相当于永不过期了。

2.2 管理密码策略的瑞士军刀:chage命令

直接编辑/etc/shadow文件虽然高效,但容易因格式错误导致用户无法登录,风险较高。因此,系统提供了更安全的专用工具——chage命令。它的全称是“change age”,就是用来修改用户密码和账号“年龄”信息的。

chage命令功能强大,常用选项有:

  • -l: 列出指定用户的所有密码过期信息。
  • -m: 设置密码最短有效天数(对应shadow第4字段)。
  • -M: 设置密码最长有效天数(对应shadow第5字段,这是我们最关注的)。
  • -I: 设置密码过期后到账号被锁定的宽限天数(对应shadow第7字段)。
  • -W: 设置密码过期前多少天开始警告(对应shadow第6字段)。
  • -E: 设置账号失效的绝对日期(YYYY-MM-DD格式,对应shadow第8字段)。
  • -d: 设置上次修改密码的日期(0表示下次登录强制修改)。

注意chage命令需要root权限。对于非root用户,可以使用sudo来执行。

2.3 查看当前用户的密码状态

在修改之前,先诊断。使用chage -l命令,可以清晰地看到当前用户的密码策略详情。例如,查看testuser的状态:

sudo chage -l testuser

输出可能类似于:

Last password change : Mar 01, 2024 Password expires : May 30, 2024 Password inactive : never Account expires : never Minimum number of days between password change : 0 Maximum number of days between password change : 90 Number of days of warning before password expires : 7

这里清楚地显示,Maximum number of days...是90天,并且给出了具体的过期日期May 30, 2024。我们的任务就是把那个90改成99999

3. 修改现有用户的密码为永不过期

现在,我们进入实操环节。假设我们已经有一个用户appuser,它的密码即将在90天后过期,我们需要将其改为永不过期。

3.1 方法一:使用chage命令(推荐)

这是最标准、最安全的方法。只需一条命令:

sudo chage -M 99999 appuser

这条命令将用户appuser的密码最长有效天数设置为99999天(约273年)。执行后,再次使用chage -l appuser查看,会发现Maximum number of days...已经变成了99999,并且Password expires一项变成了never

参数解释与注意事项

  • -M 99999: 这里的99999是一个惯例值,代表“永不过期”。你也可以设置成其他更大的数字,但99999是公认的、安全的表示方式。
  • 立即生效:此修改是即时生效的,用户下次登录时就会应用新的策略。
  • 不影响已过期密码:如果用户的密码已经过期,执行此命令并不会自动解锁账号。你需要先让用户修改密码,或者由管理员使用chage -d 0 appuser强制其下次登录时修改密码,之后新的永不过期策略才会生效。

3.2 方法二:直接编辑/etc/shadow文件(高级操作)

如果你习惯于直接操作配置文件,也可以直接修改/etc/shadow。但务必小心,任何格式错误都可能导致用户无法登录。

  1. 使用vipw命令或sudo vi /etc/shadow打开shadow文件。推荐使用vipw,因为它会在编辑前对文件进行锁定和备份,更安全一些。
    sudo vipw -s
  2. 找到对应用户appuser的那一行。
  3. 定位到第5个字段(由冒号分隔),将其值从原来的数字(如90)修改为99999
  4. 保存并退出编辑器。

重要警告:直接编辑/etc/shadow风险极高。务必确保:

  1. 使用cp命令先备份原文件:sudo cp /etc/shadow /etc/shadow.bak
  2. 编辑时不要增减任何冒号,不要破坏字段结构。
  3. 如果不确定,强烈建议优先使用chage命令。

3.3 验证修改结果

无论用哪种方法,修改后都需要验证。除了用chage -l查看,还有一个快速命令可以检查密码过期状态:

sudo grep appuser /etc/shadow | cut -d: -f5

这个命令会直接输出appuser在shadow文件中的第5个字段值,如果显示99999,就说明修改成功了。

4. 一劳永逸:修改系统默认密码过期策略

解决了现有用户的问题,我们更希望防患于未然:让所有未来新建的用户,默认就是密码永不过期。这需要修改系统的用户创建默认配置。

4.1 核心配置文件:/etc/login.defs

/etc/login.defs这个文件定义了很多用户和组创建的默认规则。其中,就包括密码过期策略的默认值。我们需要修改其中几个关键参数:

sudo vi /etc/login.defs

找到并修改以下几行(如果不存在则添加):

PASS_MAX_DAYS 99999 PASS_MIN_DAYS 0 PASS_WARN_AGE 7
  • PASS_MAX_DAYS 99999: 新用户密码的最大有效期,设为99999天(永不过期)。
  • PASS_MIN_DAYS 0: 密码修改的最小间隔天数,0表示可以随时修改。
  • PASS_WARN_AGE 7: 在密码过期前7天开始警告用户。

修改后的影响:这个修改是前瞻性的,只对在此之后使用useradd命令(且不使用-M等覆盖参数)创建的新用户生效。它不会影响系统中已经存在的任何用户。

4.2 用户创建的模板:/etc/default/useradd

另一个可能影响默认值的文件是/etc/default/useradd。我们可以查看一下里面是否有关于过期时间的设置:

sudo cat /etc/default/useradd | grep -i expire

通常,这个文件里可能有一个EXPIRE=INACTIVE=的配置。但更常见、更全局的配置是在/etc/login.defs中。/etc/default/useradd主要定义的是家目录、shell、默认组等基础属性。

4.3 验证默认策略是否生效

修改完/etc/login.defs后,如何验证呢?最直接的方法是创建一个测试用户:

sudo useradd testnewuser sudo chage -l testnewuser

查看新用户testnewuser的密码策略,其Maximum number of days...应该显示为99999。验证完毕后,记得删除这个测试用户:sudo userdel -r testnewuser

5. 特殊场景与深度排查

在实际运维中,情况可能比单纯的修改数字更复杂一些。下面是一些你可能遇到的特殊场景和深度问题。

5.1 用户已处于密码过期状态怎么办?

如果用户密码已经过期,即使你修改了-M为99999,用户登录时仍然会被要求强制更改密码。此时有两种处理方式:

  1. 让用户自行修改密码:这是最合规的方式。用户通过SSH或控制台登录时,系统会提示输入新密码。
  2. 管理员强制重置“上次修改时间”:如果因为某些原因(比如服务账号),你需要让它立即恢复可用,可以使用以下命令:
    sudo chage -d 0 username
    这个命令将用户的上次密码修改日期设置为“纪元开始”(1970-1-1),这会导致系统认为密码已经过期太久,从而在用户下次登录时强制要求修改密码。对于服务账号,这之后你可以再把它改成一个固定的强密码。或者,更常见的做法是,对于服务账号,直接禁用密码登录,改用密钥认证,一劳永逸。

5.2 排查密码过期引起的连锁问题

密码过期不仅影响登录,还可能引发一些“诡异”的故障,这正是开头那个深夜告警的根源。

  • 场景一:Crontab定时任务失败如果以某个用户身份运行的cron作业,该用户密码过期,cron在执行任务时可能会因为无法验证用户身份而失败。检查系统日志/var/log/cron/var/log/syslog,可能会看到认证错误的信息。

  • 场景二:SFTP/SCP服务异常一些SFTP服务(如OpenSSH的sftp子系统)在用户密码过期后,可能会拒绝连接,即使使用密钥认证。错误信息可能比较模糊,例如“Connection closed”或“Authentication failed”。此时需要检查系统日志(/var/log/auth.log/var/log/secure)来确认是否为密码过期问题。

  • 场景三:基于PAM的应用程序故障任何通过PAM进行用户认证的应用程序(如某些FTP服务、Web控制台等),都可能因为密码过期而拒绝服务。排查时,应用程序自身的日志和系统的认证日志是关键。

通用排查思路

  1. 检查日志:第一时间查看/var/log/secure/var/log/auth.logjournalctl -u相关服务。
  2. 确认用户状态:使用chage -lpasswd -S-S显示密码状态摘要)快速诊断。
  3. 隔离测试:尝试直接以该用户身份执行一个简单命令,如sudo -u username whoami,看是否会提示密码过期。

5.3 企业环境下的平衡之道

在个人或测试环境中,我们可以大胆设置为永不过期。但在严格的企业生产环境或需要遵守等保、PCI DSS等合规要求的环境下,密码定期更换是强制要求。此时,一刀切的“永不过期”可能不合规。

更佳实践是精细化策略管理

  1. 区分账号类型
    • 交互式用户账号(如管理员、开发人员):保持合理的过期策略(如90天),并配合密码复杂度要求和密码历史记录(通过/etc/pam.d/system-auth配置)来提升安全性。
    • 服务/系统账号(如nginxmysqlapprunner):这些账号通常不用于交互式登录,应设置为密码永不过期(-M 99999),并且最好将其登录shell设置为/sbin/nologin/bin/false,并禁用密码登录,仅使用密钥或socket认证。这才是最安全的方式。
  2. 使用集中化管理工具:如果服务器数量多,可以考虑使用像LDAP、FreeIPA或微软AD这样的目录服务来统一管理用户和密码策略,这比在每台机器上手动修改要高效和一致得多。

6. 自动化脚本与批量操作

当需要管理的服务器或用户数量众多时,手动操作效率低下。这里提供两个简单的脚本思路。

6.1 批量修改现有用户为永不过期

假设你想把除了root之外的所有本地用户的密码策略都改为永不过期(请谨慎评估此操作的影响范围)。

#!/bin/bash # 批量修改所有非root、非系统用户密码永不过期脚本 # 使用前请务必在测试环境验证! # 获取所有普通用户(UID >= 1000,根据系统不同可能需调整) for user in $(awk -F: '$3 >= 1000 && $1 != "nobody" {print $1}' /etc/passwd); do echo "Processing user: $user" sudo chage -M 99999 "$user" # 可选:同时将密码过期警告也设为一个值 # sudo chage -W 7 "$user" done echo "批量修改完成。"

重要提醒:执行此类批量操作前,务必:

  1. 在测试环境充分验证脚本逻辑。
  2. 明确知晓脚本会影响到哪些用户。
  3. 做好备份,并准备好回滚方案。

6.2 在新服务器上自动应用默认策略

如果你经常需要初始化新的服务器,可以将修改默认配置的步骤写入自动化脚本(如Ansible Playbook、Shell初始化脚本)。

一个简单的Ansible任务示例:

- name: Set default password expiration policy to never expire lineinfile: path: /etc/login.defs regexp: '^PASS_MAX_DAYS' line: 'PASS_MAX_DAYS 99999' state: present become: yes - name: Ensure PASS_MIN_DAYS is set to 0 lineinfile: path: /etc/login.defs regexp: '^PASS_MIN_DAYS' line: 'PASS_MIN_DAYS 0' state: present become: yes

7. 常见问题与故障排除实录

在实际操作中,你可能会遇到下面这些“坑”。这里记录了我自己踩过或见过的一些典型问题。

7.1 执行chage命令报错“Permission denied”

问题:普通用户直接运行chage -l usernamechage -M ... username时,提示权限不足。原因与解决chage命令需要读取或修改/etc/shadow文件,该文件权限为-rw-r-----,所有者是root,只有root用户和shadow组可读。普通用户无权访问。

  • 查看信息:使用sudo chage -l username
  • 修改策略:必须使用sudo chage -M 99999 username

7.2 修改后用户登录仍提示密码过期

问题:已经用chage -M 99999修改了,但用户SSH登录时依然提示“Your password has expired”,要求更改。原因:这种情况通常发生在密码已经过期之后才去修改-M值。-M控制的是未来的过期时间,但无法追溯性地清除“已过期”的状态。解决

  1. 让用户按照提示输入旧密码,然后设置一个新密码。这是最直接的方法。
  2. 如果用户无法交互(如服务账号),管理员可以强制重置其密码修改日期,迫使其进入“必须改密码”的状态,然后由管理员为其设置一个新密码:
    sudo chage -d 0 username # 强制下次登录改密码 sudo passwd username # 管理员直接为用户设置新密码
    注意:有些发行版在chage -d 0后,即使用passwd改了密码,首次登录可能仍会要求更改。最稳妥的办法还是让该账号通过一次交互式登录流程。

7.3 忘记了root密码且已过期,无法sudo

问题:这是最棘手的情况之一。你的个人用户密码可能没过期,但root密码过期了,而你的个人用户又不在sudoers文件里,导致无法获取root权限来修改任何策略。解决:必须通过单用户模式或救援模式来重置root密码。

  1. 重启服务器,在GRUB引导菜单界面,按e键编辑启动参数。
  2. 找到以linuxlinux16开头的那一行,在行尾(在quiet参数之前)添加init=/bin/bash
  3. Ctrl+XF10启动。系统会直接进入bash shell,且拥有root权限。
  4. 此时文件系统通常是只读的,需要重新挂载为可写:mount -o remount,rw /
  5. 使用passwd root命令重置root密码。
  6. 执行sync命令同步数据,然后重启:exec /sbin/initreboot -f
  7. 重启后,用新root密码登录,再处理密码过期问题。

警告:此操作需要物理或虚拟控制台访问权限,对云服务器可能不适用(云平台通常提供控制台重置密码功能)。操作前请确认你有权限且了解风险。

7.4 PAM模块覆盖了默认策略

问题:明明修改了/etc/login.defschage设置,但新用户创建后密码策略还是不对。深度排查:除了login.defs,Linux的认证体系PAM也可能强制执行密码策略。特别是如果系统安装了libpam-pwqualitypam_cracklib等模块,并在/etc/pam.d/common-password/etc/pam.d/system-auth中配置了pam_unix.sorememberminlenmaxrepeat等参数,或者使用了pam_pwquality.so模块,它们可能会定义独立的密码生命周期规则。检查点

  1. 查看PAM配置:cat /etc/pam.d/system-authcat /etc/pam.d/common-password
  2. 寻找包含pam_unix.sopam_pwquality.so的行,看是否有类似maxage=90这样的参数。PAM的优先级有时会高于login.defs
  3. 如果存在冲突,需要根据实际情况调整PAM配置或login.defs配置,确保一致。

经过以上从原理到实操,从单个用户到默认配置,从普通场景到特殊故障的全面梳理,你应该已经能够游刃有余地处理Linux下的用户密码过期问题了。核心就是理解/etc/shadow的字段含义,熟练运用chage这个工具,并知道如何通过/etc/login.defs来定义未来。记住,对于生产环境中的服务账号,最好的安全实践是“禁用密码登录 + 使用密钥认证”,这远比纠结密码过期策略要来得根本和有效。

← 返回列表