在批量部署服务器的场景中,Kickstart无人值守安装是运维工程师的必备技能。但很多人忽略了一个致命细节:安装过程中设置的root密码、用户密码,如果直接以明文形式写在配置文件里,无异于把服务器大门钥匙直接挂在门把手上。任何能接触到这个kickstart文件的人,都能直接获取最高权限。解决这个问题的核心在于,必须对密码进行加密处理,并且要理解不同加密算法的强度差异。

CentOS系统在kickstart配置中支持多种密码设置方式,从最不安全的明文,到相对安全的MD5哈希,再到目前推荐使用的SHA-512哈希。直接写入明文密码是最偷懒的做法,比如在ks.cfg里写一句rootpw --plaintext MyPass123,这等于把密码完全暴露。稍微有点安全意识的人会用rootpw --iscrypted参数,后面跟加密后的字符串。但关键问题来了:这个加密字符串怎么生成,用什么算法生成,强度够不够。

很多人习惯用openssl passwd命令来生成密码哈希,默认情况下它使用的是MD5算法。在CentOS 7及更早版本中,MD5仍然是可用的,但在现代计算能力面前,MD5的碰撞脆弱性已经让它不再适合作为密码哈希算法。CentOS 8及更新的系统中,系统默认使用SHA-512算法,其哈希值以$6$开头标识。如果你在CentOS 8的kickstart文件里塞一个MD5哈希,安装程序虽然可能接受,但这会降低整体安全水位。

生成符合标准的SHA-512密码哈希

最可靠的方法是使用系统自带的工具生成高强度哈希。在已经安装好的Linux机器上执行以下命令,可以生成SHA-512加密的密码字符串:

python3 -c 'import crypt; print(crypt.crypt("你的密码", crypt.mksalt(crypt.METHOD_SHA512)))'

这条命令会输出一个类似$6$随机盐值$加密后的长字符串的结果。其中的$6$就是SHA-512算法的标识符。随机盐值由crypt.mksalt函数自动生成,每次执行都会产生不同的盐,所以即使是相同的密码,每次生成的哈希字符串也完全不同。这一点非常重要,因为盐值的存在让彩虹表攻击完全失效。

如果你的环境中没有Python,也可以用mkpasswd命令,这个命令通常包含在whois包中:

yum install whois -y
mkpasswd -m sha-512 你的密码

或者用openssl,但要明确指定算法为sha512:

openssl passwd -6 -salt 随机盐 你的密码

这里要特别说明-6参数,它代表SHA-512算法。很多旧教程里用的-1参数代表MD5,现在已经不推荐使用。盐值建议至少8位以上的随机字符串,包含大小写字母和数字,避免使用固定盐值。

在kickstart文件中正确配置加密密码

生成哈希字符串后,在ks.cfg文件中的写法是这样的:

rootpw --iscrypted $6$abc123def456$KJHBkjahsd87asd7a8sd87asd87asd87asd87asd87asd87asd87asd87

注意--iscrypted参数是必须的,它告诉安装程序这个密码已经是加密过的,不要再进行二次加密。如果漏掉这个参数,安装程序会把整个哈希字符串当作明文密码再加密一次,导致你安装完成后根本无法登录。

对于普通用户的密码设置,在kickstart的%post阶段添加用户时,同样需要处理密码。比如:

%post
useradd -m -p '$6$salt$hashedpassword' opsuser
%end

这里有一个容易踩的坑:单引号和双引号的区别。在bash中,单引号内的$符号不会被解释为变量,所以密码哈希字符串必须放在单引号内,否则shell会尝试解析$6等符号,导致密码设置错误。

加密算法的选择与安全层级分析

Linux系统密码哈希算法通过$id$前缀来标识,这个id数字直接对应算法类型。1代表MD5,2a代表Blowfish,5代表SHA-256,6代表SHA-512。在CentOS 7/8/9中,系统默认的密码哈希算法都是SHA-512,存储在/etc/shadow文件中的密码字段以$6$开头。

SHA-512相比MD5的优势不仅仅是哈希长度更长,更关键的是它内置了多轮迭代计算。默认情况下,SHA-512会进行5000轮哈希迭代,这个数字可以通过$6$rounds=轮数$的格式来调整。比如你想提高迭代次数到10000轮,可以这样生成:

