简介:这是一套用于 Rocky Linux 9.6 及 Red Hat Enterprise Linux 9.6、Oracle Linux 9.6、AlmaLinux 9.6 等红帽系发行版的一键升级包,聚焦 OpenSSH 与 OpenSSL 两个核心安全组件,主要帮助系统管理员快速修复 SSH 服务漏洞,省去手工编译的兼容性烦恼。压缩包内共包含 6 个文件,包括 5 个适用于 x86_64 架构的安装软件包和 1 个自动执行升级脚本,整体大小仅 10.75MB,覆盖服务端、客户端以及相关系统依赖组件,非常适合内网离线环境或批量服务器安全加固。完成升级后,OpenSSH 将更新至 10.2p1,OpenSSL 将更新至 3.5.4,两个版本均修复了已知安全漏洞并增强传输加密与身份验证强度;配合脚本引导,可平稳完成软件替换和原有配置保留,降低误操作风险。目前已有 142 人学习浏览,适用于等保合规加固、安全漏洞应急响应和版本统一管理等常见运维场景,推荐给具备基础 Linux 操作经验、追求稳定高效升级的运维人员。 前段时间接了个安全基线的整改单子,几十台Rocky Linux 9.6的机器扫出来OpenSSH和OpenSSL有中高危漏洞,客户给的窗口期又短。这种活干过一次的人都懂,最怕的不是编译报错,而是每台机器环境各不相同,编译安装一遍三五十分钟,滚完一遍得耗进去一两天。后来我干脆把OpenSSH 10.2p1和OpenSSL 3.5.4打成了RPM包,做了一套针对x86_64架构的rockylinux9.6-ssh10.2p1-ssl3.5.4-rpm-x86-64一键升级包,整个过程才算真正顺下来。这篇文章就把这套方案的思路、包结构、实操步骤和踩坑记录完整写出来,给同样被OpenSSH/OpenSSL漏洞升级折磨的朋友做个参考。
1. 为什么我说别再拿源码编译硬扛了(需求与方案选型)
1.1 系统自带版本到底够不够用
Rocky Linux 9.6自带的OpenSSH版本大概是8.7p1,OpenSSL是3.0.x。单纯从功能上说,日常用没啥大问题,但安全扫描工具和等保基线检查不会跟你讲情面,只要版本低于某个阈值,直接给你标红。尤其这两年OpenSSH和OpenSSL被挖出来的CVE一个接一个,从远程代码执行到信息泄露,评分一个比一个高,很多甲方在看到扫描报告后只给一句话“限期整改”。这时候如果你还抱着系统默认版本不放,整改单大概率过不了。
那是不是直接换最新版就行了?也不完全是。OpenSSH 10.2p1和OpenSSL 3.5.4都属于大版本跨级升级,改动非常多。升级完之后老客户端连不上、密钥登录失效、服务启动失败都是常规操作。如果没有一套完整的升级方案,很容易把自己锁在机器外面。我之前就见过有同事在跳板机上直接编译安装新版sshd,结果sshd服务起不来,远程会话一断,只能找机房的人帮忙重启,场面极其狼狈。
1.2 RPM包方案 vs 编译安装:这笔账要算清楚
在决定方案之前,我把源码编译和RPM包升级做了个对比。编译安装的灵活性的确高,能自己指定prefix,能选编译参数,但问题也非常明显:第一,每台机器都要装gcc、make、openssl-devel这一堆构建依赖,离线环境里凑齐这些包本身就是个灾难;第二,编译出来的文件散落在/usr/local/bin、/usr/local/etc这些目录,后续卸载、回滚全靠手动清理,稍不留神就残留一堆垃圾文件;第三,几十台机器逐台编译,时间成本根本扛不住。
RPM包方案的优势在于它把依赖关系和文件清单都记录在库里,升级、卸载、查询都走系统标准机制。我只需要在一台干净的构建机上把openssh和openssl的rpm包打出来,然后把包和脚本分发到目标机器上执行,一台机器三五分钟就能搞定。而且RPM包的卸载和回滚很干净,rpm -e一条命令就能回到之前的版本,万一升级出问题,不至于陷入“文件不知道装在哪”的尴尬。
从实际交付的角度看,甲方要的往往不是你“会编个最新版”,而是“能在规定时间内把几十台机器全部整改完”。这时候RPM批量升级就是唯一靠谱的答案。
1.3 这套一键升级包解决的核心问题
我最终确定的方案是:把OpenSSH 10.2p1和OpenSSL 3.5.4制作成适配Rocky Linux 9.6 x86_64的RPM包,再配一个自动检测、备份、安装、回滚的脚本,整体打包成一套rockylinux9.6-ssh10.2p1-ssl3.5.4-rpm-x86-64一键升级包。它主要解决四件事:
- 批量分发安装:不管机器在机房、云上还是内网隔离区,只要把包传上去跑一次脚本就完事。
- 离线可用:把所有依赖rpm都收集进包内,目标机不需要联网,也不需要配外部yum源。
- 紧急回退:升级前自动备份原配置文件,脚本里预留回滚入口,万一服务起不来能快速恢复。
- 应急通道:升级包内附带telnet-server的rpm,升级前先拉起telnet作为备用通道,防止SSH挂了人进不去。
2. 升级包内幕:包结构、依赖梳理与兼容性
2.1 包内结构一览
先展示一下这套升级包的主要目录结构,方便你理解整体的设计思路。
rockylinux9.6-ssh10.2p1-ssl3.5.4-rpm-x86-64/ ├── RPMS/ │ ├── openssh-10.2p1-1.el9.x86_64.rpm │ ├── openssh-clients-10.2p1-1.el9.x86_64.rpm │ ├── openssh-server-10.2p1-1.el9.x86_64.rpm │ ├── openssl-3.5.4-1.el9.x86_64.rpm │ ├── openssl-libs-3.5.4-1.el9.x86_64.rpm │ ├── openssl-devel-3.5.4-1.el9.x86_64.rpm │ └── telnet-server-*.x86_64.rpm ├── deps/ │ ├── zlib-*.rpm │ ├── pam-*.rpm │ ├── libedit-*.rpm │ └── krb5-libs-*.rpm ├── backup/ ├── upgrade.sh └── README.mdRPMS目录里放的是核心升级包,deps目录放的是可能缺失的依赖包,backup目录用来存放升级前的sshd_config、moduli、证书密钥等备份文件,upgrade.sh是自动安装脚本。telnet-server的rpm是应急通道用的,在升级sshd之前先启用telnet,建议只在临时整改期间开启,整改完成后立即停掉。
2.2 OpenSSH 10.2p1的关键变化与兼容性
OpenSSH 10.x相比8.x,默认行为变化非常大,升级后经常出现“旧客户端连不上新服务端”的情况。最典型的是这两点:
- 默认禁用了ssh-rsa(SHA-1)签名算法,老客户端如果还走
ssh-rsa公钥算法,会直接报no matching host key type found。解决方法是让老客户端升级到支持rsa-sha2-256/512的版本,或者在服务端sshd_config里临时加上HostKeyAlgorithms +ssh-rsa(不推荐,仅应急)。 - 废弃了旧的
ssh-dss、部分弱KEX算法,像diffie-hellman-group1-sha1这种在10.2p1里默认就不再支持。
另外,10.x对密钥文件的权限要求更严格,私钥文件如果权限过宽,sshd会直接拒绝使用。很多机器之前的/etc/ssh/ssh_host_*_key权限是644,升级后sshd启动时就报错。所以升级包脚本里专门加了权限修复的步骤,把私钥统一改成600,公钥改成644,防止这类低级问题。
2.3 OpenSSL 3.5.4升级注意事项
OpenSSL从3.0升到3.5,API层面变化不大,但要注意几个连带影响。第一,很多第三方软件(Nginx、Apache、Postfix、vsftpd这些)在编译时是动态链接libssl.so.3和libcrypto.so.3的,升级OpenSSL后这些服务未必会立刻出问题,但只要不重启,它们加载的还是旧版本OpenSSL。所以升级完OpenSSL,我的脚本里会强行提醒你重启所有依赖openssl的服务,或者干脆建议直接重启机器。别偷懒,这一步省不了。
第二,OpenSSL 3.x对配置文件openssl.cnf的解析更严格,老的配置里如果用了过时的语法,可能会在启动时打出warning甚至报错。我遇到过一个情况,Nginx配置了双向TLS认证,升级OpenSSL之后客户端访问时直接报no required ssl certificate was sent,排查半天发现是服务端配置的CA证书链不完整,系统里的CA bundle路径在OpenSSL 3.5里发生变化,需要重新指定SSL_CERT_FILE或在Nginx配置里显式声明证书链。这类问题不是RPM升级本身引起的,但升级会把它提前引爆。
2.4 依赖解析:离线环境怎么不翻车
做离线升级包最头疼的就是依赖收集。RPM的依赖关系不像源码编译那么随意,少一个依赖,rpm -Uvh就会直接拒绝安装。我制作这套包时,先用rpmspec和rpmbuild在干净的Rocky Linux 9.6构建机上把包打出来,然后用rpm -qpR逐个检查依赖,把所有可能缺失的依赖包全部收进deps目录。
常见的依赖包括zlib、pam、pam-devel、krb5-libs、libedit、openssl-libs等。这里有个小技巧:Rocky Linux 9.6的系统安装ISO里本身就带了大部分依赖的rpm包,如果你在不能外网的环境里,直接挂载ISO镜像当本地源用就行,不必非得去网上找。另外,千万别图省事用rpm -Uvh *.rpm --nodeps绕过依赖检查,那等于给后续埋雷,等哪天某功能突然崩了,你根本不知道是哪层依赖不对。
3. 实操:从零到一跑完整个升级流程
3.1 升级前必须做的三项检查
升级这种核心组件的操作,最忌讳拿到包就直接装。我每台机器都会先跑一遍检查,确认三件事:
先看当前版本,记录现场。
ssh -V openssl version -a cat /etc/redhat-release再看磁盘空间,RPM安装和备份都需要空间,低于5GB我会先清理。
df -h /最后最关键的一点,也是很多人忽略的:确认你当前是通过什么方式连接的机器。如果你只有一条SSH连接,最好先通过控制台、带外管理或临时启用telnet开一条应急通道,否则sshd重启失败的那一瞬间,你就失去这台机器的所有控制权了。我用的是telnet-server做兜底,虽然明文传输只用于应急,但有总比没有强。
3.2 一键升级脚本的执行过程
upgrade.sh的核心流程我用伪代码理一下,你一看就明白:
#!/bin/bash # 0. 检查用户、系统版本、架构 [ "$EUID" -ne 0 ] && { echo "请用root执行"; exit 1; } rpm -q rockylinux-release | grep -q el9 || { echo "仅支持Rocky Linux 9.x"; exit 1; } [ "$(uname -m)" = "x86_64" ] || { echo "仅支持x86_64架构"; exit 1; } # 1. 启用telnet应急通道(如果已经把telnet-server.rpm放进deps) rpm -q telnet-server || rpm -Uvh deps/telnet-server-*.rpm systemctl enable --now telnet.socket # 2. 备份关键配置 mkdir -p backup cp -a /etc/ssh/sshd_config backup/ cp -a /etc/ssh/moduli backup/ cp -a /etc/pki/tls/openssl.cnf backup/ # 3. 批量安装升级包 rpm -Uvh RPMS/*.rpm deps/*.rpm # 4. 修复可能出现的权限与SELinux问题 chmod 600 /etc/ssh/ssh_host_*_key chmod 644 /etc/ssh/ssh_host_*_key.pub restorecon -Rv /etc/ssh /etc/pki 2>/dev/null # 5. 重载配置并重启sshd sshd -t && systemctl restart sshd # 6. 验证版本 ssh -V 2>&1 openssl version中途如果rpm -Uvh里某个包因为依赖冲突报错,脚本会停下来并把错误信息打出来。正常执行完,你看到的结尾大概是这样的:
OpenSSH_10.2p1, OpenSSL 3.5.4 OpenSSL 3.5.4 9 Jul 2025 (Library: OpenSSL 3.5.4)3.3 升级后的第一件事:验证服务与恢复远程连接
脚本执行完不代表万事大吉。我会先开一个新的SSH连接窗口测试登录,确认能正常连上之后,再关闭旧会话。这一步的顺序不要搞反,旧会话一旦断掉而新连接还不稳定,你就只能在控制台前面哭了。
新连接验证通过后,立刻停掉telnet应急通道,防止明文协议暴露在网络上。
systemctl disable --now telnet.socket接着我还会再做一轮日常操作验证:试一下sudo切换、检查sshd状态、看journalctl里有没有报错。
systemctl status sshd journalctl -u sshd -n 50 --no-pager如果这些都没问题,才真正算升级完成。
4. 真实踩坑记录与排查速查表
4.1 sshd启动失败三连:权限、SELinux、配置语法
整个升级过程中,sshd启动失败是遇到概率最高的问题,而且失败原因往往就那么三类。
第一类是密钥文件权限问题。新版本对私钥权限有硬性要求,/etc/ssh/ssh_host_rsa_key、/etc/ssh/ssh_host_ecdsa_key、/etc/ssh/ssh_host_ed25519_key如果是644,sshd会直接退出。修法很简单:
chmod 600 /etc/ssh/ssh_host_*_key chmod 644 /etc/ssh/ssh_host_*_key.pub第二类是SELinux安全上下文错误。升级过程中如果文件被复制、解压又覆盖,可能导致/etc/ssh目录下的文件失去了正确的SELinux类型标签。检查方法:
ls -Z /etc/ssh/sshd_config如果类型不是ssh_config_t之类的正确标签,执行:
restorecon -Rv /etc/ssh第三类是配置语法错误。老版本能容忍的写法,新版本可能直接报错。比如某些机器在sshd_config里写了废弃的指令或格式不对的参数。好在新版本提供了很好的语法检查工具,重启前一定要先跑:
sshd -t有错误它会明确告诉你哪一行有问题,改完再重启,别直接systemctl restart sshd硬试。
4.2 客户端连接报错的几种典型场景
升级完服务端,客户端反而连不上了,这种问题最让人抓狂。常见报错和处理方式我整理成了速查表。
| 客户端报错 | 原因 | 处理办法 |
|---|---|---|
no matching key exchange method found | 老客户端不支持新服务端的KEX算法 | 客户端升级到较新版本,临时加-oKexAlgorithms=+diffie-hellman-group14-sha1 |
no matching host key type found | 客户端只提供ssh-rsa,服务端默认禁用 | 客户端升级,或在服务端临时加HostKeyAlgorithms +ssh-rsa |
packet length too long | 多半是代理、端口转发干扰或客户端连错端口 | 检查是否经过代理、端口号是否被占用,用nc -vz IP 22测试端口 |
Permission denied (publickey,password) | 密钥或密码认证均失败 | 检查PAM配置、PermitRootLogin、AllowUsers等限制 |
这里重点提醒一句:很多做运维的朋友喜欢在sshd_config里限制只允许wheel组的用户SSH登录,或者禁用root登录。这些配置在升级后依然有效,但如果PAM配置和sshd配置不匹配,会出现“密码明明正确但就是登不进去”的现象。排查时先临时把PermitRootLogin yes和AllowGroups注释掉试一下,确认是配置问题后再按需收紧。热搜里提到的“Bitvise SSH Server”“VSCode连接远程服务器”,本质也是同样的兼容性问题,旧的客户端保持更新就好。
4.3 密钥认证失效的解决办法
升级后密钥登录失效也是高频问题,尤其是历史遗留了几年的机器,用户目录下的权限往往乱七八糟。
先检查服务端日志:
journalctl -u sshd | grep -i "authentication"常见问题:.ssh目录权限是755、authorized_keys权限是644,新版本sshd对这些文件的权限检查更严格。规整权限的做法:
chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys chown -R $(whoami):$(whoami) ~/.ssh如果是root用户被限制登录,检查sshd_config里这几行:
PermitRootLogin prohibit-password AllowUsers root someone AllowGroups wheel还有种情况是升级后系统重新生成了host key,导致客户端的known_hosts存的指纹对不上。处理方式很简单,客户端删除对应的旧指纹重新连接即可:
ssh-keygen -R 服务器IP4.4 OpenSSL升级后连带服务的诡异问题
OpenSSL升级后出现的连带故障,往往比SSH本身更隐蔽。比如Web服务器、邮件服务器、数据库客户端都有可能在某个时刻突然报SSL相关错误。
我印象最深的是一个Nginx配置了客户端证书认证的服务,升级OpenSSL后客户端访问报no required ssl certificate was sent,看名字以为是客户端没发证书,查了半天发现是服务端的ssl_client_certificate指定的CA证书文件内包含了不完整的链,旧的OpenSSL能容忍,新版本解析更严格,直接判定证书无效。解决办法是把完整CA链拼进一个文件,并显式设置:
ssl_client_certificate /etc/pki/nginx/ca-chain.crt; ssl_verify_client on;另外一个高频报错是Git等客户端连HTTPS仓库时报error:0a0000c6:ssl routines::packet length too long。这通常是代理或者端口配置不对导致的,不是证书本身的问题。排查思路是先取消代理直连,确认端口正确,再看本机系统时间和证书有效期是否匹配。不要把大量时间浪费在重新安装证书上,先做排除法。
4.5 离线机器缺依赖怎么办
这套升级包在设计时已经考虑了大部分离线场景,deps目录里把常见依赖都收集齐了。但总有些特殊环境,比如最小化安装的机器,缺的依赖可能超出预期。如果有网,先执行一次dnf makecache再补装:
dnf install -y zlib-devel pam-devel libedit-devel krb5-devel如果是纯离线,最好提前在一台有网的Rocky Linux 9.6机器上把依赖包全部下载好,用createrepo做成一个本地源,然后目标机配置一个本地repo文件。这个方法不仅适用于x86_64的Rocky,也能帮助处理类似ARM架构的银河麒麟、欧拉系统的离线安装场景。只不过架构不同、系统不同,包不能混用,要单独用各自的构建环境重新打一套。
至于热搜里出现的“没找到rpm命令”这种问题,大概率是最小化系统里连rpm都没装。这在RHEL系操作系统里极其少见,真遇到了先dnf install -y rpm装回来再说。另外提醒一下,不要在挂载了CephFS、NFS等网络文件系统的目录下解压升级包,RPM的一些临时文件操作会被文件锁拖死,我就踩过一次,卡了十几分钟才反应过来。
写在最后:被大规模整改逼出来的经验
这套rockylinux9.6-ssh10.2p1-ssl3.5.4-rpm-x86-64一键升级包,本质上是把“安全基线整改”这个重复到令人烦躁的活儿,变成了一条流水线。做了几十台机器之后,我最大的体会是:搞运维的人,平时可以靠技术吃饭,但到了整改窗口面前,拼的往往不是技术新旧,而是流程是否顺畅、回退是否可靠、有没有给自己留后路。所以我每到一个新环境,都会先问三个问题:现在这个会话断了还能不能回来?配置文件有没有备份?sed和rpm的依赖心里有没有数?把这几个问题想清楚了,升级也就是一脚油门的事。最后再分享一个习惯:升级完的机器,我习惯在/root下留一份当次升级的日志文件和包名清单,下次扫描再出问题的时候,一眼就能看出当前跑的到底是哪个版本,省得又从头查一遍。
本文还有配套的精品资源,点击获取