ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

RHEL 9.0 root密码重置与GRUB密码配置全攻略

RHEL 9.0 root密码重置与GRUB密码配置全攻略

系统管理员最怕的场面之一,就是接手一台前任同事留下的服务器,root 密码写在交接文档里但文档找不到了,或者更糟——密码就在脑子里,但脑子那天恰好不在状态。RHEL 9.0 在这件事上比前几代又多了几道门槛,SELinux 策略收紧、GRUB 配置路径调整、rd.break打断点之后挂载参数的变化,都让"照着老教程敲一遍"这种做法变得不太靠谱。这篇内容就是围绕RHEL 9.0 下重置 root 密码并顺手把 GRUB 密码配上这条完整链路展开的,从打断点进 initramfs、重新挂载根分区、处理 SELinux 上下文,到grub2-setpassword的实操和几个容易翻车的细节,都会讲到。适合手里有 RHEL 9 系机器、需要做密码恢复或安全加固的运维人员,也适合刚接触 RHEL 9、想搞清楚启动流程底层逻辑的朋友。下面这些步骤我在多台测试环境里反复跑过,踩过的坑会一并标出来。

1. 动手之前先搞清楚 RHEL 9 的启动链路

很多人拿到"重置 root 密码"这个任务,第一反应是搜一条命令然后照抄。但 RHEL 9.0 和 RHEL 7/8 在启动早期阶段的行为差异不小,不理解链路就动手,很容易卡在某个环节不知道下一步该干嘛。所以先把启动过程拆开看。

1.1 从 GRUB 到 initramfs 再到真实根分区

机器加电后,固件完成自检,把控制权交给引导程序。RHEL 9 默认用 GRUB2 作为引导器,GRUB 读取/boot/grub2/grub.cfg(BIOS 环境)或/boot/efi/EFI/redhat/grub.cfg(UEFI 环境),把内核和 initramfs 镜像加载进内存。内核启动后,先执行 initramfs 里的初始化脚本,这个微型根文件系统里带着挂载真实根分区所需的驱动和工具。等真实根分区挂载完成,才切换到systemd接管后续服务。

关键点在于:initramfs 阶段真实根分区是以只读方式挂载的。这是很多人第一次操作时最困惑的地方——明明用passwd改了密码,重启后却提示认证失败。原因就是只读挂载下对/etc/shadow的写入没有真正落到磁盘上,或者落到了但 SELinux 上下文不对导致登录时被拦。理解这一点,后面mount -o remount,rw /sysroot这步的意义就清楚了。

1.2 rd.break 到底打断了什么

GRUB 编辑界面里在linux行末尾加rd.break,作用是让内核在 initramfs 阶段、切换到真实根分区之前停下来,给你一个switch_root之前的 shell。这个 shell 运行在 initramfs 环境里,此时真实根分区挂在/sysroot下,但还没被切换成/。所以你在这一步做的所有操作,都是针对/sysroot这个路径下的文件系统,而不是直接对/。

这和init=/bin/bash那种方式有本质区别。init=/bin/bash是让 bash 直接替代 systemd 作为 1 号进程,此时根分区已经切换完成,但很多服务没起来,SELinux 也可能处于半加载状态。RHEL 9 上我更推荐rd.break,因为它停得更早、环境更干净,对 SELinux 上下文的处理也更可控。两种方式都能用,但rd.break的确定性更高,尤其是在启用了 SELinux enforcing 的机器上。

1.3 为什么 RHEL 9 要特别关注 SELinux 上下文

RHEL 9 默认 SELinux 处于 enforcing 模式。/etc/shadow这个文件的 SELinux 类型是shadow_t,如果你在 initramfs 环境下用某些方式创建或覆盖文件,新文件的上下文可能变成unlabeled_t或者继承父目录的默认类型,登录时 PAM 读取 shadow 就会被 SELinux 拒绝,表现就是密码明明改对了却登不进去。所以重置密码之后必须补一步touch /.autorelabel,让系统下次启动时对整个文件系统重新打标签。这一步在 RHEL 7 时代经常被省略也能过,但 RHEL 9 上省略它的翻车概率明显更高,我建议养成习惯,别省。

