RHEL 9系统救援:root密码重置与GRUB密码加固实战

发布时间:2026/10/26 11:16:12
RHEL 9系统救援:root密码重置与GRUB密码加固实战

1. 系统救援场景下的密码恢复整体设计思路

1.1 为什么重置root密码和GRUB密码要放在一起做

很多人在运维现场遇到的情况是这样的:一台跑了几年业务的生产服务器,root密码被前任工程师带走,或者交接文档里压根没记录;同时这台机器的GRUB引导菜单还是裸奔状态,任何能接触到物理机或带外管理口的人,重启时按一下方向键就能进单用户模式,等于系统安全形同虚设。这两件事本质上是同一个安全链条上的两个环节——root密码是系统内的最后一道门,GRUB密码是系统外的第一道门。只重置root密码而不锁GRUB,等于把钥匙换了但窗户还开着;只设GRUB密码而不确认root密码可用,万一引导参数改错连救援入口都进不去。

所以我把这两个操作合并成一次完整的救援流程来设计。核心思路是:先通过引导加载器的编辑能力拿到一个临时的、无需密码的root shell,完成密码重置;然后趁着手上有root权限,立刻把GRUB的编辑权限和引导参数锁定,形成闭环。这个顺序不能反——先设GRUB密码再重置root密码,会导致你下次想进救援模式时被自己设的密码挡住,虽然也能解,但多绕一圈。

1.2 方案选型:为什么走rd.break而不是init=/bin/bash

在RHEL 9这类使用systemd和SELinux的发行版上,重置root密码有几种常见路径,我逐一说明取舍逻辑。

第一种是传统的init=/bin/bash方式,在GRUB编辑界面把ro改成rw init=/bin/bash。这种方式能拿到shell,但它绕过了systemd的初始化流程,SELinux上下文不会被正确加载,/etc/shadow的标签可能出问题,改完密码后重启偶尔会遇到登录异常。而且RHEL 9默认开启SELinux enforcing,这种粗暴方式的风险明显偏高。

第二种是rd.break方式,在引导参数末尾加rd.break,系统会在initramfs阶段暂停,挂载的是只读的sysroot。这种方式的好处是initramfs环境干净、可控,通过mount -o remount,rw /sysroot重新挂载后,再用chroot /sysroot切进真实系统,此时SELinux的重新打标机制(/.autorelabel)可以正常触发。这是RHEL官方文档推荐的做法,也是我在生产环境反复验证过最稳的路径。

第三种是救援模式(Rescue Mode)从安装介质引导,适合系统完全无法引导的极端情况。但它需要额外的ISO或U盘,现场不一定具备,所以作为备选而非首选。

综合下来,rd.break是首选,理由是:不需要外部介质、不破坏SELinux上下文、步骤可逆、对文件系统损伤最小。下面所有实操都基于这条路径展开。

1.3 整体流程的四个阶段划分

我把整个救援过程拆成四个阶段,每个阶段有明确的输入输出,方便你在现场按节奏推进,也方便出问题时定位卡在哪一步。

  • 阶段一:引导中断与参数注入——在GRUB菜单阶段拦截引导,进入编辑模式,追加rd.break参数。
  • 阶段二:initramfs环境下的挂载与切换——重新挂载sysroot为可写,chroot进入真实根文件系统。
  • 阶段三:密码重置与SELinux打标——用passwd改密码,创建/.autorelabel触发重启后自动重打标签。
  • 阶段四:GRUB密码加固——系统正常启动后,用grub2-setpassword设置引导密码,并验证编辑权限已被锁定。

这四个阶段环环相扣,阶段三的/.autorelabel如果漏掉,阶段四重启后可能因为SELinux标签错乱导致服务起不来,这是新手最容易踩的坑,后面会详细讲。

2. 核心细节解析与实操前的关键准备

2.1 进入GRUB编辑界面的时机把握

RHEL 9默认的GRUB超时是5秒,而且很多云环境或带外管理口下,启动画面一闪而过。实操时我的习惯是:机器上电后立刻开始连续敲击Esc键(部分固件是Shift),不要等看到菜单再按。如果错过了,就等系统起来后reboot重来,别在启动过程中乱按其他键,容易触发固件层面的中断。

看到GRUB菜单后,光标停在默认启动项上,按e进入编辑模式。这里有个细节:RHEL 9的GRUB菜单可能显示的是Red Hat Enterprise Linux (9.0) ...这样的条目,你要编辑的是当前要高亮启动的那一项,别选错了内核版本。编辑界面里会看到以linux开头的一长行,这就是内核引导参数行。

注意:编辑界面是vi风格的简易编辑器,方向键可能不灵,用Ctrl+E跳到行尾更可靠。改完之后用Ctrl+X直接引导,不要用F10,某些固件下F10会被拦截。

2.2 rd.break参数的作用原理拆解

