常见的Linux发行版升级openSSH10.+

当你在终端输入ssh user@server时,这个简单命令的背后,是 OpenSSH 协议二十余年的安全积淀。作为 Linux 系统远程管理的 "生命线",OpenSSH 的每一次大版本迭代,都直接影响企业服务器的安全防线 ------2025 年 4 月 9 日发布的 OpenSSH 10.0,以禁用脆弱加密算法、拆分认证模块等颠覆性升级,成为云原生时代的安全刚需。

而在实际运维中,不同主流发行版的 SSH 10 适配节奏差异显著:CentOS 7.9 + 因系统基线较旧需突破依赖限制,Ubuntu 22.04 + 作为 LTS 版本提供稳定但非默认的更新路径,openEuler 22.03 则凭借国产化适配优势实现快速落地。本文聚焦这三大高频使用的发行版,带你避开升级陷阱,掌握从依赖准备到实战部署的全流程技巧。

一. SSH 10重构远程安全的底层逻辑

1.1 版本迭代背后的安全诉求

OpenSSH 10.0 的发布并非简单功能叠加,而是针对近年密码学漏洞的系统性修复。根据官方 Release Notes,核心驱动来自两大痛点:SHA-1 哈希函数破解风险加剧、传统认证架构存在权限溢出隐患。开发团队重构 30% 核心代码后,三个变化对运维场景影响最深远:

  • 加密套件 "大清洗":默认禁用diffie-hellman-group1-sha1等 6 种老旧密钥交换算法,强制启用 TLS 1.3 协商 ------ 这意味着旧版客户端(如 CentOS 6 自带 SSH)将直接被拒绝,倒逼设备更新。
  • 认证模块独立化:将用户认证从sshd-session剥离至全新sshd-auth进程,即便攻击者突破会话层,也无法触及认证核心,相当于给登录加了 "安全隔离舱"。
  • FIDO 硬件密钥原生支持:无需额外插件即可对接 YubiKey,实现 "双因素认证 + 密钥登录" 双重防护,彻底解决密码泄露风险 ------ 这对需合规的企业场景(如金融、政务)尤为关键。

1.2 三大目标发行版的 SSH 10 适配 "成绩单"

截至 2025 年 10 月,CentOS 7.9+、Ubuntu 22.04+、openEuler 22.03 的 SSH 10 支持情况呈现差异化特征,适配策略需针对性调整:

|-----------------|----------------------------|----------------------------------------|---------------------------|
| 发行版 | 支持状态 | 核心更新路径 | 关键特性适配细节 |
| CentOS 7.9+ | 需突破依赖限制(无官方源) | EPEL 源 + 编译结合(先升 OpenSSL) | 需手动启用 FIDO,SELinux 策略需自定义 |
| Ubuntu 22.04+ | 稳定支持(backports 源)/ 最新版需要编译 | apt -t jammy-backports install openssh | 默认禁用旧算法,FIDO 即开即用 |
| openEuler 22.03 | 需要编译 | dnf install openssh | 集成国产化密钥工具,适配麒麟硬件 |

实操案例

  • CentOS 7.9 用户需先解决 OpenSSL 依赖(默认 1.0.2k 需升级至 3.5+):通过 SCL 源安装rh-openssl30,再编译 SSH 10 源码,编译时需指定--with-ssl-dir=/opt/rh/rh-openssl30/root/usr。
  • Ubuntu 22.04 用户启用 backports 源后,升级后需重启ssh.service,系统会自动备份旧配置至/etc/ssh/sshd_config.dpkg-old,无需手动迁移。
  • openEuler 22.03 用户直接通过官方源安装后,可通过ssh-keygen -t ecdsa-sk生成 FIDO 硬件密钥,适配国产飞天云等环境时无需额外配置。

1.3 三大发行版的兼容性陷阱与规避方案

升级 SSH 10 的核心风险集中在兼容性,需针对各发行版特性规避:

  • CentOS 7.9+:依赖与权限双重陷阱

问题 1:编译后sshd启动报错 "libcrypto.so.3: cannot open shared object file"------ 需在/etc/ld.so.conf.d/新增文件,写入/opt/rh/rh-openssl30/root/usr/lib64,执行ldconfig生效。

问题 2:SELinux 阻止sshd-auth进程运行 ------ 需执行setsebool -P sshd_full_access on,或自定义策略模块(audit2allow -a -M sshd_auth)。

  • Ubuntu 22.04+:配置与监控适配

问题 1:旧版sshd_config中AllowUsers配置冲突 ------ 升级后需将用户限制配置迁移至/etc/ssh/sshd_config.d/目录下的.conf文件,避免主配置被覆盖。

问题 2:Zabbix 监控识别错误 ------ 因协议标识改为SSH-2.0-OpenSSH_10.0,需修改监控项正则表达式,将OpenSSH_[0-9]+\.[0-9]+调整为OpenSSH_[0-9]+\.[0-9]+|OpenSSH_10\.0。

  • openEuler 22.03:硬件密钥适配

问题:部分国产 USB Key(如华大智宝)无法识别 ------ 需安装openssl-pkcs11包,通过ssh-keygen -t ecdsa-sk -O provider=pkcs11指定 PKCS#11 驱动路径,即可正常生成密钥。

今天的这篇文章主要包含了Centos的发行版本,Ubuntu发行版本,OpenEuler发行版本的ssh升级。

一.5 执行脚本前必看

1. 在升级ssh服务的时候一定要多开窗口,避免升级失败导致无法连接到服务器中。

2. 此脚本的包是放在了阿里云OSS对象存储中,如果出现404NotFount的情况请使用如下网盘链接获取包:通过网盘分享的文件:202509openssh.tar
链接: https://pan.baidu.com/s/1PUPpwo19PRC1yRROYr1SpA?pwd=uvr9 提取码: uvr9

3. Centos操作系统网盘链接:通过网盘分享的文件:openssh-10.2p1&openssh-3.0.18.el7.tar.gz
链接: https://pan.baidu.com/s/1pleTY4vF2E2wXMH4Vs_1tA?pwd=hhhj 提取码: hhhj

4. 脚本在执行前一定要有阅览脚本内容的好习惯,这不仅对脚本报错和环境适配起到重要作用。

二. OpenEuler22.03+自动升级OpenSSH10+OpenSSL3.6

本脚本实现了自动检测版本,然后备份旧版本文件,升级OpenSSH与SSL,升级过程中遇到故障也会自动回滚。

bash 复制代码
#!/bin/bash
# OpenSSH安全升级脚本 for 生产环境
# 版本: 2.1 (更新最后认证功能)
# 日期: 2025-10-13
# 脚本执行成功最后请source一下环境profile文件

