统信UOS服务器版OpenSSH 9.6p1自制RPM升级实战
简介面向统信UOSUEL20-aarch64服务器运维人员提供一套自制OpenSSH离线升级解决方案适用于OpenSSH 9.6p1以下版本向9.6p1版本升级的场景解决了因外网受限或本地仓库缺少对应rpm导致安装困难的问题也降低了逐一手动编译OpenSSH的复杂度。压缩包内共4个文件包含openssh主程序、openssh-clients客户端和openssh-server服务端三个aarch64架构rpm包以及配套的upgrade_openssh.sh升级脚本整体仅1.5MB便于内网环境快速分发部署。包内目录结构清晰用户可按需选择安装服务端或客户端组件适合漏洞修复、等保合规或系统安全加固等常规运维场景。目前已有1277人学习下载对于需要维护统信UOS aarch64系统的运维工程师这份资源从包体组成到脚本使用方式提供了完整参考能帮助快速完成OpenSSH版本的统一升级与收敛。 做这行久了总会碰到一些绕不开的硬骨头。这周刚完成了一批统信UOS服务器版的OpenSSH安全升级架构是aarch64最终方案是自制9.6p1的rpm安装包统一部署。整个过程从梳理依赖、写SPEC、跑rpmbuild到内网分发、逐台升级踩了不少坑也沉淀出一套可以复用的打法。这篇就把完整过程拆开揉碎给同样在信创环境里做运维的同学一份可以直接抄作业的参考。1. 项目背景与痛点分析1.1 安全审计带出的升级刚需事情的起因并不复杂内网安全扫描报告里一批统信UOS服务器版的OpenSSH版本停留在8.x命中了好几个中高危CVE包括SSH握手协议层面的Terrapin攻击CVE-2023-48795和scp命令注入漏洞CVE-2023-51385。安全团队给的整改期限很紧要求尽快升级到修复版本。翻了一圈系统自带的软件源OpenSSH版本还是老样子并没有9.6p1的现成rpm包。网上搜到的第三方源又不敢直接用毕竟生产环境谁敢随便引进一个不明来路的二进制包于是只能走上自制rpm这条路。为什么选9.6p1这是2023年12月发布的一个稳定版本修复了上述两个已知高危漏洞同时兼容性经过了较长时间的社区验证。后面虽然有更新的版本但在信创环境里稳妥比追新更重要9.6p1是一个风险收益比很合适的选择。1.2 为什么是自制rpm而不是源码编译可能有同学会问直接拿到源码 ./configure make make install 不就行了为什么非要打rpm包主要考虑到三点。第一源码编译安装默认会覆盖系统自带的OpenSSH文件如果版本冲突或配置残留很容易留下隐患后续系统升级还会被系统包管理器“回滚”覆盖造成版本漂移。第二rpm包有完整的卸载、升级、依赖管理机制部署到多台机器时可以统一版本、统一校验还能通过内网yum源集中分发不用每台机器都装一遍编译工具链。第三运维需要可追溯性rpm的安装记录、文件清单rpm -ql、配置归属都清晰可查出了问题能快速定位。当然自制rpm也有代价SPEC文件要自己写构建依赖要自己梳理遇到报错得自己扛。但把这套流程跑通一次后面再升级9.7、9.8就是改版本号的事边际成本很低。2. 构建环境准备与依赖梳理2.1 确认系统版本与架构动手之前先把构建机和目标机器的系统信息摸清楚。统信UOS服务器版虽然整体走的是类CentOS的技术路线但不同版本之间的基础包还是有差异不能想当然。cat /etc/os-release uname -m sshd -V rpm -q openssh-server openssh-clients openssh我这边构建机的信息大概是这样的统信UOS服务器版内核版本跟随系统自带架构输出为aarch64OpenSSH原版本为8.2p1。这里有个坑要提前说统信UOS的aarch64和标准ARM64指令集是一致的但部分库文件的版本、路径可能和CentOS不完全一致所以构建时尽量在目标系统同版本环境上进行避免动态库链接不上的问题。有一台机器上执行rpm命令居然提示“没找到rpm命令”后来发现是PATH环境变量被改过而系统默认的包管理器还是完整的。如果是全新环境建议先确认包管理器可用which rpm which yum yum --version如果不小心把rpm相关基础组件破坏了可以尝试用系统的恢复模式修复但这属于另一个话题。日常操作中像rpm这种基础命令一般不会缺失真遇到的时候优先检查环境变量。2.2 构建依赖安装与rpmbuild目录初始化OpenSSH从源码构建rpm核心依赖集中在编译器、头文件和几个关键库上。我在构建机上用如下命令一次性装齐yum install -y rpm-build gcc make openssl-devel zlib-devel pam-devel krb5-devel libedit-devel audit-libs-devel pcre2-devel systemd-devel逐个解释一下这些包的作用rpm-build提供rpmbuild命令和宏定义不打rpm就用不到它gcc/make编译源码的基础工具链openssl-develOpenSSH运行依赖OpenSSL库加解密算法全靠它头文件必须齐全zlib-devel压缩传输支持pam-develPAM认证模块如果计划打开UsePAM这个必须装krb5-devel如果生产环境要对接Kerberos认证比如某些企业内部统一认证就需要这个libedit-devel提供交互式命令行编辑支持不装也能编过但为了功能完整推荐装上。依赖装完之后初始化rpmbuild目录结构。这个目录可以建在任意位置我习惯放在普通用户家目录下不推荐直接用root跑rpmbuildmkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}对应的几个目录作用分别是BUILD是解压源码的临时构建区BUILDROOT是打包时的虚拟根目录RPMS存放最终生成的二进制包SOURCES放源码包和补丁SPECS放SPEC文件SRPMS放源码rpm。3. SPEC文件编写与rpmbuild构建3.1 源码下载与完整性校验去OpenSSH官网下载9.6p1源码包这个环节有一个细节尽量同时下载对应的签名文件用PGP校验一下源码完整性。如果内网没有外网权限就找一台允许访问外网的机器下载好通过内部文件服务器拉回来。wget https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-9.6p1.tar.gz wget https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-9.6p1.tar.gz.asc下载完先看文件大小和校验和即使没有PGP密钥也可以顺手做一次SHA256对比sha256sum openssh-9.6p1.tar.gz把源码包放到~/rpmbuild/SOURCES/目录下。3.2 SPEC文件核心配置解析SPEC文件是整个rpm构建的心脏也是最容易出问题的环节。我直接贴一份经过实机验证的完整SPEC基于常见实践整理关键项逐一说明Name: openssh Version: 9.6p1 Release: 1.aarch64 Summary: OpenSSH 9.6p1 for UOS aarch64 License: BSD URL: https://www.openssh.com/ Source0: openssh-%{version}.tar.gz # 构建依赖 BuildRequires: gcc, make, openssl-devel, zlib-devel, pam-devel Requires: openssl-libs, zlib, pam %description OpenSSH is a free version of the SSH connectivity tools. %prep %setup -q -n openssh-%{version} %build ./configure \ --prefix/usr \ --sysconfdir/etc/ssh \ --with-md5-passwords \ --with-pam \ --with-privsep-path/var/empty/sshd \ --with-zlib \ --with-ssl-dir/usr \ --with-kerberos5/usr \ --with-libedit \ --mandir/usr/share/man \ --disable-static make -j$(nproc) %install make install DESTDIR%{buildroot} # 创建必要的配置目录和用户 install -d %{buildroot}/var/empty/sshd install -d %{buildroot}/etc/ssh # 保持系统原有的主机密钥目录 %post # 如果不存在主机密钥自动生成 if [ ! -f /etc/ssh/ssh_host_rsa_key ]; then /usr/bin/ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N /dev/null 21 fi if [ ! -f /etc/ssh/ssh_host_ecdsa_key ]; then /usr/bin/ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N /dev/null 21 fi if [ ! -f /etc/ssh/ssh_host_ed25519_key ]; then /usr/bin/ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N /dev/null 21 fi # 注册systemd服务 systemctl daemon-reload /dev/null 21 || true %preun if [ $1 -eq 0 ]; then systemctl stop sshd /dev/null 21 || true systemctl disable sshd /dev/null 21 || true fi %files /usr/bin/scp /usr/bin/sftp /usr/bin/ssh /usr/bin/ssh-add /usr/bin/ssh-agent /usr/bin/ssh-keygen /usr/bin/ssh-keyscan /usr/sbin/sshd /usr/libexec/openssh/* /etc/ssh/ /usr/share/man/man1/* /usr/share/man/man5/* /usr/share/man/man8/* %changelog * Thu Jan 01 2024 ops opsexample.com - 9.6p1-1 - Upgrade to 9.6p1这个SPEC有几个值得注意的点。--with-privsep-path/var/empty/sshd是OpenSSH权限分离机制的运行目录目录必须存在且属主是root权限不能过宽否则sshd启动会报错。很多同学升级后遇到“/var/empty/sshd must be owned by root and not group or world-writable”就是这个问题。--with-pam是必须的统信UOS系统里远程密码登录的验证走的是PAM链路如果编译时没带PAM支持即使配置了PasswordAuthentication yes登录也会失败。--disable-static是为了不生成静态库减少打包体积和潜在兼容问题。%post脚本里自动生成主机密钥的逻辑也是从实战中加的。用rpm -Uvh升级时如果原系统里有旧的/etc/ssh/ssh_host_*文件rpm包不会覆盖它们这是好事保留了原主机指纹用户侧不会收到“host key has changed”的告警。但如果是全新安装目录里没有密钥文件sshd起不来所以做了兜底自动生成。3.3 执行rpmbuild与产物验证把SPEC文件保存为~/rpmbuild/SPECS/openssh.spec然后切换到普通用户目录下执行cd ~/rpmbuild/SPECS/ rpmbuild -ba openssh.spec构建过程会先解压源码、执行configure、make编译最后打包。整个流程大概需要几分钟到十几分钟不等取决于机器性能。如果中途报错常见原因和排查方式我在第5章详细说。构建完成后二进制rpm会生成在~/rpmbuild/RPMS/aarch64/下ls -lh ~/rpmbuild/RPMS/aarch64/我这边生成的产物包括openssh-9.6p1-1.aarch64.rpmopenssh-clients-9.6p1-1.aarch64.rpmopenssh-server-9.6p1-1.aarch64.rpm用rpm -qpi检查包的基本信息确认版本、架构、依赖都符合预期rpm -qpi RPMS/aarch64/openssh-9.6p1-1.aarch64.rpm再查看文件清单确认关键文件路径正确rpm -qpl RPMS/aarch64/openssh-9.6p1-1.aarch64.rpm如果文件路径不对比如sshd安装到了/usr/local/sbin/sshd后面启动服务时就会找不到命令。在SPEC阶段把--prefix/usr指明确能规避绝大多数路径问题。4. 升级部署实操与风险控制4.1 升级前的备份与安全通道确认自制rpm包构建成功只是第一步真正让人紧张的是在生产环境上升级。这个环节的核心原则是永远给自己留一条后路。执行升级之前必须完成三件事。第一备份OpenSSH配置和密钥文件cp -a /etc/ssh /etc/ssh.bak.$(date %Y%m%d%H%M%S) cp -a /etc/pam.d/sshd /etc/pam.d/sshd.bak.$(date %Y%m%d%H%M%S)第二确认有非SSH的备用通道。如果机器是虚拟机确认控制台vnc/物理终端可用如果是物理机确认能通过带外管理卡访问。升级过程中一旦sshd起不来这些是唯一能救命的入口。第三检查sshd_config里有没有不可替换的定制项。我遇到过一台机器配置了很复杂的ForceCommand和Match块升级前对照备份逐项核对避免新版本默认配置把定制逻辑覆盖掉。OpenSSH 9.6p1对过时的算法和密钥类型限制更严格比如默认禁用了ssh-dss、ssh-rsaSHA1如果生产环境有老客户端依赖这些弱算法升级后可能连不上这一步必须提前排查。4.2 rpm安装与配置迁移备份完成后开始安装。三合一升级的命令是rpm -Uvh openssh-9.6p1-1.aarch64.rpm openssh-clients-9.6p1-1.aarch64.rpm openssh-server-9.6p1-1.aarch64.rpm注意这里用了-Uvh而不是-ivh-U表示升级会先卸载旧版本再安装新版本。如果你已经用源码编译方式安装过OpenSSH文件散落在/usr/local/rpm包是感知不到这些文件的可能会出现命令路径冲突。这种情况下建议先手动清理/usr/local下旧的OpenSSH以实际安装路径为准再执行rpm安装。安装完成后执行systemctl daemon-reload systemctl restart sshd systemctl status sshd这里有一个高频坑systemctl restart sshd报错找不到服务单元。原因通常是打包时没有处理systemd的unit文件或者安装后没有执行daemon-reload。解决办法是确认/usr/lib/systemd/system/sshd.service存在如果不存在可以从旧版本目录拷贝或者手写一个基础unit文件放到/etc/systemd/system/sshd.service里内容大致如下[Unit] DescriptionOpenSSH server daemon Afternetwork.target [Service] Typenotify EnvironmentFile-/etc/sysconfig/sshd ExecStart/usr/sbin/sshd -D $OPTIONS ExecReload/bin/kill -HUP $MAINPID KillModeprocess Restarton-failure RestartSec42s [Install] WantedBymulti-user.target另外升级后要重点检查一下sshd_config里以下几项PasswordAuthentication是否保持原值很多环境下默认配置是关闭密码登录的升级后如果不小心重置了文件会把密钥登录也搞挂Subsystem sftp路径是否正确9.6p1默认sftp服务端路径是/usr/libexec/openssh/sftp-server如果系统原来用的是/usr/lib/openssh/sftp-server而配置里还是旧路径sftp会连不上UsePAM推荐保持yes和统信UOS的认证框架协同工作。检查配置正确性用sshd自带的测试模式/usr/sbin/sshd -t如果没有输出说明语法没问题。4.3 升级后的验证与安全加固升级和重启服务只是开始真正的验收要看线上能不能正常接入。我一般会按这个顺序做验证。第一步本地验证监听端口和进程状态ss -lntp | grep 22 ps -ef | grep sshd | grep -v grep第二步从另一台机器用SSH客户端连接测试观察能否正常完成登录。这里注意升级过程因为服务重启已有的长连接会断开这是正常现象不要慌。第三步分别测试密码登录和密钥登录两种方式确认PAM链路没有受影响。具体方法是在一台测试机上先ssh -o PreferredAuthenticationspassword userhost再ssh -o PreferredAuthenticationspublickey userhost。第四步检查登录日志有没有异常tail -f /var/log/secure第五步确认ssh和scp、sftp功能都正常特别是sftp很多团队日常用sftp传文件要实测一下。如果以上都通过升级基本就算成功了。最后建议顺手开启或确认安全加固项比如PermitRootLogin prohibit-password MaxAuthTries 3 ClientAliveInterval 300 ClientAliveCountMax 0这些配置不是9.6p1专属的但每次升级都是重新梳理安全基线的好机会。5. 常见问题与避坑实录5.1 sshd启动失败目录权限与主机密钥升级后最常见的启动失败场景有两个。第一个就是前面提到过的/var/empty/sshd must be owned by root and not group or world-writable。很多自制包没在SPEC里显式创建这个目录或者目录权限被之前的操作改过。解决办法chown root:root /var/empty/sshd chmod 755 /var/empty/sshd第二个常见问题是主机密钥缺失。如果升级后日志报sshd: no hostkeys available说明/etc/ssh/下没有密钥文件而旧版本的密钥可能因为路径差异没有被新版本识别。直接用ssh-keygen生成/usr/bin/ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N /usr/bin/ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N /usr/bin/ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N 生成后重启sshd即可。需要提醒一下如果你在升级前没有备份/etc/ssh而rpm安装又因为某些原因删除了密钥文件客户端的known_hosts会报警。这也是为什么我一直强调备份优先。5.2 远程连接被拒绝PAM与认证配置问题还有一种比较隐蔽的情况sshd启动正常但远程登录时密码输入正确却反复认证失败。问题往往不在SSH本身而在PAM配置。统信UOS系统的PAM模块有自己的链路升级OpenSSH后如果/etc/pam.d/sshd文件丢失或者被重置成默认状态可能导致密码验证无法通过。遇到这种问题把备份的/etc/pam.d/sshd恢复回去然后重启sshd。另外如果编译时没有加--with-pam即使配置了UsePAM yessshd启动时也会报错或忽略PAM配置表现同样是密码登录失败。这在自制rpm包时特别容易出现SPEC里一定要把--with-pam配上。5.3 老客户端连不上算法策略变化升级到9.6p1后部分老版本SSH客户端比如一些设备内置的OpenSSH 5.x/6.x可能会出现无法连接的情况日志里通常能看到no matching key exchange method或Unable to negotiate之类的错误。这是新版OpenSSH默认禁用旧算法导致的属于预期的安全行为。如果生产环境确实还有老客户端需要兼容可以针对性地在sshd_config里追加旧算法但不推荐全局放宽最好限定来源IPMatch Address 192.168.1.0/24 KexAlgorithms diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha256 HostKeyAlgorithms ssh-rsa,ssh-dss PubkeyAcceptedKeyTypes ssh-rsa这只是临时过渡方案长期建议推动客户端升级。安全性和兼容性的平衡运维者心里要有一杆秤。5.4 构建报错依赖与宏定义问题最后梳理一下rpmbuild阶段常见的报错和排查思路。如果在./configure阶段报configure: error: *** OpenSSL headers not found基本就是openssl-devel没装好执行rpm -q openssl-devel确认。如果configure报其他依赖缺失根据提示补对应-devel包。如果rpmbuild本身报Failed to parse spec file通常是SPEC里宏定义或标签写错了用rpmlint检查一下rpmlint openssh.spec还有一个非常实际的坑rpmbuild要求当前用户家目录下存在.rpmmacros文件如果没配置构建时可能报找不到顶层目录。建议在构建用户家目录创建echo %_topdir %(echo $HOME)/rpmbuild ~/.rpmmacros cat ~/.rpmmacros EOF %_topdir %(echo $HOME)/rpmbuild EOF如果是内网离线环境所有依赖包都需要提前准备好。在能联网的构建机上执行yum install --downloadonly --downloaddir/tmp/openssh-build-deps gcc make openssl-devel zlib-devel pam-devel krb5-devel libedit-devel然后把整个目录拷到内网机器上用rpm -Uvh *.rpm离线安装即可。这个套路我反复用了很多次稳得很。5.5 自制包分发的经验生产环境如果不是一两台机器而是一批机器需要升级建议别一台台拷rpm包手动装。更高效的做法是把打好的rpm包放到内网yum仓库然后批量执行升级。我一般用createrepo搭一个简单的内网源mkdir -p /data/yum-repo/openssh-9.6p1 cp RPMS/aarch64/*.rpm /data/yum-repo/openssh-9.6p1/ createrepo /data/yum-repo/openssh-9.6p1在目标机器上配置repo文件指向内网源之后直接yum update openssh openssh-server openssh-clients这样既能统一版本又能利用yum的依赖解析能力避免手动rpm安装时漏装依赖。唯一的教训是repo源里同时存在旧版本和新版本的包时yum可能意外把其他依赖一起升级所以隔离一个独立目录放升级包更稳妥。写在最后的运维心得这批服务器升级完毕到现在已经稳定运行了一段时间回顾整个过程最大的体会是“自制rpm包”这件事真正难的其实不是rpmbuild命令本身而是对系统底层的理解和对风险的敬畏。SPEC文件里一行--with-pam背后是统信UOS整个认证体系的衔接一个/var/empty/sshd目录权限卡住过多少台机器的sshd启动。做信创环境运维没有捷径就是一步一个坑踩出来的。另外想对准备动手的同学说一句先从测试机完整走一遍构建和升级流程确认无误再上生产永远不要在没有任何备用通道的机器上直接升级sshd。把SPEC文件和rpm包保留好放到公司内部源里下次再升级就是把版本号从9.6p1改成9.7p1重新构建一下的事。这套流程一旦跑通以后面对类似需求心态会从容很多。本文还有配套的精品资源点击获取