2. 重置 root 密码的完整操作链路

这一节把从重启到验证的每一步拆开讲,包括每一步的意图和可能遇到的意外。操作环境以 UEFI + SELinux enforcing 的 RHEL 9.0 为准,BIOS 环境差异会在对应位置标注。

2.1 进入 GRUB 编辑界面并追加 rd.break

重启机器,在 GRUB 菜单出现时(默认停留 5 秒,手速不够的话可以提前在/etc/default/grub里把GRUB_TIMEOUT调大,或者开机时连按方向键打断倒计时),选中默认启动项,按e进入编辑模式。

找到以linux开头的那一行(UEFI 环境下可能是linuxefi,RHEL 9 统一用linux),光标移到行尾,加一个空格,然后输入:

rd.break

注意不要动这一行里已有的其他参数,尤其是ro和rhgb quiet,改了可能影响后续判断。加完之后按Ctrl+X启动。

提示:如果 GRUB 菜单本身已经被密码保护,这一步会先要求输入 GRUB 用户名和密码。这正是本文后半部分要配置的东西,如果你现在连 GRUB 密码都不知道,那就得先走一遍"清除 GRUB 密码"的流程,或者用救援介质引导,那是另一条路径了。

2.2 重新挂载 sysroot 为可写

进入紧急 shell 后,提示符通常是switch_root:/#。此时先确认一下挂载状态:

mount | grep sysroot

正常会看到/dev/mapper/rhel-root on /sysroot type xfs (ro,relatime,...)这样的输出,注意那个ro。接着执行:

mount -o remount,rw /sysroot

这一步把/sysroot从只读改成可读写。为什么要 remount 而不是直接 umount 再 mount?因为 initramfs 环境下/sysroot是后续switch_root的目标,直接卸载会破坏启动流程的预期状态,remount 是更安全的做法。执行完再mount | grep sysroot确认ro变成了rw。

2.3 chroot 进入真实系统并改密码

chroot /sysroot

执行后提示符会变化,你现在的/就是真实根分区了。接着:

passwd root

按提示输入两次新密码。这里有个细节:RHEL 9 默认的密码质量策略(pwquality)比较严格,如果密码太短或太简单会直接拒绝。如果你只是想临时恢复访问、后续再改,可以在 chroot 环境里临时绕过,但我不建议在生产机上这么干,老老实实设一个符合策略的密码更省事。

改完之后,立刻执行:

touch /.autorelabel

这一步就是前面说的 SELinux 重打标签。/.autorelabel这个标记文件存在时,系统下次启动会在systemd的早期阶段触发selinux-autorelabel服务,对整个文件系统重新计算安全上下文。代价是重启会慢一些(大文件系统可能要几分钟),但换来的是登录不会被 SELinux 拦。

然后退出 chroot 并重启:

exit exit

第一个exit退出 chroot,第二个exit让 initramfs 继续走完switch_root流程。有些教程会让你在第二个 exit 之前执行mount -o remount,ro /sysroot,实测在 RHEL 9 上不是必须的,系统会自己处理,但如果你追求稳妥,加上也无妨。

2.4 重启后的验证与常见异常

系统重启过程中会看到 SELinux relabel 的进度输出,耐心等它跑完。起来之后用新密码登录 root,验证通过就说明主流程走通了。

如果登录失败,按现象排查:

现象可能原因处理方式
密码正确但提示认证失败SELinux 上下文不对确认/.autorelabel是否生效,检查/etc/shadow的上下文
提示密码错误只读挂载导致写入未落盘重走流程,确认 remount 成功后再改密码
系统卡在启动relabel 未完成或中断等待完成,不要强行断电
GRUB 阶段就进不去GRUB 密码已启用需先处理 GRUB 密码,见下一节

/etc/shadow的上下文可以用ls -Z /etc/shadow检查,正常应该是system_u:object_r:shadow_t:s0。如果显示unlabeled_t,说明 relabel 没跑成功,可以手动执行restorecon -v /etc/shadow修复。

3. 给 GRUB 加密码:不只是设个口令那么简单

