简介在 Rocky Linux 9.5 系统中OpenSSH 版本直接反映远程管理安全性面向运维人员这套快速升级加固方案针对等保整改、漏洞修复等场景提供将默认 OpenSSH 升级至 10.0p1 版本、配套 OpenSSL 3.5.0 环境所需的 RPM 包与一键加固脚本。包体共 6 个文件包含 openssh、openssh-server、openssh-clients、chkconfig、initscripts 等 5 个 RPM 安装包分别用于更新服务端与客户端组件、补齐系统依赖另有 1 个 upgrade_ssl_ssh.sh 脚本负责串联安装和加固流程整包约 10.96 MB已有 205 人学习使用。实际使用时无需手动编译源码只需上传并赋予脚本执行权限后运行即可自动完成依赖安装、服务重启和 sshd 基础安全设置运行结束后可从 systemctl 输出中确认 sshd 服务已经正常进入 active (running) 状态执行过程的关键输出也会保留在控制台便于查看升级结果和回溯错误。方案适合需要按时完成 OpenSSH 补丁升级、又希望降低手工操作风险的中小规模服务器环境。1. OpenSSH 加固为什么我盯上了 RockyLinux 9.5 的 SSH 与 SSL 升级SSH 服务大概是每台 Linux 服务器上最“显眼”的攻击面偏偏系统自带的 OpenSSH 版本往往落后于安全通告的要求。我在某公司的模拟项目X环境里就吃过一次亏等保巡检一扫描OpenSSH 老版本中招一堆 CVE客户只丢下一句“该升就升别让 SSH 成为黑匣子”。而 RockyLinux 9.5 自带的是 OpenSSH 8.7p1 和 OpenSSL 3.0.7距离 10.0p1、3.5.0 这两个较新版本还差着一大截。最麻烦的是Red Hat 系系统里 sshd 和 openssl 深度绑定直接替换二进制极易把 sshd 搞到起不来远程机器直接失联。所以这个升级加固脚本的核心价值在于把 OpenSSH 10.0p1 和 OpenSSL 3.5.0 编译成 RPM 包再通过一套可重复的脚本完成依赖处理、编译安装、配置加固和验证回滚。它适合两类人一类是卡在等保合规、漏扫报告上不得不升的运维另一类是像我这样对“编译安装一时爽升级回滚火葬场”有阴影、想找一条稳路的人。这篇笔记就把我实际跑通的升级流程、参数取舍和踩过的坑都写下来。2. 升级前摸底版本选择与 RPM 打包思路2.1 为什么非要 RPM 而不是 make install 直接装很多新手拿到 OpenSSH 10.0p1 源码第一反应是 ./configure make make install。在 RockyLinux 9.5 上这么干大概率会把系统搞进 rescue 模式。原因很简单系统里 yum、rpm、sudo 这些关键工具都动态链接了系统的 OpenSSL 库你贸然用新版本覆盖了 /usr/lib64 下的 libssl.so 和 libcrypto.so整个用户态的依赖链就断了。我一般会坚持把 OpenSSH 和 OpenSSL 都打成 RPM 再装核心好处有三个一是 rpm 数据库会记录文件清单卸载和回滚有据可查二是可以通过 rpm -qp 检查依赖关系提前发现缺库问题三是升级脚本可以把 SRPM 的构建过程固化成 spec 文件换一台机器也能复现。这个脚本也正是按这条路走的先做 OpenSSL 3.5.0 的 RPM再做 OpenSSH 10.0p1 的 RPM最后才动系统配置。2.2 版本对应关系与安装前置条件在 RockyLinux 9.5 上做这个升级版本组合要提前想清楚。OpenSSH 10.0p1 对 OpenSSL 的版本要求比较宽容但如果你只升 OpenSSH 而不升 OpenSSL编译时大概率会碰到头文件路径不一致的问题。脚本里直接把 OpenSSL 也升到 3.5.0就是为了让 sshd 链接的 libssl 和编译时的头文件版本完全对齐。安装前置条件里最容易被忽略的是编译工具链和依赖库。以下这些包在 RockyLinux 9.5 上缺一不可dnf install -y gcc gcc-c make perl zlib-devel \ krb5-devel pam-devel libselinux-devel \ x11-util-libs openssl-devel rpm-build这行命令里每个包都有明确用途gcc/gcc-c 是编译 OpenSSL 和 OpenSSH 的基础工具链perl 是 OpenSSL 构建脚本的依赖少了它 Configure 步骤会直接报错zlib-devel 对应压缩支持OpenSSH 的压缩传输依赖它krb5-devel 提供 Kerberos 支持如果你不需要 GSSAPI 认证可以去掉但留着能减少后续 configure 的参数调整pam-devel 和 libselinux-devel 则是为了让 sshd 能正常集成 PAM 认证和 SELinux 上下文。这里有一个细节要注意RockyLinux 9.5 自带的 openssl-devel 是 3.0.7 版本而脚本要构建的 OpenSSL 3.5.0 是独立路径安装。为了避免两个版本的头文件和库互相干扰我建议把新版本安装到 /usr/local/ssl 而不是覆盖系统路径这个选择在后面配置环境变量时会省掉很多麻烦。2.3 spec 文件里最关键的三处定制RPM 构建的核心是 spec 文件。脚本里对 OpenSSL 和 OpenSSH 的 spec 都做了定制其中三个点直接影响升级后的稳定运行。第一个是 OpenSSL 的安装路径。默认 spec 会安装到 /usr/local/openssl但为了保证 sshd 能找到新库我在 spec 里明确设置了--openssldir/usr/local/ssl同时用%config声明了 openssl.cnf。这样 rpm 卸载时不会把管理员改过的配置文件直接删掉会保留成 .rpmsave 文件。第二个是 OpenSSH 的 configure 参数。脚本里我特别关注这几个./configure --prefix/usr \ --sysconfdir/etc/ssh \ --with-md5-passwords \ --with-pam \ --with-ssl-dir/usr/local/ssl \ --with-privsep-path/var/empty/sshd \ --with-zlib--prefix/usr是为了让 sshd 二进制和系统原有的路径保持一致避免 ssh 命令找不到 sftp-server 这类辅助程序--with-ssl-dir/usr/local/ssl是核心它让编译时链接的是新升级的 OpenSSL 3.5.0--with-privsep-path/var/empty/sshd对应 privilege separation 沙箱目录这个目录如果不存在或权限不对sshd 启动时会报Missing privilege separation directory后面排查章节我会专门讲。第三个是%post和%preun脚本段。我在%post里做了两件事生成新的 SSH host key如果不存在以及帮用户启动新的 sshd 服务。%preun里则保留旧的配置文件备份把/etc/ssh/sshd_config备份为sshd_config.rpmsave。这个设计是为了防止升级后配置不兼容导致 sshd 起不来至少能有一个后悔药可以快速回切。3. 构建 OpenSSL 3.5.0 RPM从源码到可安装的二进制包3.1 准备 RPM 构建目录与源码包先说我习惯的构建方式用普通用户而不是 root 构建 RPM避免构建产物污染系统目录。脚本里通常是在 /root 下直接操作但我建议单独建一个 rpmbuild 目录结构。mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS} cd ~/rpmbuild/SOURCES wget https://www.openssl.org/source/openssl-3.5.0.tar.gz wget https://www.openssl.org/source/openssl-3.5.0.tar.gz.ascRPM 构建时需要 spec 文件里声明的源码包恰好存在于 SOURCES 目录中文件名要严格匹配。如果你是从其他机器拷贝源码包记得检查 tar 包的校验和我遇到过源码包下载不完整导致 BUILD 阶段解压报错的那真是白等半小时。3.2 OpenSSL spec 文件的关键片段与参数说明接着写 spec 文件我通常命名为 openssl3.spec。这个文件不长但每个段落都有讲究Name: openssl3 Version: 3.5.0 Release: 1 Summary: OpenSSL 3.5.0 for RockyLinux 9.5 License: Apache-2.0 Source0: openssl-3.5.0.tar.gz BuildRequires: gcc, perl, make %description OpenSSL 3.5.0 build for sshd upgrade. %prep %setup -q %build ./Configure linux-x86_64 \ --prefix/usr/local/ssl \ --openssldir/usr/local/ssl \ shared zlib enable-cms enable-md2 enable-rc5 \ no-ssl3 no-comp no-afalgeng make -j$(nproc) %install make install DESTDIR%{buildroot} %post ldconfig %files /usr/local/ssl/*这里linux-x86_64是 OpenSSL 在 x86_64 架构上的标准 Configure target注意不要拿 32 位平台的 target 硬套。shared表示构建动态库zlib启用压缩算法支持enable-cms和enable-md2是为了兼容一些老的加密算法需求等保评测里有时会检查这些功能是否可用。no-ssl3是安全加固的硬性要求SSLV3 协议早就被弃用了留着只会让扫描工具报漏洞。%post里的ldconfig很关键新库安装完成后必须刷新动态链接器缓存。如果没有这一步后续编译 OpenSSH 时链接器可能找不到 libssl.so.3就算找到了运行时也可能因为缓存未更新加载到旧版本。3.3 构建 RPM 包并检查产物spec 文件写好之后用 rpmbuild 命令构建cd ~/rpmbuild/SPECS rpmbuild -ba openssl3.spec-ba参数表示同时构建二进制 RPM 和源码 SRPM。构建完成后检查 RPMS 目录下的产物ls -lh ~/rpmbuild/RPMS/x86_64/ rpm -qpl openssl3-3.5.0-1.x86_64.rpm这时重点检查两件事一是 /usr/local/ssl/lib 下有没有 libssl.so.3 和 libcrypto.so.3二是头文件是否存在。如果缺头文件后面编译 OpenSSH 时 configure 会报找不到 opensslv.h。我遇到过 make install 时 DESTDIR 路径写错导致头文件只装到了构建根目录而没进 RPM 包的情况检查产物这一步能提前拦下来。4. 构建 OpenSSH 10.0p1 RPM链接新 SSL 并处理好 PAM 与依赖4.1 源码准备与 spec 文件填写要点OpenSSH 10.0p1 的源码包也放到 SOURCES 目录同时需要一个独立的 spec 文件。这里我特别提醒一点不要直接拿系统自带的 openssh.spec 来改因为 RockyLinux 9.5 的官方 spec 是针对 8.7p1 调优过的直接套在新版本上可能漏掉新增的编译选项。我一般新建一个 openssh.spec核心填写如下Name: openssh Version: 10.0p1 Release: 1 Summary: OpenSSH 10.0p1 with OpenSSL 3.5.0 License: BSD Source0: openssh-10.0p1.tar.gz BuildRequires: gcc, make, pam-devel, zlib-devel, krb5-devel Requires: openssl3 3.5.0 %description OpenSSH 10.0p1 for security hardening. %prep %setup -q %build ./configure --prefix/usr \ --sysconfdir/etc/ssh \ --with-md5-passwords \ --with-pam \ --with-ssl-dir/usr/local/ssl \ --with-privsep-path/var/empty/sshd \ --with-zlib make -j$(nproc) %install make install DESTDIR%{buildroot} %files /usr/bin/ssh /usr/bin/scp /usr/bin/sftp /usr/sbin/sshd /usr/libexec/openssh/* /etc/ssh/*Requires: openssl3 3.5.0这行是为了让 rpm 在安装 openssh 时先检查 OpenSSL 3.5.0 是否已安装避免装完 sshd 再发现库不对。如果你按顺序先装 openssl3 再装 openssh这个依赖关系通常不会触发问题但如果跨机器分发 RPM这个字段能避免低级错误。4.2 PAM 与 GSSAPI 的配置取舍OpenSSH 编译时有两个参数经常让人纠结一个是--with-pam一个是--with-kerberos5。我的建议是 PAM 必须开启因为 RockyLinux 9.5 的登录流程高度依赖 PAM 模块如果编译时不带 PAM 支持sshd 无法正确调用 password-auth 和 system-auth 堆栈可能出现密码正确却登录失败的情况。Kerberos5 取决于你的环境是否需要 GSSAPI 认证。一般企业内部没有 Kerberos 域的话我建议不启用因为编译时需要 krb5-devel运行时还可能带来未知的认证延迟。但如果你要对接某个跨平台系统的统一认证那就加上--with-kerberos5/usr/kerberos并确保系统里有 krb5-libs。还有一个容易被忽略的参数是--with-privsep-path/var/empty/sshd。新版本 OpenSSH 对权限分离目录的安全性要求很高这个目录必须存在且属主是 root权限不能有写权限。如果目录配置不对sshd 启动时会直接拒绝工作。4.3 构建并安装 RPM 包spec 文件写好后同样的流程构建cd ~/rpmbuild/SPECS rpmbuild -ba openssh.spec构建过程需要几分钟到十几分钟不等取决于机器 CPU 核数。结束后进入安装阶段。这里顺序很重要rpm -Uvh ~/rpmbuild/RPMS/x86_64/openssl3-3.5.0-1.x86_64.rpm rpm -Uvh ~/rpmbuild/RPMS/x86_64/openssh-10.0p1-1.x86_64.rpm先装 OpenSSL再装 OpenSSH顺序反了会导致 OpenSSH 安装时找不到 libssl.so.3。安装完成后先别急着重启 sshd先检查 sshd 是否能正常解析配置/usr/sbin/sshd -t这一步会打印配置文件的语法错误和参数冲突。我通常会在安装后跑一次sshd -T来查看生效的配置参数确认 sshd 确实链接到了新的 OpenSSL 版本ldd /usr/sbin/sshd | grep ssl正常输出应该包含libssl.so.3 /usr/local/ssl/lib/libssl.so.3。如果这里显示的还是系统自带的 libssl.so.1.1说明 configure 阶段--with-ssl-dir参数没有真正生效需要检查 spec 文件里的编译参数是否被正确传递。5. 配置加固与升级后第一次启动常见问题排查与避坑指南5.1 sshd_config 加固参数详解OpenSSH 10.0p1 装好后配置加固是重头戏。我按照安全基线要求对 /etc/ssh/sshd_config 做了以下调整Port 22 Protocol 2 PermitRootLogin no MaxAuthTries 3 MaxSessions 4 PubkeyAuthentication yes PasswordAuthentication no PermitEmptyPasswords no ChallengeResponseAuthentication no UsePAM yes X11Forwarding no ClientAliveInterval 300 ClientAliveCountMax 2 AllowUsers root admin这里几个参数都有实际意义Protocol 2在 OpenSSH 10.0p1 里其实是默认值但显式写出来能提醒自己不要回退到 1.x 兼容模式PermitRootLogin no是等保测评的常见要求如果你确实需要 root 远程登录可以改成prohibit-password允许密钥登录但禁止密码登录PasswordAuthentication no和PubkeyAuthentication yes搭配是为了彻底关闭密码爆破路径但要注意如果服务器还没部署公钥就关掉密码认证你会被锁在外面所以这个参数一定要在确认密钥登录可用后再改。AllowUsers这行需要注意如果你不需要限制用户建议直接删掉否则会影响所有未列出的用户登录。我一般在加固脚本里默认不启用这个参数只留注释模板。5.2 升级后 sshd 启动失败的高频原因与解决方案以下三条是我在实际升级中踩过的最典型的坑每条都按「现象 → 原因 → 解决」记录坑一sshd 报 Missing privilege separation directory。现象/usr/sbin/sshd -t输出Missing privilege separation directory: /var/empty/sshd。原因新版本 OpenSSH 编译时指定的 privsep 目录在系统里不存在或者权限不对。解决mkdir -p /var/empty/sshd chown root:root /var/empty/sshd chmod 755 /var/empty/sshd这里权限必须是 755 而不能是 700因为 sshd 运行时需要以 unprivileged 用户进入该目录。如果之前装过旧版本目录里可能有残留文件建议先清空再重新设置权限。坑二sshd 启动后服务正常但远程密码登录一直失败。现象系统日志里能看到Failed password记录但密码明明是对的。原因编译 OpenSSH 时没有带 PAM 支持或者UsePAM no导致 sshd 绕过了 PAM 认证堆栈。解决确认编译参数里有--with-pam并在 sshd_config 里设UsePAM yes。如果用的是系统自带的 PAM 配置还要检查 /etc/pam.d/sshd 是否存在不存在就从 sshd 的样例配置里拷一份。坑三升级后 yum 或 rpm 命令报错openssl: error while loading shared libraries。现象执行 dnf 时直接崩溃提示找不到 libssl.so。原因新 OpenSSL 安装到了 /usr/local/ssl但系统的动态链接器缓存没有把它加进去或者环境变量 LD_LIBRARY_PATH 覆盖了系统库搜索路径。解决echo /usr/local/ssl/lib /etc/ld.so.conf.d/openssl3.conf ldconfig执行完 ldconfig 后用ldconfig -p | grep libssl确认两条路径都存在。这个坑最容易出现在用make install而不是 RPM 安装的场景里RPM 安装方式下%post里的 ldconfig 已经帮你处理了。5.3 回滚方案与备份策略升级前无论如何都要做备份这是我的血泪经验。脚本默认在升级前执行一次全量备份备份内容包括 /etc/ssh 整个目录和当前 sshd 的二进制。tar -czf /backup/ssh_backup_$(date %Y%m%d).tar.gz /etc/ssh cp /usr/sbin/sshd /backup/sshd_old rpm -qa | grep openssh /backup/openssh_rpm_list.txt如果升级后出现无法解决的问题回滚分为两步第一步把 sshd_config 恢复成备份版本第二步用 rpm -Uvh --oldpackage 装回旧版本 RPM。我一般是把旧 RPM 文件先留一份在 /backup 目录因为系统仓库里的旧版本可能已经因镜像更新被替换掉了。另外提醒一点升级前检查一下系统的磁盘分区是否预留了足够空间。编译 OpenSSL 和 OpenSSH 需要大约 1GB 的临时空间rpmbuild 目录又会生成大量中间文件如果 /var 或 /home 满了构建会在中途诡异失败还不好排查。6. 验证加固成果从 sshd -T 到全链路登录测试6.1 静态配置验证sshd -T 与二进制链接检查升级折腾完最后一步是验证这个环节必须认真走一遍否则你不知道这次加固到底有没有生效。先看静态层面用sshd -T导出最终生效的配置/usr/sbin/sshd -T | grep -E protocol|permitrootlogin|passwordauthentication|maxauthtries|clientaliveintervalsshd -T会读取配置文件并输出所有生效参数但不会真正启动服务。它比直接 grep 配置文件更可靠因为配置里有默认值和条件块直接看文本容易理解错。例如PasswordAuthentication no这一项只有在配置文件里显式设置时sshd -T才会输出对应的值。同时验证二进制层ssh -V ldd /usr/sbin/sshd | grep -E ssl|cryptossh -V应该输出OpenSSH_10.0p1ldd检查结果应指向/usr/local/ssl/lib下的新库。这两个命令一跑版本匹配和动态链接情况一目了然。6.2 动态验证重启服务与真实登录测试静态验证通过后重启 sshd 服务systemctl restart sshd systemctl status sshd如果重启失败systemctl status会直接显示失败原因同时查看 /var/log/messages 里 sshd 的启动日志。这里有一个重要原则不要因为急于验证而关闭当前 SSH 连接因为一旦 sshd 重启失败当前连接也会被断开你会完全失去这台机器的访问途径。我一般会开两个 SSH 窗口一个留着不动另一个用来重启和测试。如果重启失败且第一个连接也掉线就要靠带外管理口或者本机控制台救急了。避免这种极端情况的唯一办法就是前面说的升级前备份好配置和旧二进制并且确认系统开启了 sshd 的自动启动。真实的登录测试包括密码认证和密钥认证两条链路。如果关闭了密码认证重点测试密钥登录ssh -i ~/.ssh/id_rsa testuser127.0.0.1在服务器本机跑这个命令可以验证 sshd 是否按预期接受密钥。接着从一台远端机器再试一次公网 IP 的登录确认服务端口和防火墙规则也正常。6.3 连接保持的细节ClientAlive 参数与长连接体验最后提一个我经常跟别人强调的设置ClientAliveInterval和ClientAliveCountMax的组合。这两个参数决定服务器多久探测一次空闲连接以及允许连续多少次探测无响应。ClientAliveInterval 300 ClientAliveCountMax 2这组参数的意思是每 300 秒发一次 keepalive 包连续 2 次无响应就断开连接。加固文档里通常要求这类参数开启但我见过不少人把ClientAliveInterval设成 60结果用户稍微挂机几分钟就被踢下线体验很差。我的习惯是 300 秒配 2 次既能识别连接失效又不会误杀短暂离开的会话。从那次在模拟项目X里差点因为升级把 SSH 搞挂之后我养成了一个习惯每次升级 OpenSSH 或 OpenSSL无论时间多紧都要强制走一遍「备份 → 构建 RPM → sshd -T 静态验证 → 双窗口重启 → 本机密钥登录 → 远端登录」这条链。这套流程确实让后续的环境搭建少了很多“玄学”问题。希望这份笔记能帮到你照着跑通一次你也会对这套升级加固方案建立起信心。本文还有配套的精品资源点击获取