麒麟V10离线升级OpenSSH 9.8:完整方案与排错实战
简介针对国产麒麟操作系统的离线一键升级场景和等保加固需求这份资源为系统运维与安全管理员提供了一套完整的 OpenSSH 及依赖组件升级方案同时兼容 CentOS 系统。通过自带升级脚本与依赖源码包可在无互联网环境下批量完成 OpenSSH、OpenSSL、zlib 的更新适用于内网隔离或弱网环境的安全加固需求也适合定期维护的生产服务器。资源包共 4 个文件以 3 个源码压缩包和 1 个升级脚本为主整体约 20.04MB结构简洁、无需额外配置便于直接部署。目前已有 2078 人学习/下载说明该方法在真实运维场景中具备较高的参考价值与复用性。读者可获得离线升级脚本与关键依赖库源码覆盖 OpenSSH 9.7p1、OpenSSL 3.2.0、zlib 1.3.1 的版本组合无需手动排查依赖即可完成编译升级脚本同时适配 CentOS可复用于常规 Linux 服务器的安全加固特别适合内网环境的批量操作能有效减少人工干预和误操作风险帮助提升关键系统的稳定性与安全性。1. 为什么麒麟系统需要离线升级OpenSSH先说结论这个需求在信创环境里几乎天天遇到而且十有八九不是“闲着没事升级”是被安全扫描报告和等保测评逼着干的。银河麒麟V10这个系统底层虽然是Linux内核但自带的那套OpenSSH版本普遍偏老桌面版和服务器版默认装的可能是OpenSSH 7.4甚至更低。这个版本有什么问题它在2024年被爆出的高危漏洞比如CVE-2024-6387也就是regreSSHion一个不需要认证就能触发远程代码执行的严重漏洞影响范围里7.4就是重灾区。另外很多用户的业务系统做等保测评时测评机构拿扫描器扫一遍老版本OpenSSH会报出一堆中高危漏洞项不修复就拿不到备案。问题在于麒麟系统普遍部署在政务网、内网、专网这类隔离环境里没有外网也没有配置可用的yum源。即便配了源麒麟自带仓库里的openssh版本也不一定会更新到安全版本。这就把“升级OpenSSH”从一个简单的包管理操作变成了一个需要手动解决依赖、处理兼容性、保证远程连接不断线的运维工程。文章说的“离线一键升级”核心思路其实不复杂提前准备好源码包写好脚本在目标机器上一条命令完成编译、安装、配置、重启、验证。但这里面最坑的地方不在“编译”这一步而在于升级完连不上机器、ssh服务起不来、密码登录被拒、sftp不可用这几个经典事故。这篇文章就从需求背景讲到完整落地把我在实际项目里踩过的坑一并整理出来。2. 升级前必须搞清楚的4个问题2.1 确认当前系统和OpenSSH版本动手之前先把目标机器的家底摸清楚。用下面几条命令快速确认# 查看麒麟系统版本 cat /etc/kylin-release # 或 nkvers # 查看架构 uname -m # 查看当前OpenSSH版本 ssh -V # 查看当前OpenSSL版本 openssl version为什么要先查这些因为麒麟V10有x86_64和aarch64ARM架构两个大方向还有些基于飞腾、鲲鹏、海光等不同CPU的整机。不同架构编译参数基本一致但依赖库的情况可能会有差异。另外OpenSSH对OpenSSL的版本有最低要求比如OpenSSH 9.x系列要求OpenSSL 1.1.1以上如果系统里自带的是OpenSSL 1.0.2那就需要连带升级OpenSSL这一步很多人会忽略。我建议把查到的版本信息先记下来后面写脚本做版本判断时会用到。2.2 评估升级OpenSSH会不会“断连”服务器如果只能通过SSH远程管理那升级OpenSSH就是一次“手术”搞不好就把自己的后路切断了。升级过程中sshd服务会重启如果新版本起不来你的远程会话就断了而且短时间内还不一定找得到人帮你到机房去操作。所以实际项目中我会先评估一下机器上有没有其他远程通道有没有带外管理比如BMC/IPMI有没有堡垒机、KVM等物理访问途径有没有华为云、VMware等虚拟化平台的控制台如果都没有那就必须在脚本里做足防护升级前备份原sshd二进制和配置文件、编译安装完成后先临时保留一个手动启动的入口、重启sshd失败时自动回滚。这些设计后面会详细讲。2.3 离线环境下的依赖准备离线升级最头疼的不是OpenSSH本身而是它的编译依赖。编译OpenSSH至少需要gcc、make、gcc-c等编译工具链zlib和zlib-developenssl和openssl-devel如果OpenSSH要与系统OpenSSL动态链接pam和pam-devel如果要用PAM认证如果机器上原本是精简安装连gcc都没有那就得先从一台同版本、同架构的机器上把rpm包攒齐做成一个离线目录升级前统一装好。有一个取巧的办法rpm -qa可以看哪些包已经装了缺哪些就找哪些。不需要最新版能用就行本地源里带上就够了。我在实际项目里的做法是准备一个deps目录里面放好编译必需的rpm包脚本执行时先检查gcc是否存在不存在就自动从本地目录安装这样能省很多事。2.4 升级版本的选择离线升级第一步是下载合适的OpenSSH源码包。热词里有人在搜“openssh 10.3”也有搜“升级到9.8”的。实际上OpenSSH官方已经不接受老的源码包下载方式了现在要从OpenBSD的镜像站点或者GitHub的openssh/openssh-portable仓库拿release包。版本怎么选我的经验是优先选当前主流的稳定版本比如9.8p1或9.9p1既能覆盖已知漏洞又经过了大范围验证。不要一味追新。太新的版本依赖要求可能更高比如某些新版本要求OpenSSL 3.x而麒麟V10自带的可能是1.1.1系列强制升级OpenSSL会引入更大的兼容性风险。建议选与自带OpenSSL版本能够兼容的OpenSSH版本。如果不想动OpenSSL建议直接选择9.8p1这一档它对OpenSSL 1.1.1是友好支持的。同样需要准备的还有OpenSSL源码包如果判断需要升级和zlib源码包。把这些源码包放到同一个目录里后面的脚本会依次完成编译。3. 一键升级脚本的设计思路3.1 脚本的整体结构我写的脚本不搞花哨操作核心就五个阶段环境检查、备份、编译安装、配置替换、启动验证。每个阶段都有日志输出遇到问题马上就停不让错误继续往下滚。核心代码框架如下#!/bin/bash # 麒麟系统离线一键升级OpenSSH set -e # 基础配置区 SSH_SRC_DIR/opt/ssh_src SSH_INSTALL_PREFIX/usr/local/openssh SSHD_CONFIG/etc/ssh/sshd_config BACKUP_SUFFIX.bak_$(date %Y%m%d%H%M%S) LOG_FILE/var/log/upgrade_openssh.log # 阶段1环境检查 check_env() { echo [INFO] 开始环境检查... if [ ! -f $SSH_SRC_DIR/openssh-9.8p1.tar.gz ]; then echo [ERROR] 未找到OpenSSH源码包 | tee -a $LOG_FILE exit 1 fi which gcc /dev/null 21 || { echo [ERROR] gcc未安装; exit 1; } # 获取当前版本号用于日志记录 OLD_VERSION$(ssh -V 21 | awk {print $1}) echo [INFO] 当前OpenSSH版本: $OLD_VERSION } # 阶段2备份 backup_ssh() { echo [INFO] 开始备份原OpenSSH文件和配置 mkdir -p /root/ssh_backup cp /usr/sbin/sshd /root/ssh_backup/sshd$BACKUP_SUFFIX cp /usr/bin/ssh /root/ssh_backup/ssh$BACKUP_SUFFIX cp /usr/bin/scp /root/ssh_backup/scp$BACKUP_SUFFIX cp /usr/bin/sftp /root/ssh_backup/sftp$BACKUP_SUFFIX cp $SSHD_CONFIG /root/ssh_backup/sshd_config$BACKUP_SUFFIX echo [INFO] 备份完成备份位置为 /root/ssh_backup/ }备份这一步千万不能省。我在项目中遇到过好几次升级后sshd起不来的情况最后都是靠备份文件快速恢复的。备份对象包括三个层次二进制sshd、ssh、scp、sftp、配置sshd_config、依赖库如果升级了OpenSSL。备份目录固定放在/root/ssh_backup下文件名带时间戳后面回滚时一眼就能找到对应版本。3.2 编译安装的核心逻辑核心代码如下# 阶段3编译安装OpenSSH compile_install() { cd $SSH_SRC_DIR # 解压源码 tar -zxvf openssh-9.8p1.tar.gz cd openssh-9.8p1 # 配置编译参数 ./configure --prefix$SSH_INSTALL_PREFIX \ --sysconfdir/etc/ssh \ --with-ssl-dir/usr/local/openssl \ --with-pam \ --with-zlib/usr/lib64 \ --with-md5-passwords # 编译和安装 make -j$(nproc) make install echo [INFO] 编译安装完成 }这里有几个配置参数需要重点解释一下。--prefix指定安装路径我习惯装到/usr/local/openssh不直接覆盖系统自带的OpenSSH。这样好处是新版本先装好验证没问题后再替换系统路径下的二进制万一出问题系统自带的二进制理论上还在虽然实际项目里这个回滚路径不总会成功但多一层保障总是好的。--sysconfdir/etc/ssh用来指定配置文件路径。注意新版OpenSSH安装后不会自动生成sshd_config文件它会安装一个sshd_config.default模板到安装目录下。所以安装完要手动把模板复制到/etc/ssh/下或者保留原有的配置文件不动。我实际更倾向保留原有的sshd_config老文件里已经做好了很多定制端口、允许用户、密钥认证方式等升级后继续沿用减少改动面。--with-ssl-dir只在OpenSSL需要同步升级时才配置。如果你的系统OpenSSL版本满足要求这个参数可以去掉让OpenSSH直接动态链接系统libssl。--with-pam表示启用PAM认证。麒麟系统的登录认证很多依赖PAM模块比如密码复杂度、账户锁定不启用PAM的话升级后很可能会出现密码登录报错、系统日志里找不到认证记录的问题。3.3 安装后的配置替换编译安装完成后不能直接重启sshd有两个地方必须处理把新版本的sshd、ssh、sftp等二进制替换到系统目录/usr/sbin/sshd、/usr/bin/ssh等确保systemd服务启动时调用的是新版本。处理sshd服务的systemd单元文件。麒麟系统的sshd.service一般定义在/usr/lib/systemd/system/sshd.service最好把服务文件里的ExecStart路径改成新二进制的位置例如ExecStart/usr/local/openssh/sbin/sshd -D $OPTIONS不做这个改动你也可以用绝对路径启动sshd但systemd管理会乱掉后续开机自启和状态检查都会出问题。还有一个关键操作——配置sshd_config里的SFTP子系统路径。老版本系统里sftp-server默认路径可能是Subsystem sftp /usr/libexec/openssh/sftp-server而新版本编译后sftp-server被放在了新的安装目录里比如/usr/local/openssh/libexec/sftp-server。如果没改配置升级完sftp客户端连上来时会报“connection closed”或者直接拒绝连接。这是OpenSSH升级后最常见的坑之一。所以脚本里必须做一次sed替换把Subsystem那一行的路径指向新版的sftp-server。3.4 安全检查与重启验证替换完配置后先做语法检查再重启/usr/local/openssh/sbin/sshd -t如果输出没有报错再重启服务systemctl restart sshd systemctl status sshd重启后立即验证端口是否监听ss -tlnp | grep :22然后开一个新终端连一次确认密码和密钥认证都能正常工作。测试sftp也顺手做一下sftp rootlocalhost这套验证流程一步都不能跳。尤其要注意不要只从本机连尽量从另一台机器远程连一次因为本机连接和外网连接的链路验证效果不一样。4. 实操中踩过的坑和排错经验4.1 sshd启动失败日志报“Permission denied”有一次我在一台麒麟V10服务器上升级到9.8p1重启sshd直接失败查看日志看到sshd: /usr/local/openssh/bin/ssh-keygen: Permission denied排查发现是/usr/local/openssh这个目录的权限不对。源码包我没做任何特殊处理但解压时如果用了root之外的用户或者复制文件时权限被改了就会出现这种情况。解决办法很简单chmod 755 /usr/local/openssh -R chown root:root /usr/local/openssh -R这个坑很隐蔽因为你编译时明明一切正常安装也没报错偏偏启动时才暴露。记住编译和安装最好全程用root安装完顺手把权限统一一下能省很多事。4.2 升级后密码登录被拒热词里有人专门搜“openssh升级拒绝密码”这个现象相当常见。新版OpenSSH默认配置里PermitRootLogin是prohibit-password意思是禁止root用户用密码登录只允许密钥登录。如果你原来的sshd_config里没有显式写这个参数升级前用的可能是老版本的默认值行为不一样升级后默认值一变密码登录就被拒绝了。还有更隐蔽的原因新版本OpenSSH对密码认证的PAM依赖更严格。如果编译时没加--with-pam或者系统里pam配置不对密码验证阶段会直接失败日志里甚至连密码错误的提示都看不到。解决办法是升级后在sshd_config中显式加入下面几行PermitRootLogin yes PasswordAuthentication yes UsePAM yes KbdInteractiveAuthentication yes注意如果安全策略不允许root直接登录可以用一个普通用户登录后su切换这时候PermitRootLogin保持no也是可以的。但为了应急恢复建议至少在配置里保留一个密钥登录的入口。4.3 升级后SSH连接卡在“timed out while waiting for handshake”热词里也有“银河麒麟v10 openssh timed out while waiting for handshake”这种搜索。这个报错通常出现在ssh连接建立过程的早期也就是TCP都通了但无法完成SSH协议握手。常见原因防火墙或安全组没有放行新监听的端口如果你把端口从22改成了别的。新编译的sshd启动时没有正确加载host key导致无法完成密钥交换。系统里残留了旧的sshd进程占用了22端口新进程起在别的端口上。排查思路# 查看端口状态 ss -tlnp | grep ssh # 查看sshd日志 journalctl -u sshd -n 50 # 检查host key ls -l /etc/ssh/ssh_host_*key*如果是host key缺失可以用ssh-keygen重新生成ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key4.4 SELinux导致连接被拒麒麟系统默认开启了SELinux虽然很多内网环境会把它关掉但有些没关。新编译的sshd二进制路径在/usr/local/openssh下SELinux策略没有放行这个路径下的sshd监听端口就会导致sshd启动正常、监听正常但从外部连接却不通查看AVC日志会看到拒绝记录。临时做法setenforce 0验证是不是SELinux的问题。如果是可以永久放行semanage fcontext -a -t sshd_exec_t /usr/local/openssh/sbin(/.*)? restorecon -Rv /usr/local/openssh或者干脆在/etc/selinux/config里把SELinux设为permissive。但从安全角度我不建议直接全关至少把sshd相关目录的context处理好。4.5 编译时提示缺少“openssl/xxx.h”头文件编译时最常见的一类报错是找不到openssl头文件fatal error: openssl/opensslv.h: No such file or directory这说明系统里没有安装openssl-devel这个开发包。如果连不上yum源需要手动挂载麒麟系统ISO作为本地源然后安装mount -o loop Kylin-Desktop-V10-SP1-x86_64.iso /mnt cd /etc/yum.repos.d/ cat local.repo EOF [local] namelocal baseurlfile:///mnt enabled1 gpgcheck0 EOF yum clean all yum install -y openssl-devel pam-devel zlib-devel这一步如果做不好后面编译全部卡住。所以我建议在写一键脚本之前先把依赖准备这一步吃透。5. 一键脚本里容易被忽略的细节5.1 编译安装的时间开销在I/O性能一般的服务器上OpenSSH全量编译加安装大概需要3到8分钟取决于CPU核数和磁盘速度。如果加上OpenSSL编译那可能得20分钟往上。所以脚本里的进度提示和日志输出非常关键运维人员不可能一直盯着屏幕日志要写到文件里出了问题能从头查到尾。另外make -j后面的并行数最好根据机器配置动态获取我习惯用nproc命令获取CPU核数不要硬编码-j4或-j8不然在低配机器上编译时会内存溢出。5.2 升级后要不要重启系统很多人升级完sshd验证没问题就以为大功告成了。其实有隐藏风险OpenSSH里有几个重要组件比如sshd、ssh-agent在系统启动初期就会被调用如果二进制被替换了但没有重启相关服务下次系统重启后可能因为新的二进制依赖了某些库导致启动顺序问题。我的做法是升级完sshd后把pam配置文件、密钥文件、以及systemd服务文件都检查一遍然后在业务低峰期安排一次重启验证。当然如果条件不允许重启至少确认ssh、scp、sftp、sshd这几个命令能正常调用并且sshd服务是active状态。5.3 升级后要同步处理的“相关文件”题目里专门提到“以及相关文件”这说明升级OpenSSH不光是换一个sshd二进制那么简单。我整理了一个清单文件/目录说明升级后的处理/etc/ssh/sshd_config主配置文件保留原配置手动修改关键参数/etc/ssh/ssh_host_*_key主机密钥保留避免客户端有known_hosts冲突/etc/pam.d/sshdPAM认证配置检查是否存在缺失需创建/usr/lib/systemd/system/sshd.servicesystemd服务文件修改ExecStart为新版本路径/etc/ssh/ssh_config客户端配置一般可保留默认~/.ssh/authorized_keys用户密钥授权不受影响但要注意路径权限这里特别说一下/etc/pam.d/sshd。麒麟系统自带的sshd的PAM配置在/etc/pam.d/sshd如果升级后这个文件缺失或者内容不完整密码认证会直接失败。如果没有这个文件可以手动创建一个最小可用的auth required pam_env.so auth sufficient pam_unix.so nullok try_first_pass auth requisite pam_succeed_if.so uid 1000 quiet_success auth required pam_deny.so account required pam_unix.so session required pam_limits.so session optional pam_keyinit.so force revoke password sufficient pam_unix.so sha512 shadow nullok try_first_pass不同系统的PAM配置略有差异建议先从同系统的正常机器上拷一份过来修改而不是凭空写。5.4 回滚方案必须有脚本里必须预留一个回滚组件。我习惯把备份的文件放在/root/ssh_backup下然后写一个rollback.sh内容大致是#!/bin/bash # 回滚OpenSSH升级 systemctl stop sshd cp /root/ssh_backup/sshd.bak_202501011200 /usr/sbin/sshd cp /root/ssh_backup/ssh.bak_202501011200 /usr/bin/ssh cp /root/ssh_backup/sshd_config.bak_202501011200 /etc/ssh/sshd_config systemctl start sshd这个回滚脚本不要等到出问题再写应该在升级脚本里一并生成好。反正就几行命令顺手做出来关键时刻能救命。另外如果你同时升级了OpenSSL在/etc/ld.so.conf.d/里新增了自定义库路径那么回滚时要一并删除否则老版本sshd启动时可能加载到新版本的libssl行为不可预测。6. 实战场景从一台全新麒麟V10服务器开始为了让你对整个过程有更清晰的画面感我拿一台全新的麒麟V10服务器举例完整跑一遍升级流程。6.1 现场环境系统银河麒麟V10 SP1x86_64架构 自带OpenSSH7.4p1 自带OpenSSL1.0.2kRPM版本可能显示1.0.2k-xxx 网络情况完全隔离无yum源无外网 需求升级OpenSSH到9.8p1修复安全漏洞不影响现有业务6.2 准备阶段在一台能上网的机器上先下载好以下源码包这一步通常是在运维自己的办公电脑上完成openssh-9.8p1.tar.gzzlib-1.2.13.tar.gz如果系统自带zlib太老建议同步升级openssl-1.1.1w.tar.gz因为系统自带OpenSSL是1.0.2不升级会卡住OpenSSH 9.8的configure检查把这三个包上传到服务器的/opt/ssh_src目录。6.3 执行阶段检查gcc依赖rpm -qa | grep gcc如果没有gcc利用麒麟系统ISO做本地源安装mount -o loop /opt/Kylin-Desktop-V10-SP1-x86_64.iso /mnt cat /etc/yum.repos.d/local.repo EOF [local] namelocal baseurlfile:///mnt enabled1 gpgcheck0 EOF yum clean all yum install -y gcc make pam-devel zlib-devel openssl-devel然后执行一键脚本。脚本内处理顺序优先升级zlib再升级OpenSSL最后编译安装OpenSSH。这中间zlib的编译很关键因为如果系统的libz.so版本太老新编译的OpenSSH运行时会报“version ZLIB_1.2.9 not found”这类错误。6.4 验证阶段升级完的验证清单# 检查版本 ssh -V /usr/local/openssh/sbin/sshd -V # 检查服务状态 systemctl status sshd # 检查端口 ss -tlnp | grep sshd # 测试密码登录 ssh userlocalhost # 测试sftp sftp userlocalhost # 检查日志有没有报错 journalctl -u sshd -n 30跑完这一步整个升级才算真正完成。7. 最后再分享几个小经验我在实际给多台麒麟机器升级时遇到过几次比较特殊的情况这里挑两条补充一下。第一如果机器上有装了第三方安全软件比如主机加固、防篡改系统升级前一定要先跟负责安全运维的同事确认有些加固策略会锁住/lib、/usr/bin下的二进制文件你明明执行了替换命令文件也没报错但它就是改了又被还原。遇到“升级完版本没变”的情况先排查这类安全软件不要一味怀疑自己的编译步骤。第二把升级脚本本身做成一个可重复执行的版本。比如我在脚本里加了版本判断如果发现目标版本已经被安装并且sshd正在运行就跳过编译和安装只做配置检查和回显。这样同一台机器跑两遍、三遍都不会搞出问题。运维场景里最怕的就是脚本不幂等。第三离线环境下的“依赖灾难”是最大的不确定性。你永远不知道下一台机器会缺哪个包。所以不要图省事只准备OpenSSH源码包最好是连编译工具链、依赖库的rpm包一起打包做一个完整的offline bundle。我现在的习惯是每到一个新的麒麟版本或者架构环境先在测试机上完整跑一遍升级确认无误后再去生产环境批量执行测试过程中记录下缺了哪些依赖然后补进bundle里。多花半小时准备能避免在生产环境卡住一整天。本文还有配套的精品资源点击获取