root 密码能重置这件事本身就是个安全隐患——任何人只要能物理接触到机器、能进 GRUB 编辑界面,就能用rd.break把密码改掉。所以重置完密码之后,紧接着给 GRUB 加密码是顺理成章的安全加固动作。RHEL 9 提供了grub2-setpassword这个工具,比早期手动改grub.cfg的方式规范得多。

3.1 grub2-setpassword 做了什么

执行grub2-setpassword后,工具会交互式要求输入两次密码,然后把密码的 PBKDF2 哈希写入/boot/grub2/user.cfg(BIOS)或/boot/efi/EFI/redhat/user.cfg(UEFI)。同时它会确保grub.cfg里有对应的source语句去加载这个文件。注意它写入的是哈希不是明文,user.cfg的权限默认是 600,只有 root 可读。

这里有个容易误解的点:grub2-setpassword设置的是GRUB 超级用户密码,默认超级用户名是root。也就是说,GRUB 菜单里需要输入的用户名是root,密码是你刚设的那个。这跟系统 root 密码是两回事,可以不同,也建议不同——GRUB 密码泄露的影响面比系统密码小,但也没必要复用。

3.2 实操步骤与配置验证

在正常启动的系统里,用 root 执行:

grub2-setpassword

按提示输入两次密码。完成后验证配置文件:

cat /boot/grub2/user.cfg

应该能看到类似GRUB2_PASSWORD=grub.pbkdf2.sha512.10000.xxxx...的内容。再确认grub.cfg里有加载语句:

grep -n "user.cfg" /boot/grub2/grub.cfg

UEFI 环境下路径换成/boot/efi/EFI/redhat/。如果grub.cfg里没有对应的source行,说明工具没自动写入(某些定制镜像会这样),需要手动在grub.cfg的合适位置加一行:

source ($root)/user.cfg

但更规范的做法是改/etc/grub.d/下的模板再重新生成grub.cfg,避免下次内核更新时被覆盖。具体来说,/etc/grub.d/01_users这个脚本负责生成用户相关配置,可以检查它是否存在且可执行。

3.3 密码策略与哈希算法选择

grub2-setpassword默认用 PBKDF2-SHA512,迭代 10000 次,这个强度对 GRUB 场景足够了。如果你有合规要求需要调整,可以手动生成哈希再写入user.cfg,用grub2-mkpasswd-pbkdf2命令:

grub2-mkpasswd-pbkdf2

它会要求输入密码和盐值迭代次数,输出完整的grub.pbkdf2.sha512.10000.xxx字符串,你把它填到user.cfg的GRUB2_PASSWORD=后面即可。迭代次数调高会增加暴力破解成本,但 GRUB 启动时验证也会稍慢,10000 到 50000 之间是比较平衡的区间。

注意:user.cfg里存的是哈希,但哈希本身也是敏感信息,权限务必保持 600,属主 root。可以用ls -l确认,如果权限不对,chmod 600修正。

4. 那些教程不会告诉你的翻车点

前面两节是标准流程,但真实环境里出问题的往往不是主流程,而是边角情况。这一节把我在实际操作中遇到过、以及同行反馈过的高频问题集中列一下,每个都给出排查思路。

4.1 只读挂载的坑比想象中深

最常见的翻车就是忘了mount -o remount,rw /sysroot,或者执行了但没确认结果。表现是passwd命令看起来成功了,没有任何报错,但重启后密码没变。原因是只读文件系统上passwd对/etc/shadow的写入进了页缓存但没落盘,或者被文件系统层静默丢弃。

排查方法很简单:改完密码后、退出 chroot 之前,执行cat /etc/shadow | grep root看一眼 root 那一行的哈希有没有变化。如果哈希还是旧的,说明写入没生效,回去检查 remount。这个习惯能帮你省掉一次无谓的重启。

4.2 SELinux relabel 没跑完就断电

touch /.autorelabel之后重启,relabel 过程可能持续几分钟。有些人在虚拟机里看到黑屏或者进度条不动,以为卡死了就强制重启,结果 relabel 中断,文件系统处于部分标记状态,后续各种权限问题。正确做法是耐心等,relabel 完成后系统会自动重启一次。