python3 -c 'import crypt; print(crypt.crypt("密码", "$6$rounds=10000$" + crypt.mksalt(crypt.METHOD_SHA512)[3:]))'

增加迭代轮数会显著提高暴力破解的成本,但同时也会增加系统验证密码时的CPU消耗。对于大多数场景,默认的5000轮已经足够,除非你面临的是国家级攻击者的威胁模型。如果你管理的是高安全等级环境,建议将轮数设置为20000以上,但要注意这会让登录验证时有可感知的延迟。

kickstart文件本身的安全防护

密码加密只是安全链条上的一环。kickstart文件在安装过程中通常通过HTTP、FTP或者NFS协议从网络获取,这个传输过程如果没有加密,攻击者可以在网络层面截获整个配置文件。虽然密码是哈希过的,但攻击者拿到哈希后可以离线暴力破解。因此,强烈建议通过HTTPS来提供kickstart文件,并且在安装完成后立即删除或妥善保管这个文件。

另一个常见的安全隐患是kickstart文件残留。安装完成后,CentOS会把kickstart文件保存在/root/anaconda-ks.cfg,这个文件的权限默认是600,只有root可读。但如果你在%post阶段做了某些操作导致权限变更,或者系统被入侵后攻击者第一时间就会找这个文件。建议在%post阶段的最后加上清理操作:

%post
# 其他安装后配置...
# 最后清理kickstart文件中的密码信息
sed -i 's/rootpw.*/rootpw --iscrypted 已删除/' /root/anaconda-ks.cfg
%end

或者更彻底的做法是直接删除这个文件,但保留它对于后续审计和自动化运维有参考价值,所以用sed替换掉密码行是更平衡的选择。

无人值守环境下的密钥认证替代方案

在高度自动化的环境中,密码本身就是一个需要管理的秘密。更先进的实践是完全不使用root密码,转而使用SSH密钥认证。在kickstart文件中可以这样配置:

%post
mkdir -p /root/.ssh
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ..." > /root/.ssh/authorized_keys
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys
# 禁用root密码登录
sed -i 's/^PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
%end

这种做法从根本上消除了密码泄露的风险,因为私钥永远不会出现在kickstart文件中。但要注意,这要求你的密钥管理体系必须健全,私钥的保管和轮换要有严格的流程。

常见错误排查与验证方法

安装完成后验证密码是否正确设置,最直接的方法就是尝试登录。但如果无法登录,排查思路如下:首先检查/root/anaconda-ks.cfg文件中rootpw那一行的写法,确认--iscrypted参数是否存在,确认哈希字符串是否完整,没有因为shell转义而损坏。其次检查/etc/shadow文件中root用户的密码字段,看它是否以$6$开头,如果是以$1$开头说明用了MD5,如果以明文形式出现说明完全没有加密。

还有一个容易被忽略的问题:字符编码。如果你在Windows上用记事本编辑kickstart文件,然后上传到Linux服务器,可能会因为换行符差异或者BOM头导致安装程序解析异常。始终建议在Linux环境下编辑kickstart文件,或者使用支持Unix换行符的编辑器,并确保文件编码为UTF-8无BOM。

密码中的特殊字符也需要特别注意。如果密码包含$!"等shell敏感字符,在生成哈希时不会有问题,但在kickstart文件的%post脚本中使用时,必须正确转义或者使用单引号包裹。最稳妥的做法是密码中避免使用这些特殊字符,或者确保整个密码处理流程都在单引号保护下进行。

从CentOS 7到CentOS 8再到CentOS Stream,密码哈希的默认算法没有变化,都是SHA-512。但在Rocky Linux和AlmaLinux这些CentOS的替代发行版中,情况完全一致,本文的所有方法同样适用。如果你还在管理着CentOS 6这样的老旧系统,需要特别注意它默认使用MD5,必须手动指定SHA-512算法才能达到合理的安全水平。

在实际运维中,建议将密码哈希的生成过程脚本化,纳入配置管理工具中。例如在Ansible中可以用password_hash过滤器来生成SHA-512哈希,然后通过模板渲染到kickstart文件中。这样既保证了安全性,又避免了手动操作可能引入的错误。密码的明文永远不要出现在任何版本控制系统中,即使是私有仓库也不行。