rd.break这个参数的字面意思是"在ramdisk阶段中断"。要理解它,得先知道Linux启动的大致链条:固件→GRUB→内核→initramfs(内存根文件系统)→切换根→systemd→用户空间。initramfs是一个临时的小型根文件系统,负责加载必要的驱动、挂载真实根分区,然后通过switch_root把控制权交给真实系统。

rd.break的作用就是在initramfs完成挂载、但还没执行switch_root之前,抛出一个调试shell。此时真实根文件系统已经被挂载到/sysroot目录下,但它是只读的。这个设计非常巧妙——只读挂载保证了你在救援过程中不会意外破坏数据,同时/sysroot路径让你能访问到真实系统的所有文件。

对比一下rd.break=pre-mount、rd.break=cmdline这些变体,默认的rd.break(等价于rd.break=pre-pivot)是最适合改密码的,因为此时根分区已经挂载好了,你不需要自己去找分区设备名。

2.3 实操前的环境确认清单

动手之前,花两分钟确认几件事,能省掉后面大量返工。

确认项检查方法不确认的后果
是否有带外管理或物理接触权限确认iDRAC/iLO/IPMI/KVM可用无法在GRUB阶段拦截
系统是否启用全盘加密回忆安装时是否勾选LUKS加密盘需先解锁才能进rd.break
是否有近期备份确认备份任务状态操作失误时无回退余地
是否记录当前GRUB配置启动后cat /etc/default/grub改错参数难以还原
业务是否允许重启确认维护窗口生产环境贸然重启影响业务

特别强调全盘加密这一项。如果根分区是LUKS加密的,rd.break阶段会先要求输入磁盘解锁密码,输对了才能继续。如果你连磁盘密码都没有,那这条路径走不通,只能考虑从备份恢复或重装。这个判断要在动手前做,别进了rd.break才发现卡在解锁环节。

2.4 SELinux上下文为什么必须重新打标

这是整个流程里技术含量最高、也最容易被忽视的点。RHEL 9默认SELinux策略是enforcing,每个文件都带有一个安全上下文标签(比如/etc/shadow的标签是shadow_t)。当你用passwd修改密码时,文件内容变了,但更关键的是——在chroot环境下,某些操作可能导致新写入的文件继承错误的标签。

/.autorelabel这个空文件是一个触发器。系统下次启动时,如果检测到这个文件存在,会在早期启动阶段对整个文件系统做一次完整的SELinux重新打标,然后自动删除该文件并再次重启。这个过程可能耗时几分钟到几十分钟(取决于文件数量),期间系统看起来像卡住了,其实是正常的。

提示:如果不创建/.autorelabel,轻则密码改了但登录被SELinux拒绝,重则系统启动后大量服务因标签错误无法启动。这个文件是保命的,千万别省。

3. 完整实操过程与核心环节实现

3.1 阶段一:拦截引导并注入rd.break参数

机器重启,在固件自检画面过后、GRUB菜单出现的瞬间,连续按Esc(或Shift)停住菜单。光标默认停在第一项,按e进入编辑。

找到以linux开头的那一行,它大概长这样(不同硬件略有差异):

linux ($root)/vmlinuz-5.14.0-70.el9.x86_64 root=/dev/mapper/rhel-root ro crashkernel=auto resume=/dev/mapper/rhel-swap rd.lvm.lv=rhel/root rd.lvm.lv=rhel/swap rhgb quiet

把光标移到行尾(Ctrl+E),在quiet后面加一个空格,然后输入rd.break。改完后这一行末尾应该是:

... rhgb quiet rd.break

按Ctrl+X引导。系统会快速滚过一堆initramfs的日志,最后停在一个提示符:

switch_root:/#

看到这个提示符,说明阶段一成功,你已经站在initramfs的调试shell里了。

3.2 阶段二:重新挂载sysroot并chroot切换

此时/sysroot是只读的,直接改密码会失败。先重新挂载为可写:

mount -o remount,rw /sysroot

这条命令的意图很明确:-o remount,rw是在不卸载的前提下改变挂载属性,比先umount再mount安全得多,因为根分区上可能有正在被引用的文件。执行后没有任何输出就是成功,Linux的哲学是"沉默即正常"。

接着切换根:

chroot /sysroot

chroot的作用是把/sysroot当作新的根目录,之后所有命令都在真实系统的文件系统里执行。切换后提示符会变成sh-5.1#之类的形式。此时你操作的/etc/shadow就是真实系统的那个文件,不是initramfs里的临时副本。

验证一下切换是否成功,可以看一眼:

ls /etc/redhat-release

能正常列出文件,说明chroot生效。

3.3 阶段三:重置root密码并触发SELinux打标

现在可以改密码了:

passwd root

系统会提示输入新密码两次。这里有个实操细节:RHEL 9默认的密码复杂度策略(pwquality)可能拒绝过于简单的密码,如果提示"BAD PASSWORD",要么换复杂点的,要么临时降低策略(不推荐在生产上这么做)。输入时屏幕不显示字符,这是正常的,别以为键盘坏了。