如果已经中断了,补救办法是进单用户模式或者用rd.break再touch /.autorelabel一次,让它重新跑完整。实在不行可以在 GRUB 里临时加selinux=0启动进去修复,但修完记得改回来,别让 enforcing 长期关着。

4.3 GRUB 密码设了但没生效

grub2-setpassword执行成功、user.cfg也生成了,但重启后 GRUB 菜单照样能直接编辑,不要求密码。这种情况通常是grub.cfg没有正确 sourceuser.cfg。检查grub.cfg里有没有source语句,以及路径对不对。UEFI 环境下$root的解析可能和预期不同,可以改成绝对路径试试。

另一个可能是grub.cfg被重新生成过(比如内核更新触发了grub2-mkconfig),而生成脚本没有包含用户配置。所以改完密码后,最好跑一次grub2-mkconfig -o /boot/grub2/grub.cfg(UEFI 路径对应调整),确保配置一致。

4.4 忘记 GRUB 密码之后的处理

如果 GRUB 密码设了但忘了,而系统 root 还能登录,处理起来不难:直接重新执行grub2-setpassword覆盖即可。麻烦的是 root 也进不去、GRUB 又被锁的情况,这时候只能靠救援介质(安装 ISO 的 rescue 模式)引导,挂载真实根分区后手动清理user.cfg或者重设。所以设 GRUB 密码时一定要把密码记到可靠的地方,别只存在脑子里。

5. 把密码恢复能力变成可复用的运维习惯

单次重置密码是个一次性任务,但"能快速、可靠地恢复访问"这件事应该沉淀成团队的习惯。这一节聊聊怎么把上面的流程固化下来,减少下次手忙脚乱。

5.1 写一份自己的操作清单

标准流程容易记混顺序,尤其是 remount 和 autorelabel 这两步的位置。我习惯在内部文档里维护一份带勾选框的清单,大致长这样:

  1. 重启,GRUB 菜单按e
  2. linux行尾加rd.break,Ctrl+X
  3. mount -o remount,rw /sysroot
  4. chroot /sysroot
  5. passwd root
  6. touch /.autorelabel
  7. exit两次,等待 relabel 完成
  8. 验证登录,检查/etc/shadow上下文
  9. 视需要执行grub2-setpassword

清单的价值在于,紧急情况下人的注意力容易窄化,盯着一个步骤忘了下一步。有清单照着走,出错率明显下降。

5.2 测试环境先演练一遍

RHEL 9.0 的小版本之间也有细微差异,比如某些 update 版本调整了 initramfs 的默认行为。所以在正式对生产机操作前,在测试环境完整走一遍流程,确认每一步的输出符合预期。特别是 SELinux 相关的行为,不同安装选项(最小化安装 vs 带 GUI 安装)下 relabel 的耗时和表现可能不同,提前摸清楚心里有底。

5.3 密码管理与审计的配合

GRUB 密码和 root 密码都应该纳入统一的密码管理流程,而不是散落在个人笔记里。同时建议开启auditd对关键文件的监控,比如对/etc/shadow和/boot/grub2/user.cfg的写入操作记审计日志。这样即使有人走了rd.break流程改密码,事后也能从审计日志里发现痕迹。配置一条简单的 audit 规则:

auditctl -w /etc/shadow -p wa -k shadow_change auditctl -w /boot/grub2/user.cfg -p wa -k grub_pwd_change

把这两条写进/etc/audit/rules.d/下的规则文件,重启后依然生效。这样密码相关的变更就有了可追溯的记录,对安全运维来说是很实用的一层保障。

我个人在实际操作中的体会是,RHEL 9 的密码恢复流程本身不复杂,复杂的是那些"看起来成功了其实没成功"的隐性失败。养成改完密码先cat /etc/shadow确认、重启后先ls -Z检查上下文的习惯,能挡掉大部分返工。GRUB 密码这块,设完之后一定要实际重启验证一次,别设完就当完事——我见过不止一次设了密码但grub.cfg没正确加载、等于白设的情况。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进