ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CentOS7升级OpenSSH避坑指南:从编译到回滚全流程

CentOS7升级OpenSSH避坑指南:从编译到回滚全流程 简介一份面向CentOS7系统升级OpenSSH 10.0p2与OpenSSL 3.0.16的代码与文档资源包专为需要提升服务器远程连接安全性的运维工程师准备尤其适合无网络或远程升级场景。压缩包共3个文件大小仅6KB内含HTML格式的图文升级指南、inscode工程入口文件及.gitignore配置辅助文件HTML步骤清晰可逐项对照inscode便于快速进入实验环境.gitignore则辅助工程版本管理。资源完整覆盖升级全链路建议先开启telnet保底登录随后完成依赖安装、zlib/OpenSSL/OpenSSH的下载编译与旧版备份、动态库链接配置并针对sshd无法正常启动给出权限调整、日志检查和链接确认等排错方法。已有115人学习下载可帮助读者避开编译兼容性坑点在升级失败时快速回滚是一份轻量但操作性很强的现场参考。1. CentOS7 升级 OpenSSH别让编译成功变成失联的开始CentOS7 升级 OpenSSH 这件事很多人以为是编译问题其实最大的风险是把自己锁在门外。手头一批内网服务器还跑着 OpenSSH 7.4p1安全扫描报了一串高危 CVE等保整改又要求服务端和客户端的算法协商到新标准可 SSH 往往是唯一的远程通道一旦升级过程翻车轻则服务起不来重则只能去机房。这篇文章按我实际维护的顺序来写先摸清版本和依赖再编译替换把常见的 SELinux、PAM、算法兼容这些坑一个个排掉最后给出一套可回滚的验证流程。适合做安全加固、处理漏洞报告、或者管理一堆 CentOS 7 老机器的运维照着这套走能少踩一半的坑。2. 升级前把版本号和依赖摸清楚少跑一趟机房动手之前先确认现状这一步看着简单但很多人直接跳到下载源码结果编译到一半发现 OpenSSL 版本对不上、gcc 太老白白浪费时间。我一般会先在一台机器上把系统版本、OpenSSH、OpenSSL、gcc 四个版本全部打印出来再决定走哪条升级路线。2.1 先查四个版本号系统、OpenSSH、OpenSSL 与 gcccat /etc/redhat-release uname -r ssh -V 21 | grep -oE OpenSSH_[0-9.]p[0-9] openssl version -a | head -1 gcc --version | head -1 rpm -qa | grep -E ^(openssh|openssl)ssh -V默认把版本信息打到 stderr所以必须加21再过滤否则在脚本里取不到值。openssl version -a里的-a除了版本号还会输出编译参数和证书路径先看第一行就够了。最后一条rpm -qa是为了确认当前安装的包名后面回滚或者做 RPM 校验时要用到这份清单。CentOS 7 的默认组合一般是 OpenSSH 7.4p1、OpenSSL 1.0.2k、gcc 4.8.5。这个组合本身能跑但它决定了你下一步选什么版本OpenSSH 9.3p1 还兼容 OpenSSL 1.0.2而 OpenSSH 9.8 及更新版本要求 OpenSSL 1.1.1 以上。所以版本不是越新越好要跟系统里已经有的 OpenSSL 匹配先查清楚能省掉后面一大半的编译报错。2.2 装齐编译依赖gcc、openssl-devel、zlib-devel 与 PAM 一个都不能少yum install -y gcc gcc-c make zlib-devel openssl-devel pam-devel perl rpm -q gcc gcc-c make zlib-devel openssl-devel pam-devel perl这条命令把编译 OpenSSH 需要的工具链和头文件一次性装齐。gcc 和 make 负责编译zlib-devel 提供压缩库接口OpenSSH 的传输层要用到openssl-devel 提供加密库头文件签名、密钥交换都依赖它pam-devel 是 PAM 认证链的头文件CentOS 7 的 sshd 默认开 UsePAM没有它 configure 会直接失败。装完再用rpm -q复核一遍输出缺谁补谁不要凭感觉认为装过了。这里有个容易被忽略的前提如果你的机器 yum 源在国外下载依赖会很慢甚至超时。我一般先把 yum 源切成国内常用镜像源再执行上述安装否则光等一个 make 命令就能耗掉十几分钟。镜像源的切换方法和具体地址在各大镜像站首页都有说明这里就不展开了。换完源记得yum clean all yum makecache让缓存生效否则可能装到的还是旧索引里的包。2.3 离线服务器准备依赖 rpm--downloadonly 与本地安装生产环境里大量 CentOS 7 是内网机器连外网 yum 都 ping 不通。这种情况最稳妥的做法是在一台能联网的同版本机器上下好依赖包再拷进去。思路和离线装 chrony 一样先用--downloadonly把 rpm 下载到指定目录然后拿到目标机上装。mkdir -p /root/openssh-rpms yum install -y --downloadonly --downloaddir/root/openssh-rpms \ gcc make zlib-devel openssl-devel pam-devel perlcd /root/openssh-rpms yum install -y ./*.rpm--downloadonly表示只下载不安装--downloaddir指定下载目录。CentOS 7 默认带了 yum-plugin-downloadonly 插件如果执行时报参数不认识先装一下这个插件。到了内网机器上用yum install -y ./*.rpm而不是rpm -ivh *.rpm因为 yum 会同时解析同目录下 rpm 之间的依赖关系rpm 命令遇到依赖顺序不对就罢工了。有一点要提醒如果你的内网环境已经有本地镜像源优先把离线机器配到本地源上直接yum install这比手动搬运 rpm 省事得多。离线方案是给那些完全没有源、连镜像都拉不进去的极端环境用的但也是我见过最不出错的办法。3. 编译安装新版 OpenSSH从 configure 到正式接管 sshd依赖齐了之后就到了最核心的编译覆盖阶段。这一章我会把版本选择、configure 参数、备份时机、systemd 接管和验证串成一条完整链路。全程不建议开两个窗口来回试最好按顺序一次走完中间任何一个sshd -t报错都要停下来排查。3.1 源码包选择与校验系统 OpenSSL 版本决定你能装多新前面查过系统 OpenSSL 是 1.0.2k 的话建议主线用 OpenSSH 9.3p1这个版本对 OpenSSL 1.0.2 仍然友好CentOS 7 的依赖链不用动。如果一定要追新版本比如 9.8p1后面避坑章会讲怎么处理 OpenSSL 1.1.1 的问题。这里按 9.3p1 为主线写。cd /usr/local/src curl -O https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-9.3p1.tar.gz sha256sum openssh-9.3p1.tar.gz tar -xzf openssh-9.3p1.tar.gz cd openssh-9.3p1下载地址是 OpenBSD 官方的 portable 版本发布目录路径如果调整以官网实际为准。下载后一定先sha256sum和官方公布的校验值比对内网环境更要这么做防止源码包被篡改。校验通过后再解压不要省这一步。源码目录建议放在/usr/local/src不要放在/root下避免权限问题影响编译过程。3.2 configure 参数逐项说明prefix 与 sysconfdir 决定配置会不会乱./configure \ --prefix/usr/local \ --sysconfdir/etc/ssh \ --with-pam \ --with-md5-passwords \ --with-zlib/usr make -j$(nproc) echo $?--prefix/usr/local指定安装目录新版二进制会落在/usr/local/bin和/usr/local/sbin和系统自带的/usr/bin区分开方便后面手工接管和回滚。--sysconfdir/etc/ssh这个参数最关键它让配置目录保持原来的位置systemd 单元里引用的就是/etc/ssh/sshd_config如果改成默认的/usr/local/etc重启服务会找不到原配置等于白干。--with-pam必须保留和系统 sshd 的 PAM 行为保持一致否则登录认证链会变。--with-md5-passwords保留对旧密码哈希的兼容内网老机器常见。--with-zlib/usr明确告诉 configure 去/usr找 zlib 头文件和库如果你的 zlib 装在别处改成实际路径。make -j$(nproc)用上所有 CPU 核心并行编译echo $?输出 0 表示编译通过非 0 就看屏幕上的报错定位问题。我见过有人在 configure 报错后不清理直接重跑后续全是些莫名其妙的头文件错误所以每次 configure 失败先make clean再重跑别硬刚。3.3 先备份再 make install顺序错了配置就没了make install 会把新的sshd_config模板写进/etc/ssh如果之前没备份你原来的自定义配置就没了而且这个坑很难一眼发现。所以在执行 make install 之前必须先完整备份配置和二进制。顺序一定不能乱备份在前install 在后。BK/root/backup/openssh-$(date %Y%m%d-%H%M) mkdir -p $BK cp -a /etc/ssh $BK/etc-ssh cp -a /usr/sbin/sshd $BK/sshd cp -a /usr/bin/ssh $BK/ssh cp -a /usr/bin/scp $BK/scp cp -a /usr/bin/sftp $BK/sftp备份目录名带时间戳方便以后按时间点找回。/etc/ssh里除了配置还有 host keycp -a保留权限和 SELinux 上下文这一步在后面的 SELinux 避坑里会反复用到。备份完再执行make install。make install install -m 0755 /usr/local/sbin/sshd /usr/sbin/sshd install -m 0755 /usr/local/bin/ssh /usr/bin/ssh install -m 0755 /usr/local/bin/scp /usr/bin/scp install -m 0755 /usr/local/bin/sftp /usr/bin/sftpmake install把文件装进/usr/local但 systemd 启动 sshd 用的还是/usr/sbin/sshd所以必须把新二进制复制到系统标准路径接管。install -m 0755会设置可执行权限并自动完成复制比cp更规范。这里覆盖的是二进制文件不碰/etc/ssh/sshd_config因为 make install 已经装了一个新模板过去下一步要根据备份决定要不要恢复。3.4 systemd 接管与 host key 处理不用改 unit 也能跑新版本CentOS 7 自带的sshd.service单元里 ExecStart 指向/usr/sbin/sshdEnvironmentFile 指向/etc/sysconfig/sshd。因为我们直接把新二进制覆盖到了/usr/sbin/sshd所以完全不用改 systemd 单元文件这是最省事的接管方式。grep -E ExecStart|EnvironmentFile /usr/lib/systemd/system/sshd.service restorecon -Rv /usr/sbin/sshd /usr/bin/ssh /usr/bin/scp /usr/bin/sftp /etc/ssh /usr/sbin/sshd -t systemctl restart sshd systemctl status sshd --no-pager三行命令的作用分别是确认单元路径、修复 SELinux 文件上下文、校验配置语法。sshd -t只检查语法不启动服务这一步必须通过再重启。host key 的处理原则是能不动就不动保留/etc/ssh/ssh_host_*原文件客户端 known_hosts 里的指纹就不会变。除非有明确的安全要求要换指纹否则不要碰它。如果确实需要重新生成rm -f /etc/ssh/ssh_host_* ssh-keygen -A会按默认算法重新生成一套但那意味着所有客户端的 known_hosts 都要更新操作成本很大。3.5 用 sshd -t 与新会话验证确认升级完成而不是等着翻车服务重启成功不代表升级完成还要从版本、实际配置、真实登录三个角度验证。版本检查在服务器本机执行实际登录则要开一个新终端窗口连一次用真实链路确认。ssh -V /usr/sbin/sshd -T 2/dev/null | grep -Ei ^(port|usepam|permitrootlogin|pubkeyaccepted) journalctl -u sshd --no-pager | tail -20ssh -V输出版本号确认二进制换了。sshd -T是运行时配置的输出它显示的是进程实际生效的参数不是配置文件里写的字面值排错时比翻sshd_config靠谱得多。journalctl看启动日志里有没有 PAM、SELinux 相关的报错。这里要强调验证必须在新开的 SSH 会话里做不能用当前会话因为当前会话可能是旧进程的遗留状态看不出真实情况。4. 避坑六个必踩的坑每条都是血泪经验这一章列的六个问题是我在 CentOS7 升级 OpenSSH 过程中反复遇到的按「现象 → 原因 → 解决」写方便你遇到问题时直接对照。如果你按前面章节顺序走大概率会撞上其中一两个。4.1 SSH 服务起不来先查 SELinux 文件上下文现象systemctl restart sshd 后服务状态是 active (running)但远程连接直接被拒journalctl 里出现大量SELinux is preventing /usr/sbin/sshd from ...的记录。原因通过 install 或 tar 释放的新二进制文件安全上下文可能是 bin_t 而不是 sshd_exec_tSELinux 会拒绝 sshd 绑定 22 端口或读取/etc/ssh下的文件。系统自带的 sshd 有正确的标签替换后标签丢了。解决执行restorecon -Rv /usr/sbin/sshd /usr/bin/ssh /usr/bin/scp /usr/bin/sftp /etc/ssh修复上下文再systemctl restart sshd。如果 restorecon 后还是不行检查semanage fcontext -l | grep sshd是否有 sshd_exec_t 规则没有就说明 policycoreutils-python 没装补装后重新设置。4.2 root 远程登录被拒sshd_config 被模板覆盖是元凶现象升级后所有用户密码登录失败root 直接 Permission denied但/var/log/secure里只有 Failed password没有其他异常。原因make install 时 sysconfdir 指向/etc/ssh新模板把原来的 sshd_config 覆盖了。模板默认 PermitRootLogin no和原配置不一致root 登录自然被拒。解决如果第 3.3 节做了备份直接cp -a /root/backup/openssh-时间戳/etc-ssh/sshd_config /etc/ssh/sshd_config恢复再sshd -t systemctl restart sshd。没有备份的话只能人工核对每一项配置重点看 PermitRootLogin、PasswordAuthentication、PubkeyAuthentication。这个坑说明备份动作真的不能省不是走流程是后悔药。4.3 configure 报 OpenSSL 版本过旧想用新版先升级加密库头文件现象编译 OpenSSH 9.8p1 时configure 直接提示 OpenSSL 版本过旧或者 make 阶段报头文件和库版本不匹配。原因OpenSSH 9.8 之后要求 OpenSSL 1.1.1 以上CentOS 7 系统自带的 openssl-devel 停在 1.0.2k版本不够。解决两条路按需选择。想留在最新版本就yum install -y openssl11-devel装完用rpm -ql openssl11-devel查看实际安装目录再在 configure 时加--with-ssl-dir指向包含 openssl 头文件的目录。不想动系统 OpenSSL 链就退回 OpenSSH 9.3p1它对 OpenSSL 1.0.2 仍然支持绝大多数等保整改场景足够。4.4 gcc 明明升级了还是旧版本scl 环境和编译缓存两个玄学坑现象按教程装了 devtoolset-8执行 gcc --version 还是 4.8.5或者在升级 gcc 后重新编译make 还是报老语法错误。原因第一个情况通常是 scl enable 只对当前 shell 生效新开的窗口 PATH 又变回去了。第二个情况是增量编译保留了上次的 .o 文件换了编译器也没有重新编译老对象文件还在。解决用source /opt/rh/devtoolset-8/enable hash -r which gcc gcc --version强制刷新当前环境的 PATH 和命令缓存确认版本后再编译。编译前一定要make clean必要时把源码目录整个删掉重新解压别在同一目录里反复试缓存会一直骗你。4.5 restart sshd 把自己踢下线用 HUP 信号和双会话保底现象远程窗口敲 systemctl restart sshd命令执行后当前会话卡死或直接断开。如果这是唯一的维护窗口人就进不去了。原因重启守护进程会终止正在服务的 sshd 进程组当前会话跟着遭殃。改配置和换二进制对进程的影响不一样很多人混在一起操作。解决改配置时用kill -HUP $(cat /var/run/sshd.pid)让主进程重新读取配置不断已有会话。升级二进制必须重启时先在本地开 tmux 或多开一个 ssh 窗口保底再执行危险操作。推荐把命令写成一行sshd -t systemctl restart sshd语法检查失败时不会触发重启至少不会把自己锁死。4.6 旧客户端连不上为 ssh-rsa 和 sha1 算法开兼容配置现象xshell 5、老版本 PuTTY 连接时提示 no matching key exchange method或者 Host key algorithm 不支持但新版 ssh 客户端没问题。原因新版 OpenSSH 默认关闭了 ssh-rsa 签名和 diffie-hellman-group14-sha1 这类老旧算法老客户端协商不上。解决在/etc/ssh/sshd_config末尾追加兼容配置然后systemctl reload sshd让配置生效。cat /etc/ssh/sshd_config EOF HostKeyAlgorithms ssh-rsa PubkeyAcceptedAlgorithms ssh-rsa KexAlgorithms diffie-hellman-group14-sha1 MACs hmac-sha1 EOF systemctl reload sshd这些参数开的是兼容模式不影响新版客户端走更安全的算法。但要注意ssh-rsa 本质是 SHA-1 签名安全性已经不合规只应该在确有老客户端需要连接的时候开并且尽量限制来源 IP。公网上建议不开内网运维场景按需开。5. 验证与回滚升级做完不是结束能退回去才是本事升级完成后的验证决定了你能不能安心下班回滚方案决定了出问题时你还有没有后悔药。很多人在 sshd -t 通过后就直接宣布完成结果第二天用户反馈登录异常才发现运行时参数和配置文件对不上。所以验证一定要走完四个维度回滚脚本也提前准备好。5.1 升级验证的四个维度版本、语法、运行时参数与真实登录/usr/sbin/sshd -V 21 /usr/sbin/sshd -t /usr/sbin/sshd -T 2/dev/null | grep -Ei ^(port|usepam|permitrootlogin|pubkeyaccepted) tail -20 /var/log/secure第一行确认服务端版本和客户端版本都是新编译的第二行确认配置语法没有错误第三行看进程实际生效的端口、PAM、root 登录策略这行输出不是 sshd_config 里的字面值而是解析后的真实值排错价值最高第四行看登录日志里有没有 Accepted 记录。真实登录这一步一定要做从另一台机器ssh user服务器IP连一次确认能正常进入 shell然后看/var/log/secure出现 Accepted publickey 或 Accepted password才算链路完整。只看版本号很容易漏掉 PAM 或 SELinux 层面的隐藏问题。5.2 留后悔药一键回滚脚本与备份目录规范备份目录在第 3.3 节已经生成现在把它利用起来写成回滚脚本。脚本要能一键恢复二进制、配置、SELinux 上下文并完成重启。放在/root/rollback-openssh.sh随时能跑。#!/bin/bash # 用法bash rollback-openssh.sh 备份目录 BK${1:-/root/backup/openssh-$(date %Y%m%d)} [ -d $BK ] || { echo 备份目录不存在: $BK; exit 1; } set -e install -m 0755 $BK/sshd /usr/sbin/sshd install -m 0755 $BK/ssh /usr/bin/ssh install -m 0755 $BK/scp /usr/bin/scp install -m 0755 $BK/sftp /usr/bin/sftp cp -a $BK/etc-ssh/. /etc/ssh/ restorecon -Rv /usr/sbin/sshd /usr/bin/ssh /usr/bin/scp /usr/bin/sftp /etc/ssh /usr/sbin/sshd -t systemctl restart sshd echo 回滚完成脚本用 install 恢复二进制权限一并处理。cp -a 恢复配置目录保留原始权限和 SELinux 上下文。最后一步必须用sshd -t 保护语法不过就拒绝重启避免把坏状态带进生产。备份目录规范建议统一用/root/backup/openssh-YYYYmmdd-HHMM格式回滚时第一个参数传目录路径即可省得临时找历史版本。5.3 回滚后发现还是新版本定位二进制与配置的三板斧回滚完一执行 ssh -V 还是新版这种现象很常见原因可能是 PATH 里/usr/local/bin排在/usr/bin前面也可能 systemd 单元的 ExecStart 被改过。先用三条命令定位。type -a ssh sshd which ssh systemctl cat sshd | grep ExecStart rpm -V openssh-server openssh-clientstype -a和which能看出 shell 实际调用的可执行文件路径systemctl cat sshd看单元文件里 ExecStart 指向哪个二进制如果还指向/usr/local/sbin/sshd说明之前改过单元文件要改回来或用systemctl daemon-reload重载rpm -V会列出和 RPM 包不一致的文件输出带 S.5.... 的通常就是被我们覆盖过的二进制这是在确认系统状态不是报错不用慌。还有一种容易被忽略的回滚后如果 rsync、cron 里调用 ssh 的命令报错检查/etc/ssh目录权限备份恢复时如果权限变成 755 而不是 700host key 会被 SSHD 拒绝读取。6. 批量复制这套方案一台装完怎么推广到几十台单机跑通后剩下那些同样版本的内网机器没必要各自编译一遍。同架构、同系统版本的前提下把编译产物打包分发是最省时间的做法。但打包内容有讲究host key 绝对不带走。6.1 把编译产物打成 tar 包host key 坚决不带走tar -czf openssh-runtime.tar.gz \ /usr/local/sbin/sshd /usr/local/bin/ssh /usr/local/bin/scp /usr/local/bin/sftp \ /usr/local/libexec/openssh /etc/ssh/sshd_config /etc/ssh/moduli这个包只包含新二进制和通用配置不包含/etc/ssh/ssh_host_*。host key 是每台机器唯一的身份标识一旦打包分发所有机器指纹一样客户端 known_hosts 会集体告警场面很难收拾。每台机器保留自己原来的 host key客户端端无需任何改动。6.2 一条 for 循环批量推送与热重载for ip in 10.0.0.11 10.0.0.12 10.0.0.13; do scp openssh-runtime.tar.gz root$ip:/tmp/ ssh root$ip tar -xzf /tmp/openssh-runtime.tar.gz -C / \ install -m 0755 /usr/local/sbin/sshd /usr/sbin/sshd \ restorecon -Rv /usr/sbin/sshd /etc/ssh /dev/null 21; \ /usr/sbin/sshd -t systemctl restart sshd echo $ip done done先 scp 把包传到目标机再解包到根目录让/usr/local下的文件就位。然后用 install 把新 sshd 提升到/usr/sbin/sshdrestorecon 修 SELinux 上下文最后sshd -t通过才重启。这条命令必须在一行里串联因为只有在当前会话里完成全部动作才不会被中断。6.3 最终核验登录日志与 ssh -G 输出双重确认批量执行完后选一台抽查ssh -V确认版本sshd -T看运行时参数再登录一次看/var/log/secure出现 Accepted。如果有一台sshd -t失败整个 for 循环会继续跑后面机器所以建议先在一台机器上完整验证一遍再放开批量。最后说个我自己的教训有一批二十台机器我图省事把整个/etc/ssh目录打进了包结果 host key 全部一致客户端 known_hosts 疯狂报警最后只能逐台重新生成 host key 并通知所有用户更新指纹。从那以后我给自己定了两条规矩一是凡是动 ssh 相关文件第一步永远是备份第二是打包分发时反复确认不包含 ssh_host_* 密钥。这套流程做到位单机升级和几十台批量都能稳稳落地。希望帮到你。本文还有配套的精品资源点击获取
返回列表