密码改完后,立刻创建打标触发器:

touch /.autorelabel

这一步不能忘。创建完可以用ls -la /.autorelabel确认文件存在。

然后退出chroot并重启:

exit reboot

如果reboot命令在initramfs环境下不响应(偶发),可以用reboot -f强制重启,或者直接按机箱电源键(前提是文件系统已同步,sync一下更保险)。

重启后系统会自动进行SELinux重新打标,屏幕会显示类似*** Warning -- SELinux targeted policy relabel is required ***的提示,然后自动再重启一次。这个过程中千万不要断电,打标中断可能导致文件系统标签处于半完成状态,后续排查非常麻烦。耐心等它跑完,看到正常登录提示符就说明root密码重置成功。

3.4 阶段四:用grub2-setpassword锁定引导编辑权限

用新密码登录root后,开始加固GRUB。RHEL 9提供了专门的工具grub2-setpassword,比手动改配置文件可靠得多。

直接执行:

grub2-setpassword

系统会提示输入GRUB用户名(默认root,可以直接回车)和两次密码。这个密码和系统root密码是独立的,可以设成一样方便记忆,也可以设成不同的增强隔离性。我个人的习惯是设成不同的,因为GRUB密码是在引导阶段明文交互的,泄露面比系统登录更大。

执行成功后,工具会在/boot/grub2/目录下生成user.cfg文件,里面存储的是密码的PBKDF2哈希,不是明文。你可以验证一下:

cat /boot/grub2/user.cfg

看到GRUB2_PASSWORD=grub.pbkdf2.sha512...这样的内容就对了。

3.5 验证GRUB密码是否真正生效

设完不算完,必须验证。重启机器,在GRUB菜单出现时按e,此时应该弹出用户名和密码的输入提示。如果还能直接进编辑界面,说明密码没生效,需要排查。

验证通过后,还要确认正常引导不受影响——输入正确密码后能进编辑界面,或者直接回车正常启动。这两点都确认了,整个加固才算闭环。

另外,如果你希望连"选择其他启动项"都受保护,可以检查/etc/grub.d/下的配置,确保grub2-mkconfig生成的配置里包含了密码保护逻辑。grub2-setpassword通常已经处理好了,但不同小版本行为略有差异,验证一步不能省。

4. 常见问题与排查技巧实录

4.1 问题速查表

现象可能原因排查与解决
按e没反应,直接启动了错过了GRUB菜单时机重启,上电即连续按Esc/Shift
rd.break后要求输入密码磁盘启用了LUKS加密输入磁盘解锁密码,无密码则此路不通
chroot后passwd报错sysroot未remount为rw重新执行mount -o remount,rw /sysroot
改完密码登录被拒漏了/.autorelabel重进rd.break补创建,重启打标
打标过程卡住很久文件数量多,正常现象耐心等待,切勿断电
grub2-setpassword命令不存在极简安装未装grub2-toolsdnf install grub2-tools后重试
设了GRUB密码仍能编辑配置未重新生成执行grub2-mkconfig -o /boot/grub2/grub.cfg
重启后GRUB密码失效引导分区被覆盖或重装重新执行grub2-setpassword

4.2 三个我踩过的坑

第一个坑:以为改完密码就万事大吉,结果SELinux把登录挡了。早期我图省事跳过/.autorelabel,密码确实改了,但登录时PAM报SELinux拒绝,日志里一堆avc: denied。后来老老实实补上打标流程才解决。这个教训让我养成了"改shadow必打标"的肌肉记忆。

第二个坑:在云主机上按Esc没反应。某些云平台的Web控制台会把Esc键映射成浏览器行为,根本传不到虚拟机。解决办法是改用Shift键,或者在控制台设置里切换键盘模式。如果都不行,用带外管理口的"发送Ctrl+Alt+Del"重启后立刻用Shift拦截。

第三个坑:grub2-setpassword设完,忘了验证,结果某次维护时发现密码根本没生效。原因是那次系统做过内核升级,grub.cfg被重新生成,而user.cfg的引用在某些配置下会丢失。从那以后我每次设完密码都强制重启验证一遍,并且在内核升级后复查GRUB保护状态。

4.3 一个容易被忽略的收尾动作

密码都设好之后,建议把这次操作的记录写进运维文档:包括重置时间、操作人、GRUB密码的保管方式(比如放进密码管理器)、以及/.autorelabel是否已自动删除(ls /.autorelabel应该报文件不存在)。这些记录在下次交接或审计时价值极高,比事后回忆靠谱得多。

另外,如果你管理的机器数量较多,可以考虑把GRUB密码的设置纳入标准化装机流程,用配置管理工具统一推送,避免每台机器手工操作带来的不一致。这个扩展方向我在几个环境里试过,效果比事后补救好得多。