这场劫难,从一份等保报告开始——一件运维的小事SSH升级

所有看似简单的运维操作,背后都有一个等着你跳的坑。 ------ 一个过来人的忠告,但通常你听过就忘,直到自己踩进去。


一个普通的周二下午

那天下午其实挺正常的。我刚巡检完一套系统,正在工位上跟同事扯淡,安全员小李走过来,表情微妙地递过来一份报告。

"张哥,等保测评的报告出来了。有几个高危漏洞需要修复。"

我心里毫无波澜------不就高危么,每年都一样,小 CASE!

我接过来翻了两页。得分还行,比去年有进步。正想说"不错不错",翻到漏洞清单那一页------

SSH 高危漏洞,OpenSSH 版本过低(CVE-2023-xxxx)。整改时限:15 个工作日。

我当时的表情大概经历了三个阶段:

第一阶段:哦,新系统嘛,正常都会有这个漏洞。 第二阶段:不就是升级个 SSH 嘛。 第三阶段:小事,10 分钟搞定一台。

Flag 已立好。后面的故事不出预料地,Flag 倒了!


自信的准备工作

ssh -V 看了一眼当前版本:

yaml 复制代码
OpenSSH_6.6.1p1, OpenSSL 1.0.1e-fips 11 Feb 2013

CentOS 7 自带的经典老款。都过了多少年了,也该升了。

上网查了一下最新稳定版本------OpenSSH_9.x。好家伙,从 6 到 9,跳了三个大版本。不过没关系,信心满满。

习惯性地先查了一圈资料,搜了几篇教程,大概流程都差不多:

  1. 装依赖
  2. 编译
  3. 替换
  4. 重启服务
  5. 完事

看起来毫无波澜。

我甚至还跟新同事说了一嘴:"SSH 升级,简单的,一会儿给你演示。"

------ 这句话后来成了我在这件事上说的最后悔的一句话,没有之一。


先试试 Yum 这条路

我一开始想走最简单的路:先试试 yum update openssh 能不能搞定。

结果系统告诉我没有可更新的包。CentOS 7 官方源里的 OpenSSH 早就停更了,7.4p1 就是尽头。

好吧,换阿里云的源试试。

先备份当前 yum 配置文件:

bash 复制代码
mkdir -p /etc/yum.repos.d/backup
mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup/

下载阿里云的配置文件:

bash 复制代码
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
chmod 644 /etc/yum.repos.d/CentOS-Base.repo

清理缓存并更新源:

bash 复制代码
yum clean all
yum makecache

啊哈!换源成功,这回可以试试升级了:

bash 复制代码
yum update openssh

结果只有 openssh 7.x 的包。不行,那试试 epel-release?

bash 复制代码
yum install epel-release
yum --enablerepo=epel update openssh

哦豁!不出所料,依然不是最新版本,而且新版 OpenSSH 依赖的 OpenSSL 版本跟系统自带的冲突了。

没办法了,只能上源码编译了。这条路终究躲不过去。


升级 OpenSSL:第一个连环坑

首先确保编译环境就位:

bash 复制代码
yum install -y "Development Tools"

下载 openssl-1.1.1w 源码,解压,./config,看起来一切正常。

然后 make -j$(nproc) && make install

编译完成!测试一下:

bash 复制代码
openssl version -a

显示版本为 OpenSSL 1.1.1w。OK!OpenSSL 升级完成!

但是------忘了检查其他应用会不会受影响。升级完关键库,其他依赖旧版 SSL 的服务会不会崩?

赶紧检查了一下。还好,其他应用没有异常,虚惊一场。但以后再升关键库,不能再这么鲁莽了。

确认新库的加载路径:

bash 复制代码
# 检查 ldconfig 能否找到新装的库
ldconfig -p | grep ssl
# 如果 /usr/local/lib64 不在搜索路径中,手动加一下
echo "/usr/local/lib64" > /etc/ld.so.conf.d/openssl-1.1.1w.conf
ldconfig

验证新版本:

bash 复制代码
/usr/local/bin/openssl version

输出正常:OpenSSL 1.1.1w

好,前置条件总算满足了。


正菜来了:编译 OpenSSH

下载 openssh-9.9p2 源码包,解压。

./configure 这一步是有讲究的。我查到的教程推荐这样:

bash 复制代码
./configure --prefix=/usr/local --sysconfdir=/etc/ssh
  • --prefix=/usr/local:装到独立目录,不覆盖系统原生 SSH
  • --sysconfdir=/etc/ssh:配置文件沿用原路径,不影响现有配置

然后 make && make install

编译通过了,没有报错,一切顺利。

等等,顺利得让我有点不安。

果然。我试着用另一个窗口 SSH 连接这台机器------

ssh: connect to host 192.168.x.x port 22: Connection refused

我盯着这个报错看了大概 3 秒钟,脑子里飞速闪过各种可能。

还好当前会话还连着。检查 sshd 状态:

bash 复制代码
systemctl status sshd

显示 active (running)

诶?那为什么连不上?

再仔细看看......

bash 复制代码
ps aux | grep sshd

发现了两个 sshd 进程:一个是 /usr/sbin/sshd(旧版),一个是 /usr/local/sbin/sshd(新版)。