# 全局变量
BACKUP_DIR="/home/ssh-old-bak-$(date +%Y%m%d_%H%M%S)"
LOG_FILE="/var/log/ssh_upgrade_$(date +%Y%m%d_%H%M%S).log"
TAR_URL="https://loop-bucket.oss-cn-shanghai.aliyuncs.com/202509openssh.tar"
TAR_FILE="/tmp/openssh.tar"
TARGET_DIR="/usr"
NEW_SSH_SERVICE="sshd10.service"
OLD_SSH_SERVICE="sshd.service"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 日志函数
log() {
    echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

# 错误处理函数
error_exit() {
    log "${RED}ERROR: $1${NC}"
    log "${YELLOW}开始回滚操作...${NC}"
    rollback
    exit 1
}

# 回滚函数
rollback() {
    log "开始回滚到原始状态..."
    
    # 停止新的ssh服务
    if systemctl is-active --quiet "$NEW_SSH_SERVICE"; then
        log "停止新的SSH服务: $NEW_SSH_SERVICE"
        systemctl stop "$NEW_SSH_SERVICE" || log "警告: 停止新服务失败"
    fi
    
    # 恢复旧的ssh服务
    if [ -d "$BACKUP_DIR" ]; then
        log "恢复旧的SSH配置文件..."
        
        # 恢复sshd二进制文件
        if [ -f "$BACKUP_DIR/sshd" ]; then
            # 如果目标文件存在,先备份
            if [ -f "/usr/sbin/sshd" ]; then
                mv -f "/usr/sbin/sshd" "/usr/sbin/sshd.new" || log "警告: 备份新sshd文件失败"
            fi
            mv -f "$BACKUP_DIR/sshd" "/usr/sbin/sshd" || log "警告: 恢复sshd二进制文件失败"
        fi
        
        # 恢复配置目录
        if [ -d "$BACKUP_DIR/ssh" ]; then
            # 如果目标目录存在,先备份
            if [ -d "/etc/ssh" ]; then
                mv -f "/etc/ssh" "/etc/ssh.new" || log "警告: 备份新ssh配置目录失败"
            fi
            mv -f "$BACKUP_DIR/ssh" "/etc/ssh" || log "警告: 恢复/etc/ssh目录失败"
        fi
        
        # 恢复systemd服务文件
        for service_file in sshd-keygen.service sshd.service sshd@.service sshd.socket; do
            if [ -f "$BACKUP_DIR/$service_file" ]; then
                # 如果目标文件存在,先备份
                if [ -f "/usr/lib/systemd/system/$service_file" ]; then
                    mv -f "/usr/lib/systemd/system/$service_file" "/usr/lib/systemd/system/${service_file}.new" || log "警告: 备份新$service_file失败"
                fi
                mv -f "$BACKUP_DIR/$service_file" "/usr/lib/systemd/system/$service_file" || log "警告: 恢复$service_file失败"
            fi
        done
        
        # 重新加载systemd配置
        systemctl daemon-reload
        
        # 启动旧的ssh服务
        if systemctl is-enabled --quiet "$OLD_SSH_SERVICE"; then
            systemctl start "$OLD_SSH_SERVICE" || log "警告: 启动旧SSH服务失败"
        fi
    fi
    
    # 清理临时文件
    if [ -f "$TAR_FILE" ]; then
        rm -f "$TAR_FILE"
    fi
    
    log "${YELLOW}回滚操作完成,请检查系统状态${NC}"
}

# 预检查函数
pre_check() {
    log "${GREEN}开始预检查...${NC}"
    
    # 检查是否以root用户运行
    if [ "$(id -u)" -ne 0 ]; then
        error_exit "必须以root用户运行此脚本"
    fi
    
    # 检查网络连接
    if ! ping -c 1 -W 5 string-file.oss-cn-shanghai.aliyuncs.com > /dev/null 2>&1; then
        error_exit "无法连接到下载服务器,请检查网络连接"
    fi
    
    # 检查wget是否安装
    if ! command -v wget &> /dev/null; then
        error_exit "wget未安装,请先安装wget"
    fi
    
    # 检查tar是否安装
    if ! command -v tar &> /dev/null; then
        error_exit "tar未安装,请先安装tar"
    fi
    
    # 检查当前ssh服务状态
    if ! systemctl is-active --quiet "$OLD_SSH_SERVICE"; then
        error_exit "当前SSH服务未运行,无法继续升级"
    fi
    
    # 检查是否有正在进行的ssh连接
    SSH_CONNECTIONS=$(who | grep -c pts)
    if [ "$SSH_CONNECTIONS" -gt 1 ]; then
        log "${YELLOW}警告: 检测到$SSH_CONNECTIONS个活跃的SSH连接${NC}"
        read -p "是否继续升级? (y/n): " confirm
        if [ "$confirm" != "y" ]; then
            error_exit "用户取消了升级操作"
        fi
    fi
    
    log "${GREEN}预检查完成,开始升级操作${NC}"
}

# 下载和解压函数
download_and_extract() {
    log "${GREEN}开始下载OpenSSH安装包...${NC}"
    
    # 下载tar包
    if ! wget --no-check-certificate -O "$TAR_FILE" "$TAR_URL"; then
        error_exit "下载OpenSSH安装包失败"
    fi
    
    # 验证文件是否下载成功
    if [ ! -f "$TAR_FILE" ] || [ ! -s "$TAR_FILE" ]; then
        error_exit "下载的文件为空或不存在"
    fi
    
    log "下载完成,开始解压..."
    
    # 解压到/usr目录
    if ! tar -xf "$TAR_FILE" -C "$TARGET_DIR"; then
        error_exit "解压安装包失败"
    fi
    
    # 验证解压结果
    if [ ! -d "$TARGET_DIR/openssh" ]; then
        error_exit "解压后未找到openssh目录"
    fi
    
    log "${GREEN}下载和解压完成${NC}"
}

# 配置环境变量函数
configure_environment() {
    log "${GREEN}开始配置环境变量...${NC}"
    
    # 备份profile文件
    cp -p /etc/profile "/etc/profile.bak.$(date +%Y%m%d_%H%M%S)" || error_exit "备份/etc/profile失败"
    
    # 检查环境变量是否已存在,如果存在则更新
    if grep -q "OpenSSH 10.2p1 Environment Variables" /etc/profile; then
        log "${YELLOW}环境变量配置已存在,更新配置...${NC}"
        # 删除旧的配置
        sed -i '/# OpenSSH 10.2p1 Environment Variables/,+4d' /etc/profile
    fi
    
    # 添加环境变量配置
    cat >> /etc/profile << 'EOF'

# OpenSSH 10.2p1 Environment Variables
export LD_LIBRARY_PATH=/usr/openssh/openssl-3.6.0-beta1/lib64:$LD_LIBRARY_PATH
export PATH=/usr/openssh/openssh-10.2p1/bin:/usr/openssh/openssh-10.2p1/sbin:/usr/openssh/openssl-3.6.0-beta1/bin:$PATH
export CFLAGS="-I/usr/openssh/openssl-3.6.0-beta1/include"
export LDFLAGS="-L/usr/openssh/openssl-3.6.0-beta1/lib64"
EOF
    
    # 验证配置是否添加成功
    if ! grep -q "OpenSSH 10.2p1 Environment Variables" /etc/profile; then
        error_exit "添加环境变量配置失败"
    fi
    
    # 立即生效环境变量
    source /etc/profile
    
    log "${GREEN}环境变量配置完成${NC}"
}

# 创建systemd服务文件函数
create_systemd_service() {
    log "${GREEN}开始创建systemd服务文件...${NC}"
    
    # 备份现有服务文件(如果存在)
    if [ -f "/usr/lib/systemd/system/$NEW_SSH_SERVICE" ]; then
        cp -p "/usr/lib/systemd/system/$NEW_SSH_SERVICE" "/usr/lib/systemd/system/${NEW_SSH_SERVICE}.bak.$(date +%Y%m%d_%H%M%S)"
        log "${YELLOW}已备份现有$NEW_SSH_SERVICE服务文件${NC}"
    fi
    
    # 创建sshd10.service文件
    cat > "/usr/lib/systemd/system/$NEW_SSH_SERVICE" << 'EOF'
[Unit]
Description=OpenSSH server daemon (v10.2p1)
After=network.target

[Service]
Type=simple
Environment=LD_LIBRARY_PATH=/usr/openssh/openssl-3.6.0-beta1/lib64
ExecStart=/usr/openssh/openssh-10.2p1/sbin/sshd -D -f /usr/openssh/openssh-10.2p1/etc/sshd_config
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target
EOF
    
    # 设置文件权限
    chmod 644 "/usr/lib/systemd/system/$NEW_SSH_SERVICE"
    
    # 验证服务文件是否创建成功
    if [ ! -f "/usr/lib/systemd/system/$NEW_SSH_SERVICE" ]; then
        error_exit "创建$NEW_SSH_SERVICE服务文件失败"
    fi
    
    log "${GREEN}systemd服务文件创建完成${NC}"
}

# 备份旧配置函数 - 改进版
backup_old_config() {
    log "${GREEN}开始备份旧的SSH配置...${NC}"
    
    # 创建备份目录
    if ! mkdir -p "$BACKUP_DIR"; then
        error_exit "创建备份目录失败"
    fi
    
    # 备份配置目录 - 先检查是否存在
    if [ -d "/etc/ssh" ]; then
        log "备份/etc/ssh目录..."
        # 使用cp而不是mv,确保源文件保持不变
        if ! cp -rp /etc/ssh "$BACKUP_DIR/"; then
            error_exit "备份/etc/ssh失败"
        fi
        log "成功备份/etc/ssh到$BACKUP_DIR/"
    else
        log "${YELLOW}警告: /etc/ssh目录不存在,跳过备份${NC}"
    fi
    
    # 备份sshd二进制文件
    if [ -f "/usr/sbin/sshd" ]; then
        log "备份sshd二进制文件..."
        if ! cp -p /usr/sbin/sshd "$BACKUP_DIR/"; then
            error_exit "备份sshd二进制文件失败"
        fi
        log "成功备份sshd到$BACKUP_DIR/"
    else
        log "${YELLOW}警告: /usr/sbin/sshd文件不存在,跳过备份${NC}"
    fi
    
    # 备份systemd服务文件
    for service_file in sshd-keygen.service sshd.service sshd@.service sshd.socket; do
        if [ -f "/usr/lib/systemd/system/$service_file" ]; then
            log "备份$service_file服务文件..."
            if ! cp -p "/usr/lib/systemd/system/$service_file" "$BACKUP_DIR/"; then
                log "${YELLOW}警告: 备份$service_file失败${NC}"
            else
                log "成功备份$service_file到$BACKUP_DIR/"
            fi
        else
            log "${YELLOW}警告: $service_file文件不存在,跳过备份${NC}"
        fi
    done
    
    log "${GREEN}旧配置备份完成,备份目录: $BACKUP_DIR${NC}"
}

# 停止旧服务函数
stop_old_service() {
    log "${GREEN}开始停止旧的SSH服务...${NC}"
    
    # 停止sshd服务
    if systemctl is-active --quiet "$OLD_SSH_SERVICE"; then
        log "停止$OLD_SSH_SERVICE服务..."
        if ! systemctl stop "$OLD_SSH_SERVICE"; then
            error_exit "停止旧SSH服务失败"
        fi
        log "$OLD_SSH_SERVICE服务已停止"
    else
        log "${YELLOW}警告: $OLD_SSH_SERVICE服务未运行,跳过停止操作${NC}"
    fi
    
    # 禁用sshd服务
    if systemctl is-enabled --quiet "$OLD_SSH_SERVICE"; then
        log "禁用$OLD_SSH_SERVICE服务..."
        if ! systemctl disable "$OLD_SSH_SERVICE"; then
            error_exit "禁用旧SSH服务失败"
        fi
        log "$OLD_SSH_SERVICE服务已禁用"
    else
        log "${YELLOW}警告: $OLD_SSH_SERVICE服务未启用,跳过禁用操作${NC}"
    fi
    
    # 等待服务完全停止
    sleep 5
    
    # 验证服务是否已停止
    if systemctl is-active --quiet "$OLD_SSH_SERVICE"; then
        error_exit "旧SSH服务仍在运行,无法继续升级"
    fi
    
    log "${GREEN}旧SSH服务处理完成${NC}"
}

# 移动旧文件函数 - 改进版
move_old_files() {
    log "${GREEN}开始处理旧的SSH文件...${NC}"
    
    # 移动配置目录 - 先检查是否存在
    if [ -d "/etc/ssh" ]; then
        log "移动/etc/ssh目录到备份目录..."
        # 使用mv命令,先检查目标是否存在
        if [ -d "$BACKUP_DIR/ssh" ]; then
            # 如果目标存在,先删除(因为我们已经用cp备份过了)
            rm -rf "$BACKUP_DIR/ssh" || error_exit "删除旧备份目录失败"
        fi
        if ! mv /etc/ssh "$BACKUP_DIR/"; then
            error_exit "移动/etc/ssh失败"
        fi
        log "成功移动/etc/ssh到$BACKUP_DIR/"
    else
        log "${YELLOW}警告: /etc/ssh目录不存在,跳过移动操作${NC}"
    fi
    
    # 移动sshd二进制文件
    if [ -f "/usr/sbin/sshd" ]; then
        log "移动sshd二进制文件到备份目录..."
        # 使用mv命令,先检查目标是否存在
        if [ -f "$BACKUP_DIR/sshd" ]; then
            # 如果目标存在,先删除(因为我们已经用cp备份过了)
            rm -f "$BACKUP_DIR/sshd" || error_exit "删除旧备份文件失败"
        fi
        if ! mv /usr/sbin/sshd "$BACKUP_DIR/"; then
            error_exit "移动sshd二进制文件失败"
        fi
        log "成功移动sshd到$BACKUP_DIR/"
    else
        log "${YELLOW}警告: /usr/sbin/sshd文件不存在,跳过移动操作${NC}"
    fi
    
    # 移动systemd服务文件
    for service_file in sshd-keygen.service sshd.service sshd@.service sshd.socket; do
        if [ -f "/usr/lib/systemd/system/$service_file" ]; then
            log "移动$service_file服务文件到备份目录..."
            # 使用mv命令,先检查目标是否存在
            if [ -f "$BACKUP_DIR/$service_file" ]; then
                # 如果目标存在,先删除(因为我们已经用cp备份过了)
                rm -f "$BACKUP_DIR/$service_file" || error_exit "删除旧备份文件失败"
            fi
            if ! mv "/usr/lib/systemd/system/$service_file" "$BACKUP_DIR/"; then
                log "${YELLOW}警告: 移动$service_file失败${NC}"
            else
                log "成功移动$service_file到$BACKUP_DIR/"
            fi
        else
            log "${YELLOW}警告: $service_file文件不存在,跳过移动操作${NC}"
        fi
    done
    
    log "${GREEN}旧文件处理完成${NC}"
}

# 启动新服务函数
start_new_service() {
    log "${GREEN}开始启动新的SSH服务...${NC}"
    
    # 重新加载systemd配置
    log "重新加载systemd配置..."
    if ! systemctl daemon-reload; then
        error_exit "重新加载systemd配置失败"
    fi
    
    # 启动新的ssh服务
    log "启动$NEW_SSH_SERVICE服务..."
    if ! systemctl start "$NEW_SSH_SERVICE"; then
        error_exit "启动新SSH服务失败"
    fi
    
    # 等待服务启动
    log "等待服务启动..."
    sleep 10
    
    # 验证服务状态
    if ! systemctl is-active --quiet "$NEW_SSH_SERVICE"; then
        error_exit "新SSH服务启动失败,服务状态异常"
    fi
    
    # 设置开机自启
    log "设置$NEW_SSH_SERVICE服务开机自启..."
    if ! systemctl enable "$NEW_SSH_SERVICE"; then
        log "${YELLOW}警告: 设置新SSH服务开机自启失败${NC}"
    fi
    
    # 显示服务状态
    log "新SSH服务状态:"
    systemctl status "$NEW_SSH_SERVICE" --no-pager | tee -a "$LOG_FILE"
    
    log "${GREEN}新SSH服务启动完成${NC}"
}

# 验证升级结果函数
verify_upgrade() {
    log "${GREEN}开始验证升级结果...${NC}"
    
    # 验证ssh版本
    log "验证SSH版本:"
    SSH_VERSION=$(/usr/openssh/openssh-10.2p1/bin/ssh -V 2>&1)
    log "$SSH_VERSION"
    
    if ! echo "$SSH_VERSION" | grep -q "OpenSSH_10.2p1"; then
        error_exit "SSH版本验证失败,未检测到OpenSSH_10.2p1"
    fi
    
    if ! echo "$SSH_VERSION" | grep -q "OpenSSL 3.6.0-beta1"; then
        error_exit "OpenSSL版本验证失败,未检测到OpenSSL 3.6.0-beta1"
    fi
    
    # 验证环境变量
    log "验证环境变量:"
    if [ -z "$LD_LIBRARY_PATH" ] || [[ "$LD_LIBRARY_PATH" != "/usr/openssh/openssl-3.6.0-beta1/lib64:"* ]]; then
        log "${YELLOW}警告: LD_LIBRARY_PATH环境变量设置不正确${NC}"
    else
        log "LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
    fi
    
    if [ -z "$PATH" ] || [[ "$PATH" != "/usr/openssh/openssh-10.2p1/bin:"* ]]; then
        log "${YELLOW}警告: PATH环境变量设置不正确${NC}"
    else
        log "PATH包含新的SSH路径"
    fi
    
    # 验证服务端口
    log "验证SSH端口状态:"
    if ! netstat -tlnp | grep -q ":22"; then
        error_exit "SSH端口22未监听,服务启动异常"
    fi
    
    log "${GREEN}升级结果验证完成${NC}"
}

# 测试SSH连接函数 - 修复版
test_ssh_connection() {
    log "${GREEN}开始测试SSH连接...${NC}"
    
    # 获取本地IP地址
    LOCAL_IP=$(hostname -I | awk '{print $1}')
    
    if [ -z "$LOCAL_IP" ]; then
        log "${YELLOW}警告: 无法获取本地IP地址,跳过连接测试${NC}"
        return
    fi
    
    log "测试连接到本地IP: $LOCAL_IP"
    
    # 创建测试用户(如果不存在)
    TEST_USER="ssh_test_user_$(date +%s)"
    TEST_PASSWORD=$(openssl rand -base64 12)
    
    log "创建测试用户: $TEST_USER"
    if ! useradd -m "$TEST_USER" &> /dev/null; then
        log "${YELLOW}警告: 创建测试用户失败,跳过连接测试${NC}"
        return
    fi
    
    # 设置测试用户密码
    echo "$TEST_USER:$TEST_PASSWORD" | chpasswd &> /dev/null
    
    # 等待密码生效
    sleep 2
    
    # 使用密码认证测试SSH连接
    log "使用密码认证测试SSH连接..."
    SSH_TEST_OUTPUT=$(sshpass -p "$TEST_PASSWORD" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$TEST_USER@$LOCAL_IP" "echo SSH_TEST_SUCCESS" 2>&1)
    
    if echo "$SSH_TEST_OUTPUT" | grep -q "SSH_TEST_SUCCESS"; then
        log "${GREEN}SSH连接测试成功${NC}"
    else
        # 如果密码认证失败,尝试密钥认证
        log "${YELLOW}密码认证失败,尝试密钥认证...${NC}"
        
        # 生成测试密钥
        ssh-keygen -t rsa -b 2048 -f "/tmp/ssh_test_key" -N "" &> /dev/null
        mkdir -p "/home/$TEST_USER/.ssh"
        cp "/tmp/ssh_test_key.pub" "/home/$TEST_USER/.ssh/authorized_keys"
        chown -R "$TEST_USER:$TEST_USER" "/home/$TEST_USER/.ssh"
        chmod 700 "/home/$TEST_USER/.ssh"
        chmod 600 "/home/$TEST_USER/.ssh/authorized_keys"
        
        # 修复SELinux上下文(如果启用)
        if command -v restorecon &> /dev/null; then
            restorecon -R "/home/$TEST_USER/.ssh" &> /dev/null
        fi
        
        # 使用密钥认证测试
        SSH_TEST_OUTPUT=$(ssh -i "/tmp/ssh_test_key" -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$TEST_USER@$LOCAL_IP" "echo SSH_TEST_SUCCESS" 2>&1)
        
        if echo "$SSH_TEST_OUTPUT" | grep -q "SSH_TEST_SUCCESS"; then
            log "${GREEN}SSH密钥认证测试成功${NC}"
        else
            log "${YELLOW}警告: SSH连接测试失败: $SSH_TEST_OUTPUT${NC}"
            # 不中断升级,只记录警告
        fi
        
        # 清理密钥文件
        rm -f "/tmp/ssh_test_key" "/tmp/ssh_test_key.pub"
    fi
    
    # 清理测试环境
    log "清理测试用户: $TEST_USER"
    userdel -r "$TEST_USER" &> /dev/null
    
    log "${GREEN}SSH连接测试完成${NC}"
}

# 主函数
main() {
    log "${GREEN}=============================================${NC}"
    log "${GREEN}开始OpenSSH安全升级流程 (版本2.1)${NC}"
    log "${GREEN}=============================================${NC}"
    
    # 记录系统信息
    log "系统信息:"
    uname -a | tee -a "$LOG_FILE"
    cat /etc/os-release | grep PRETTY_NAME | tee -a "$LOG_FILE"
    
    # 执行各个步骤
    pre_check
    download_and_extract
    configure_environment
    create_systemd_service
    backup_old_config
    stop_old_service
    move_old_files
    start_new_service
    verify_upgrade
    test_ssh_connection
    
    log "${GREEN}=============================================${NC}"
    log "${GREEN}OpenSSH安全升级完成!${NC}"
    log "${GREEN}新SSH服务: $NEW_SSH_SERVICE${NC}"
    log "${GREEN}备份目录: $BACKUP_DIR${NC}"
    log "${GREEN}升级日志: $LOG_FILE${NC}"
    log "${YELLOW}提示: 请不要断开连接,执行'source /etc/profile'刷新环境变量!${NC}"
    log "${GREEN}=============================================${NC}"
    
    # 清理临时文件
    if [ -f "$TAR_FILE" ]; then
        rm -f "$TAR_FILE"
    fi
    
    exit 0
}

# 启动主函数
main

验证:

bash 复制代码
[root@localhost ~]# ssh -V
OpenSSH_10.2p1, OpenSSL 3.6.0-beta1 16 Sep 2025

三. Ubuntu22.04+自动升级OpenSSH10+OpenSSL3.6

本脚本实现了自动检测版本,然后备份旧版本文件,升级OpenSSH与SSL,升级过程中遇到故障也会自动回滚。只是在欧拉原有的系统中做了适配Ubuntu系统。

bash 复制代码
#!/bin/bash
# OpenSSH 安全升级脚本 for ubuntu 环境
# 版本: 2.2 (适配 ubuntu 操作逻辑)
# 日期: 2025-10-15
# 脚本执行成功后请执行 `source /etc/profile` 刷新环境变量

# 全局变量
BACKUP_DIR="/home/ssh-old-bak-$(date +%Y%m%d_%H%M%S)"
LOG_FILE="/var/log/ssh_upgrade_$(date +%Y%m%d_%H%M%S).log"
TAR_URL="https://loop-bucket.oss-cn-shanghai.aliyuncs.com/202509openssh.tar"
TAR_FILE="/tmp/openssh.tar"
TARGET_DIR="/usr"
NEW_SSH_SERVICE="ssh10.service"   # 服务名改为 ssh10.service
OLD_SSH_SERVICE="ssh.service"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 日志函数
log() {
    echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

# 错误处理函数
error_exit() {
    log "${RED}ERROR: $1${NC}"
    log "${YELLOW}开始回滚操作...${NC}"
    rollback
    exit 1
}

# 回滚函数
rollback() {
    log "开始回滚到原始状态..."
    
    # 停止新的 SSH 服务
    if systemctl is-active --quiet "$NEW_SSH_SERVICE"; then
        log "停止新的 SSH 服务: $NEW_SSH_SERVICE"
        systemctl stop "$NEW_SSH_SERVICE" || log "警告: 停止新服务失败"
    fi
    
    # 只恢复3个核心文件(删除 /etc/ssh 相关恢复逻辑)
    if [ -d "$BACKUP_DIR" ]; then
        log "恢复旧的 SSH 核心文件..."
        
        # 恢复 sshd 二进制文件
        if [ -f "$BACKUP_DIR/sshd" ]; then
            [ -f "/usr/sbin/sshd" ] && mv -f "/usr/sbin/sshd" "/usr/sbin/sshd.new" 2>/dev/null
            mv -f "$BACKUP_DIR/sshd" "/usr/sbin/sshd" || log "警告: 恢复 sshd 二进制文件失败"
        fi
        
        # 恢复 ssh 客户端
        if [ -f "$BACKUP_DIR/ssh" ]; then
            [ -f "/usr/bin/ssh" ] && mv -f "/usr/bin/ssh" "/usr/bin/ssh.new" 2>/dev/null
            mv -f "$BACKUP_DIR/ssh" "/usr/bin/ssh" || log "警告: 恢复 ssh 客户端失败"
        fi
        
        # 恢复 ssh-keygen 工具
        if [ -f "$BACKUP_DIR/ssh-keygen" ]; then
            [ -f "/usr/bin/ssh-keygen" ] && mv -f "/usr/bin/ssh-keygen" "/usr/bin/ssh-keygen.new" 2>/dev/null
            mv -f "$BACKUP_DIR/ssh-keygen" "/usr/bin/ssh-keygen" || log "警告: 恢复 ssh-keygen 工具失败"
        fi
        
        # 恢复 systemd 服务文件(如果需要,可选保留)
        for service_file in sshd-keygen.service sshd.service sshd@.service sshd.socket; do
            if [ -f "$BACKUP_DIR/$service_file" ]; then
                [ -f "/usr/lib/systemd/system/$service_file" ] && mv -f "/usr/lib/systemd/system/$service_file" "/usr/lib/systemd/system/${service_file}.new" 2>/dev/null
                mv -f "$BACKUP_DIR/$service_file" "/usr/lib/systemd/system/$service_file" || log "警告: 恢复 $service_file 失败"
            fi
        done
        
        # 重新加载 systemd 配置
        systemctl daemon-reload
        
        # 启动旧 SSH 服务
        systemctl start "$OLD_SSH_SERVICE" || log "警告: 启动旧 SSH 服务失败"
    fi
    
    # 清理临时文件
    [ -f "$TAR_FILE" ] && rm -f "$TAR_FILE"
    
    log "${YELLOW}回滚操作完成,请检查系统状态${NC}"
}

# 预检查函数
pre_check() {
    log "${GREEN}开始预检查...${NC}"
    
    # 检查 root 权限
    [ "$(id -u)" -ne 0 ] && error_exit "必须以 root 用户运行此脚本"
    
    # 检查网络连通性
    ping -c 1 -W 5 string-file.oss-cn-shanghai.aliyuncs.com >/dev/null 2>&1 || error_exit "无法连接下载服务器,请检查网络"
    
    # 检查必备工具(wget、tar)
    command -v wget >/dev/null 2>&1 || error_exit "wget 未安装,请先安装 wget"
    command -v tar >/dev/null 2>&1 || error_exit "tar 未安装,请先安装 tar"
    
    # 检查原有 SSH 服务状态
    systemctl is-active --quiet "$OLD_SSH_SERVICE" || error_exit "当前 SSH 服务未运行,无法继续升级"
    
    # 检查活跃 SSH 连接(超过 1 个连接时提示确认)
    SSH_CONNECTIONS=$(who | grep -c pts)
    if [ "$SSH_CONNECTIONS" -gt 1 ]; then
        log "${YELLOW}警告: 检测到 $SSH_CONNECTIONS 个活跃 SSH 连接${NC}"
        read -p "是否继续升级? (y/n): " confirm
        [ "$confirm" != "y" ] && error_exit "用户取消升级"
    fi
    
    log "${GREEN}预检查完成,开始升级操作${NC}"
}

# 创建并配置 /var/empty 目录
prepare_var_empty() {
    log "${GREEN}开始创建并配置 /var/empty 目录...${NC}"
    
    # 目录不存在则创建
    [ ! -d "/var/empty" ] && mkdir -p "/var/empty" || log "/var/empty 目录已存在"
    
    # 设置所有者和权限
    chown root:root "/var/empty" || error_exit "设置 /var/empty 所有者失败"
    chmod 711 "/var/empty" || error_exit "设置 /var/empty 权限失败"
    
    log "${GREEN}/var/empty 目录配置完成${NC}"
}

# 下载并解压安装包
download_and_extract() {
    log "${GREEN}开始下载 OpenSSH 安装包...${NC}"
    
    # 下载压缩包
    wget --no-check-certificate -O "$TAR_FILE" "$TAR_URL" || error_exit "下载 OpenSSH 安装包失败"
    [ ! -f "$TAR_FILE" ] || [ ! -s "$TAR_FILE" ] && error_exit "下载的文件为空或损坏"
    
    # 解压到目标目录
    log "下载完成,开始解压..."
    tar -xf "$TAR_FILE" -C "$TARGET_DIR" || error_exit "解压安装包失败"
    [ -d "$TARGET_DIR/openssh" ] || error_exit "解压后未找到 openssh 目录"
    
    log "${GREEN}下载和解压完成${NC}"
}

# 配置环境变量
configure_environment() {
    log "${GREEN}开始配置环境变量...${NC}"
    
    # 备份 profile 文件
    cp -p /etc/profile "/etc/profile.bak.$(date +%Y%m%d_%H%M%S)" || error_exit "备份 /etc/profile 失败"
    
    # 清理旧的 OpenSSH 环境变量配置
    grep -q "OpenSSH 10.2p1 Environment Variables" /etc/profile && \
        sed -i '/# OpenSSH 10.2p1 Environment Variables/,+4d' /etc/profile
    
    # 添加新的环境变量
    cat >> /etc/profile << 'EOF'

# OpenSSH 10.2p1 Environment Variables
export LD_LIBRARY_PATH=/usr/openssh/openssl-3.6.0-beta1/lib64:$LD_LIBRARY_PATH
export PATH=/usr/openssh/openssh-10.2p1/bin:/usr/openssh/openssh-10.2p1/sbin:/usr/openssh/openssl-3.6.0-beta1/bin:$PATH
export CFLAGS="-I/usr/openssh/openssl-3.6.0-beta1/include"
export LDFLAGS="-L/usr/openssh/openssl-3.6.0-beta1/lib64"
EOF
    
    # 验证配置并生效
    grep -q "OpenSSH 10.2p1 Environment Variables" /etc/profile || error_exit "添加环境变量配置失败"
    source /etc/profile
    
    log "${GREEN}环境变量配置完成${NC}"
}

# 创建 systemd 服务文件(ssh10.service)
create_systemd_service() {
    log "${GREEN}开始创建 systemd 服务文件...${NC}"
    
    # 备份已有服务文件(若存在)
    if [ -f "/usr/lib/systemd/system/$NEW_SSH_SERVICE" ]; then
        cp -p "/usr/lib/systemd/system/$NEW_SSH_SERVICE" "/usr/lib/systemd/system/${NEW_SSH_SERVICE}.bak.$(date +%Y%m%d_%H%M%S)"
        log "${YELLOW}已备份现有 $NEW_SSH_SERVICE 服务文件${NC}"
    fi
    
    # 生成 ssh10.service
    cat > "/usr/lib/systemd/system/$NEW_SSH_SERVICE" << 'EOF'
[Unit]
Description=OpenSSH server daemon (v10.2p1)
After=network.target

[Service]
Type=simple
Environment=LD_LIBRARY_PATH=/usr/openssh/openssl-3.6.0-beta1/lib64
ExecStart=/usr/openssh/openssh-10.2p1/sbin/sshd -D -f /usr/openssh/openssh-10.2p1/etc/sshd_config
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target
EOF
    
    # 设置服务文件权限
    chmod 644 "/usr/lib/systemd/system/$NEW_SSH_SERVICE"
    [ -f "/usr/lib/systemd/system/$NEW_SSH_SERVICE" ] || error_exit "创建 $NEW_SSH_SERVICE 服务文件失败"
    
    log "${GREEN}systemd 服务文件创建完成${NC}"
}

# 备份旧 SSH 配置(改进版:备份更多核心文件)
backup_old_config() {
    log "${GREEN}开始备份旧的 SSH 核心文件...${NC}"
    
    # 创建备份目录
    mkdir -p "$BACKUP_DIR" || error_exit "创建备份目录失败"
    
    # 只备份3个核心文件
    for file in /usr/sbin/sshd /usr/bin/ssh /usr/bin/ssh-keygen; do
        if [ -f "$file" ]; then
            cp -p "$file" "$BACKUP_DIR/" || log "${YELLOW}警告: 备份 $file 失败${NC}"
            log "成功备份 $file 到 $BACKUP_DIR/"
        else
            log "${YELLOW}警告: $file 文件不存在,跳过备份${NC}"
        fi
    done
    
    # 备份 systemd 服务文件(如果需要,可选保留)
    for service_file in sshd-keygen.service sshd.service sshd@.service sshd.socket; do
        if [ -f "/usr/lib/systemd/system/$service_file" ]; then
            cp -p "/usr/lib/systemd/system/$service_file" "$BACKUP_DIR/" || log "${YELLOW}警告: 备份 $service_file 失败${NC}"
            log "成功备份 $service_file 到 $BACKUP_DIR/"
        else
            log "${YELLOW}警告: $service_file 文件不存在,跳过备份${NC}"
        fi
    done
    
    log "${GREEN}旧文件备份完成,备份目录: $BACKUP_DIR${NC}"
}

# 停止旧 SSH 服务
stop_old_service() {
    log "${GREEN}开始停止旧的 SSH 服务...${NC}"
    
    # 停止并禁用旧服务
    if systemctl is-active --quiet "$OLD_SSH_SERVICE"; then
        systemctl stop "$OLD_SSH_SERVICE" || error_exit "停止旧 SSH 服务失败"
        log "$OLD_SSH_SERVICE 服务已停止"
    else
        log "${YELLOW}警告: $OLD_SSH_SERVICE 服务未运行,跳过停止操作${NC}"
    fi
    
    if systemctl is-enabled --quiet "$OLD_SSH_SERVICE"; then
        systemctl disable "$OLD_SSH_SERVICE" || error_exit "禁用旧 SSH 服务失败"
        log "$OLD_SSH_SERVICE 服务已禁用"
    else
        log "${YELLOW}警告: $OLD_SSH_SERVICE 服务未启用,跳过禁用操作${NC}"
    fi
    
    # 等待服务彻底停止
    sleep 5
    systemctl is-active --quiet "$OLD_SSH_SERVICE" && error_exit "旧 SSH 服务仍在运行,无法继续升级"
    
    log "${GREEN}旧 SSH 服务处理完成${NC}"
}

# 移动旧 SSH 文件到备份目录
move_old_files() {
    log "${GREEN}开始处理旧的 SSH 核心文件...${NC}"
    
    # 只移动3个核心文件(删除所有 /etc/ssh 相关操作)
    for file in /usr/sbin/sshd /usr/bin/ssh /usr/bin/ssh-keygen; do
        if [ -f "$file" ]; then
            # 检查备份目录中是否已有同名文件,有则先删除(避免移动失败)
            if [ -f "$BACKUP_DIR/$(basename $file)" ]; then
                rm -f "$BACKUP_DIR/$(basename $file)" || error_exit "删除旧备份文件 $file 失败"
            fi
            # 移动文件到备份目录
            mv "$file" "$BACKUP_DIR/" || error_exit "移动 $file 到备份目录失败"
            log "成功移动 $file 到 $BACKUP_DIR/"
        else
            log "${YELLOW}警告: $file 文件不存在,跳过移动操作${NC}"
        fi
    done
    
    # 移动 systemd 服务文件(如果需要,可选保留)
    for service_file in sshd-keygen.service sshd.service sshd@.service sshd.socket; do
        if [ -f "/usr/lib/systemd/system/$service_file" ]; then
            if [ -f "$BACKUP_DIR/$service_file" ]; then
                rm -f "$BACKUP_DIR/$service_file" || error_exit "删除旧备份文件 $service_file 失败"
            fi
            mv "/usr/lib/systemd/system/$service_file" "$BACKUP_DIR/" || log "${YELLOW}警告: 移动 $service_file 失败${NC}"
            log "成功移动 $service_file 到 $BACKUP_DIR/"
        else
            log "${YELLOW}警告: $service_file 文件不存在,跳过移动操作${NC}"
        fi
    done
    
    log "${GREEN}旧文件处理完成${NC}"
}

# 启动新 SSH 服务(ssh10.service)
start_new_service() {
    log "${GREEN}开始启动新的 SSH 服务...${NC}"
    
    # 重新加载 systemd 配置
    systemctl daemon-reload || error_exit "重新加载 systemd 配置失败"
    
    # 启动新服务
    systemctl start "$NEW_SSH_SERVICE" || error_exit "启动新 SSH 服务失败"
    
    # 等待服务启动
    sleep 10
    systemctl is-active --quiet "$NEW_SSH_SERVICE" || error_exit "新 SSH 服务启动失败,服务状态异常"
    
    # 设置开机自启
    systemctl enable "$NEW_SSH_SERVICE" || log "${YELLOW}警告: 设置新 SSH 服务开机自启失败${NC}"
    
    # 输出服务状态
    log "新 SSH 服务状态:"
    systemctl status "$NEW_SSH_SERVICE" --no-pager | tee -a "$LOG_FILE"
    
    log "${GREEN}新 SSH 服务启动完成${NC}"
}

# 验证升级结果
verify_upgrade() {
    log "${GREEN}开始验证升级结果...${NC}"
    
    # 验证 SSH 版本
    SSH_VERSION=$(/usr/openssh/openssh-10.2p1/bin/ssh -V 2>&1)
    log "SSH 版本: $SSH_VERSION"
    echo "$SSH_VERSION" | grep -q "OpenSSH_10.2p1" || error_exit "SSH 版本验证失败,未检测到 OpenSSH_10.2p1"
    echo "$SSH_VERSION" | grep -q "OpenSSL 3.6.0-beta1" || error_exit "OpenSSL 版本验证失败,未检测到 OpenSSL 3.6.0-beta1"
    
    # 验证环境变量
    log "LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
    [[ "$LD_LIBRARY_PATH" != *"/usr/openssh/openssl-3.6.0-beta1/lib64"* ]] && log "${YELLOW}警告: LD_LIBRARY_PATH 配置异常${NC}"
    [[ "$PATH" != *"/usr/openssh/openssh-10.2p1/bin"* ]] && log "${YELLOW}警告: PATH 配置异常${NC}"
    
    # 验证端口监听
    netstat -tlnp | grep -q ":22" || error_exit "SSH 端口 22 未监听,服务启动异常"
    
    log "${GREEN}升级结果验证完成${NC}"
}

# 测试 SSH 连接(可选,用于验证服务可用性)
# 测试SSH连接函数 - Ubuntu适配版
test_ssh_connection() {
    log "${GREEN}开始测试SSH连接...${NC}"
    
    # 获取本地IP地址(Ubuntu兼容方式)
    LOCAL_IP=$(hostname -I | awk '{print $1}')
    if [ -z "$LOCAL_IP" ]; then
        LOCAL_IP=$(hostname -i | awk '{print $1}')  # 兼容旧版Ubuntu
    fi
    
    if [ -z "$LOCAL_IP" ]; then
        log "${YELLOW}警告: 无法获取本地IP地址,跳过连接测试${NC}"
        return
    fi
    
    log "测试连接到本地IP: $LOCAL_IP"
    
    # 创建测试用户(Ubuntu需要显式指定家目录权限)
    TEST_USER="ssh_test_user_$(date +%s)"
    TEST_PASSWORD=$(openssl rand -base64 12 | tr -d '+/'  # 移除特殊字符,避免密码兼容问题
    )
    
    log "创建测试用户: $TEST_USER"
    # Ubuntu中useradd需加-m创建家目录,-s指定shell避免nologin导致无法登录
    if ! useradd -m -s /bin/bash "$TEST_USER" &> /dev/null; then
        log "${YELLOW}警告: 创建测试用户失败,跳过连接测试${NC}"
        return
    fi
    
    # Ubuntu设置密码(使用chpasswd确保非交互模式生效)
    echo "$TEST_USER:$TEST_PASSWORD" | chpasswd &> /dev/null
    # 强制密码生效(Ubuntu有时需要刷新密码数据库)
    passwd -u "$TEST_USER" &> /dev/null
    
    # 等待用户配置生效
    sleep 3
    
    # 使用密码认证测试SSH连接(Ubuntu默认允许密码认证)
    log "使用密码认证测试SSH连接..."
    # 增加StrictHostKeyChecking=no和UserKnownHostsFile=/dev/null避免首次连接交互
    SSH_TEST_OUTPUT=$(sshpass -p "$TEST_PASSWORD" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 "$TEST_USER@$LOCAL_IP" "echo SSH_TEST_SUCCESS" 2>&1)
    
    if echo "$SSH_TEST_OUTPUT" | grep -q "SSH_TEST_SUCCESS"; then
        log "${GREEN}SSH连接测试成功${NC}"
    else
        # 密码认证失败时尝试密钥认证
        log "${YELLOW}密码认证失败,尝试密钥认证...${NC}"
        
        # 生成测试密钥(Ubuntu默认ssh-keygen路径兼容)
        ssh-keygen -t rsa -b 2048 -f "/tmp/ssh_test_key" -N "" &> /dev/null
        # Ubuntu的用户家目录权限严格,需确保正确权限
        mkdir -p "/home/$TEST_USER/.ssh"
        cp "/tmp/ssh_test_key.pub" "/home/$TEST_USER/.ssh/authorized_keys"
        chown -R "$TEST_USER:$TEST_USER" "/home/$TEST_USER/.ssh"
        chmod 700 "/home/$TEST_USER/.ssh"
        chmod 600 "/home/$TEST_USER/.ssh/authorized_keys"
        
        # Ubuntu无需SELinux,跳过上下文修复
        
        # 密钥认证测试
        SSH_TEST_OUTPUT=$(ssh -i "/tmp/ssh_test_key" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 "$TEST_USER@$LOCAL_IP" "echo SSH_TEST_SUCCESS" 2>&1)
        
        if echo "$SSH_TEST_OUTPUT" | grep -q "SSH_TEST_SUCCESS"; then
            log "${GREEN}SSH密钥认证测试成功${NC}"
        else
            log "${YELLOW}警告: SSH连接测试失败: $SSH_TEST_OUTPUT${NC}"
        fi
        
        # 清理密钥文件
        rm -f "/tmp/ssh_test_key" "/tmp/ssh_test_key.pub"
    fi
    
    # 清理测试环境(Ubuntu删除用户需加-r递归删除家目录)
    log "清理测试用户: $TEST_USER"
    userdel -r "$TEST_USER" &> /dev/null
    
    log "${GREEN}SSH连接测试完成${NC}"
}

# 主函数
main() {
    log "${GREEN}=============================================${NC}"
    log "${GREEN}开始 OpenSSH 安全升级流程 (版本 2.2)${NC}"
    log "${GREEN}=============================================${NC}"
    
    # 记录系统信息
    log "系统信息:"
    uname -a | tee -a "$LOG_FILE"
    cat /etc/os-release | grep PRETTY_NAME | tee -a "$LOG_FILE"
    
    # 执行升级流程
    pre_check
    prepare_var_empty   # 新增:创建/配置 /var/empty
    download_and_extract
    configure_environment
    create_systemd_service
    backup_old_config
    stop_old_service
    move_old_files
    start_new_service
    verify_upgrade
    test_ssh_connection  # 可选:测试连接
    
    log "${GREEN}=============================================${NC}"
    log "${GREEN}OpenSSH 安全升级完成!${NC}"
    log "${GREEN}新 SSH 服务: $NEW_SSH_SERVICE${NC}"
    log "${GREEN}备份目录: $BACKUP_DIR${NC}"
    log "${GREEN}升级日志: $LOG_FILE${NC}"
    log "${YELLOW}提示: 请执行 'source /etc/profile' 刷新环境变量,且不要断开当前 SSH 连接!${NC}"
    log "${GREEN}=============================================${NC}"
    
    # 清理临时文件
    [ -f "$TAR_FILE" ] && rm -f "$TAR_FILE"
    exit 0
}

# 启动主流程
main

验证

bash 复制代码
[root@localhost ~]# ssh -V
OpenSSH_10.2p1, OpenSSL 3.6.0-beta1 16 Sep 2025

四. Centos7.9+自动升级OpenSSH10+OpenSSL3.6

4.1 先下载适配Centos操作系统的压缩包

bash 复制代码
wget https://loop-bucket-demo.oss-cn-shanghai.aliyuncs.com/openssh-10.2p1%26amp%3Bopenssh-3.0.18.el7.tar.gz

4.2 解压压缩包

bash 复制代码
[root@10 test]# tar xf openssh-10.2p1\&amp\;openssh-3.0.18.el7.tar.gz
可以看到如下的三个rpm文件
[root@10 test]# ll
total 37024
-rw-r--r-- 1 root root  6676948 Oct 15 01:14 openssh-10.2p1-1.el7.x86_64.rpm
-rw-r--r-- 1 root root  6821392 Oct 15 01:14 openssh-clients-10.2p1-1.el7.x86_64.rpm
-rw-r--r-- 1 root root  5439764 Oct 15 01:14 openssh-server-10.2p1-1.el7.x86_64.rpm

4.3 安装rpm包

bash 复制代码
[root@10 test]# rpm -Uvh ./*.rpm
给密码文件设置正确的600权限
[root@10 ~]# chmod 600 /etc/ssh/ssh_host_*_key

4.4 重启ssh服务

bash 复制代码
[root@10 test]# systemctl restart sshd.service
[root@10 test]# systemctl status sshd.service
● sshd.service - SYSV: OpenSSH server daemon
   Loaded: loaded (/etc/rc.d/init.d/sshd; bad; vendor preset: enabled)
   Active: active (running) since Tue 2025-10-28 17:49:34 CST; 1 day 22h ago
     Docs: man:systemd-sysv-generator(8)
  Process: 26925 ExecStop=/etc/rc.d/init.d/sshd stop (code=exited, status=0/SUCCESS)
  Process: 28191 ExecStart=/etc/rc.d/init.d/sshd start (code=exited, status=0/SUCCESS)
 Main PID: 28203 (sshd)
    Tasks: 1
   Memory: 12.1M
   CGroup: /system.slice/sshd.service
           └─28203 sshd: /usr/sbin/sshd [listener] 0 of 10-100 startups

4.5 查看版本信息

bash 复制代码
[root@10 test]# ssh -V
OpenSSH_10.2p1, OpenSSL 3.0.18 30 Sep 2025

五. 总结三大发行版 SSH 10 升级的核心策略与优先级

5.1. 按发行版定升级优先级

  • 优先升级:openEuler 22.03

优势:官方源直接支持,无需解决依赖问题,国产化适配完善,适合对稳定性要求高的政务、国企场景,升级成本最低(仅需dnf install+ 重启服务)。

  • 次优先:Ubuntu 22.04+

优势:backports 源提供稳定版本,配置自动迁移,适合互联网企业的 LTS 服务器集群,需注意监控工具的正则适配,整体风险可控。

  • 谨慎升级:CentOS 7.9+

劣势:需手动升级 OpenSSL、编译源码,且 SELinux 策略需调整,适合对 CentOS 有强依赖且需高安全等级的场景(如金融灾备服务器),建议先在测试环境验证 2 周以上,再批量部署。

5.2. 通用安全操作准则

无论哪个发行版,升级前需执行三大准备:

① 备份/etc/ssh目录(cp -r /etc/ssh /etc/ssh.bak_$(date +%F_%H%M)),避免配置丢失;

② 保留旧版 SSH 监听备用端口(如 2222),测试新版本可正常登录后,再切换至 22 端口;

③ 升级后通过ssh -V验证版本(需显示OpenSSH_10.0),并使用ssh-audit工具扫描(确保无 "高危" 算法残留)。

5.3. 未来适配建议

随着 OpenSSH 10.1 版本的即将发布(预计 2026 年初),三大发行版的适配将进一步完善:Ubuntu 24.04 LTS 可能默认预装 SSH 10,openEuler 23.09 将新增国密算法支持,CentOS Stream 11 则会解决依赖链问题。建议运维人员建立版本跟踪机制(如订阅 OpenSSH 官方邮件列表),提前规划升级窗口期,确保远程管理的安全性与稳定性。

相关推荐
啊吧怪不啊吧6 小时前
SQL之表的查改(上)
服务器·数据库·sql
TomcatLikeYou6 小时前
blender4.5 使用外部IDE(pycharm)编辑脚本(bpy)实践指南
服务器·pycharm·php·blender
我爱钱因此会努力6 小时前
ansible实战- 关机
linux·运维·服务器·centos·自动化·ansible
盈创力和20076 小时前
以太网多参量传感器:工业物联网时代的安全监测革新
嵌入式硬件·物联网·安全·以太网温湿度传感器·多参量传感器·以太网多参量传感器
路由侠内网穿透.6 小时前
本地部署集成全能平台 Team.IDE 并实现外部访问
运维·服务器·数据库·ide·远程工作
Wang's Blog7 小时前
Linux小课堂: 系统救援模式操作指南:修复启动问题与重置Root密码
linux·运维
Zhangzy@8 小时前
仓颉的空安全基石:Option类型的设计与实践
java·开发语言·安全
民乐团扒谱机8 小时前
实验室安全教育与管理平台学习记录(二)化学类安全2
安全
盈创力和20079 小时前
以太网多参量传感器:构筑工业安全与环境稳定的“数据堡垒”
嵌入式硬件·安全·以太网温湿度传感器·多参量传感器