两个 sshd 在打架。

旧版的 sshd 被 systemd 管着,开机就启动了,占着 22 端口。新版的 sshd 虽然装好了,但根本没跑起来------端口被占了,它起不来。

而且更坑的是,新旧两版的配置文件虽然都指向 /etc/ssh/sshd_config,但 OpenSSH 9.x 的配置项跟前几代有差异------有些参数废弃了,有些新参数旧版不认。如果旧版的 sshd_config 里有新版不兼容的配置,新版 sshd 直接拒绝启动,而且日志里给的错误信息特别隐晦。

关键问题:你没有告诉 systemd 要启动新版本的 sshd。

新版的 systemd 服务文件 /usr/lib/systemd/system/sshd.service 里写死的二进制路径还是 /usr/sbin/sshd(旧版)。我把新的二进制复制过去行不行?行,但下次 yum update 一跑,又被覆盖了。不是长久之计。


手动抢救

先把旧版 sshd 停掉:

bash 复制代码
systemctl stop sshd

确认端口释放了:

bash 复制代码
ss -tlnp | grep 22

没输出,端口已经释放。

手动启动新版 sshd:

bash 复制代码
/usr/local/sbin/sshd

没报错。检查进程确认:

bash 复制代码
ps aux | grep sshd | grep -v grep

新版 sshd 进程在跑了。

赶紧试另一个窗口------

连上了!

bash 复制代码
ssh -V

输出确认:

yaml 复制代码
OpenSSH_9.9p2, OpenSSL 1.1.1w  11 Sep 2023

成了。

长舒一口气。看看表,从开始到解决,用了将近 3 个小时。

说好的 10 分钟呢?


但等等

现在新版 sshd 只是被我手动跑起来的。如果机器重启了,systemd 还是会拉起旧版的 sshd。得把服务配置也改过来。

修改 /usr/lib/systemd/system/sshd.service,把 ExecStart 路径指向 /usr/local/sbin/sshd,然后重新加载并重启:

bash 复制代码
systemctl daemon-reload
systemctl restart sshd

确认服务正常:

bash 复制代码
systemctl status sshd

搞定。这才算真正升级完了。


本篇的教训(不吐不快)

你以为这就完了?天真。

就在我沉浸在"搞定了"的喜悦中时,手机震了。安全员小李发来一条消息:

"张哥,这次 SSH 漏洞涉及的主机我整理好了,你看看,一共 15 台。"

我盯着手机屏幕,嘴角的笑容慢慢凝固。

屏幕上那 15 行主机名,每一行都像在嘲笑我。

15 台。每台 3 小时。那就是 45 个小时。

我开始认真思考一个哲学问题:这个班是非上不可吗?

------ 下一篇,给你讲讲我是怎么从"一台 3 小时"进化到"十五台 1 小时"的。


📌 技术要点(给不想看故事的人):

这篇涉及的知识点,先列出来,后面会有专门的标准方案篇:

  1. 升级前先确认带外管理可用(iDRAC / iLO / IPMI),这是你翻车后的最后退路。云服务器的话,确认控制台能正常登录。
  2. 生产环境不建议用 yum update 跳大版本升级 SSH。 CentOS 7 官方源不会提供 OpenSSH 9.x,走源码编译几乎不可避免。
  3. 编译前先搞清新旧两者的安装路径差异。 默认安装(/usr)和独立安装(/usr/local)各有优劣。选了独立安装就要同时处理 systemd 服务文件的路径。
  4. 升级 OpenSSH 前可能要先升 OpenSSL。 这是最常见的连环依赖问题。注意 OpenSSL 新版本默认装到 /usr/local/,编译 OpenSSH 时要确认 ldconfig 能找到它。
  5. systemd 服务文件不会自动更新。 升级完记得改 sshd.service 里的二进制路径,然后 daemon-reload + restart
  6. 换源后检查文件权限。 curl 下载的 repo 文件可能没有读取权限,记得 chmod 644

下一篇:从一台到十五台------脚本化作战,批量升级的真实姿势

相关推荐
JAVA学习通4 小时前
《大营销平台系统设计实现》 - 营销服务 第8节:抽奖规则树模型结构设计
运维·决策树·docker·容器·责任链模式
Keano Reurink4 小时前
长尾关键词自动化扩展:从1个种子词到1000个长尾词
运维·windows·自动化
自由且自律4 小时前
cenph三大存储方式
运维·经验分享·ceph
Bert.Cai4 小时前
Linux tee命令详解
linux·运维·服务器
宋浮檀s4 小时前
应急响应(系统日志)
linux·运维·网络安全·应急响应
老卢聊运维4 小时前
kdc-server部署kerberos认证
大数据·运维·hdfs
feasibility.5 小时前
nvidia-smi 失灵,显存凭空消失?—— NVML 驱动版本错配的记录
linux·运维·服务器·经验分享·nvidia·驱动
basketball6166 小时前
Linux sed 和 awk 命令使用方法
linux·运维·chrome
一拳一个娘娘腔6 小时前
Linux SSH免密登录:从“刷卡进门”到“刷脸通行”的完整指南
linux·运维·ssh