openssh平滑升级

好的,根据你的系统是 Anolis OS 8.10(基于 RHEL/CentOS),我来提供一个更适配的完善方案。

当前环境分析

  • 系统: Anolis OS 8.10 (RHEL-like)
  • 需下载:
    • https://mirrors.aliyun.com/pub/OpenBSD/OpenSSH/portable/openssh-10.2p1.tar.gz
      https://mirrors.aliyun.com/pub/OpenBSD/OpenSSH/portable/openssh-10.2p1.tar.gz.asc
  • 需要修复: CVE-2019-16905

完善的升级方案

1. 准备工作

# 首先检查当前SSH版本和配置
ssh -V
systemctl status sshd
ss -tlnp | grep :22

# 创建工作目录和备份
mkdir -p /data/backup/ssh-upgrade-$(date +%Y%m%d-%H%M)
BACKUP_DIR="/data/backup/ssh-upgrade-$(date +%Y%m%d-%H%M)"

# 备份关键配置
cp -r /etc/ssh/ $BACKUP_DIR/
cp /etc/passwd $BACKUP_DIR/
cp /etc/shadow $BACKUP_DIR/
cp /etc/group $BACKUP_DIR/
systemctl list-unit-files | grep ssh > $BACKUP_DIR/ssh-services.txt

# 记录当前SSH主机密钥状态(用于后续对比)
ls -la /etc/ssh/ssh_host_*_key* > $BACKUP_DIR/original-key-permissions.txt
echo "当前SSH主机密钥权限已记录到备份目录"

# 检查并修复SSH主机密钥权限
echo "检查并修复SSH主机密钥权限..."
for key in /etc/ssh/ssh_host_*_key; do
   if [ -f "$key" ]; then
       chmod 600 "$key"
       echo "修复 $key 权限为 600"
   fi
done

for key in /etc/ssh/ssh_host_*_key.pub; do
   if [ -f "$key" ]; then
       chmod 644 "$key"
       echo "修复 $key 权限为 644"
   fi
done

# 验证权限
echo "当前SSH主机密钥权限:"
ls -la /etc/ssh/ssh_host_*_key* | head -10

2. 安装编译依赖

# Anolis OS 8.10 使用 dnf/yum 安装依赖
dnf update -y
dnf groupinstall -y "Development Tools"
dnf install -y \
   gcc \
   make \
  openssl-devel \
  zlib-devel \
  pam-devel \
  rpm-build \
   wget \
  tar \
  systemd-devel \
  krb5-devel

# 验证依赖安装
rpm -qa | grep -E "(gcc|openssl-devel|zlib-devel|pam-devel)"

3. 下载源码

cd /tmp
#下载新版本软件包
wget https://mirrors.aliyun.com/pub/OpenBSD/OpenSSH/portable/openssh-10.2p1.tar.gz

# 解压源码
tar -xzf openssh-10.2p1.tar.gz
cd openssh-10.2p1

4. 配置和编译

# 查看当前SSH安装路径
rpm -ql openssh-server | head -10
make clean

# 配置编译选项(适配Anolis OS)
./configure \
   --prefix=/usr \
   --sysconfdir=/etc/ssh \
   --libexecdir=/usr/libexec/openssh \
   --datadir=/usr/share/openssh \
   --with-xauth=/usr/bin/xauth \
   --with-default-path=/usr/local/bin:/bin:/usr/bin \
   --with-superuser-path=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin \
   --with-privsep-path=/var/empty/sshd \
   --with-pid-dir=/var/run \
   --with-pam \
   --disable-strip \
   --without-zlib-version-check \
   --with-ssl-engine \
   --with-ipaddr-display \
   --with-kerberos5=/usr \
   --with-gssapi

# 编译(使用多核加速)
echo "开始编译..."
make -j$(nproc)

# 验证编译成功
if [ $? -eq 0 ]; then
   echo "✅ 编译完成,检查主要文件:"
   ls -la ssh sshd ssh-keygen scp sftp
else
   echo "❌ 编译失败"
   exit 1
fi

# 安装到测试目录
make install DESTDIR=/usr/local/openssh-new
echo "✅ 安装到测试目录完成"

5. 双端口安装测试

# 创建临时安装目录
#mkdir -p /usr/local/openssh-new/usr/{bin,sbin,libexec/openssh,share/man/{man1,man5,man8}}
#mkdir -p /usr/local/openssh-new/etc/ssh

# 复制编译好的文件到临时目录
# 复制主要程序到 usr/bin
#cp ssh ssh-keygen scp sftp ssh-add ssh-agent ssh-keyscan /usr/local/openssh-new/usr/bin/

# 复制sshd到 usr/sbin  
#cp sshd /usr/local/openssh-new/usr/sbin/

# 复制libexec文件到正确位置
#cp sftp-server ssh-keysign sshd-auth sshd-session ssh-pkcs11-helper ssh-sk-helper /usr/local/openssh-new/usr/libexec/openssh/

#设置正确权限
chown root:ssh_keys /usr/local/openssh-new/usr/libexec/openssh/ssh-keysign
chmod 2755 /usr/local/openssh-new/usr/libexec/openssh/ssh-keysign
# 复制当前配置文件
cp -r /etc/ssh/* /usr/local/openssh-new/etc/ssh

# 修改测试配置(使用2222端口)
sed -i 's/^Port [0-9]*/Port 2222/' /usr/local/openssh-new/etc/ssh/sshd_config
sed -i 's/^#Port [0-9]*/Port 2222/' /usr/local/openssh-new/etc/ssh/sshd_config

# 添加调试信息
echo "LogLevel INFO" >> /usr/local/openssh-new/etc/ssh/sshd_config
echo "PidFile /var/run/sshd-new.pid" >> /usr/local/openssh-new/etc/ssh/sshd_config
#防止10.2版本不兼容问题
mv /etc/crypto-policies/back-ends/openssh.config /etc/crypto-policies/back-ends/openssh.config.disable
# 临时修改服务启动命令,移除CRYPTO_POLICY
cp /usr/lib/systemd/system/sshd.service /usr/lib/systemd/system/sshd.service.backup
# 修改启动命令
sed -i 's/ExecStart=\/usr\/sbin\/sshd -D \$OPTIONS \$CRYPTO_POLICY/ExecStart=\/usr\/sbin\/sshd -D/' /usr/lib/systemd/system/sshd.service

# 重新加载systemd配置
systemctl daemon-reload

#openssh9.x版本引入的新组件sshd-session和sshd-auth
echo "=== 检查系统原有组件 ==="
if [ -f "/usr/libexec/openssh/sshd-session" ] && [ ! -L "/usr/libexec/openssh/sshd-session" ]; then
   echo "⚠️ 系统已有 sshd-session,不建议直接覆盖"
   echo "原文件信息:"
   ls -la /usr/libexec/openssh/sshd-session
   
   echo "=== 建议:备份后替换 ==="
   echo "mv /usr/libexec/openssh/sshd-session /usr/libexec/openssh/sshd-session.backup"
   echo "mv /usr/libexec/openssh/sshd-auth /usr/libexec/openssh/sshd-auth.backup"
else
   echo "✅ 系统无冲突文件,符号链接安全"
fi
# 执行符号链接
ln -sf /usr/local/openssh-new/usr/libexec/openssh/sshd-session /usr/libexec/openssh/sshd-session
ln -sf /usr/local/openssh-new/usr/libexec/openssh/sshd-auth /usr/libexec/openssh/sshd-auth


# 验证配置文件语法
echo "验证配置文件语法..."
/usr/local/openssh-new/usr/sbin/sshd -t -f /usr/local/openssh-new/etc/ssh/sshd_config

if [ $? -eq 0 ]; then
   echo "✅ 配置文件语法正确"
else
   echo "❌ 配置文件语法错误,需要手动检查"
   echo "可能的问题:"
   echo "1. SSH主机密钥权限问题"
   echo "2. 配置选项不兼容"
   echo ""
   echo "检查SSH主机密钥权限:"
   ls -la /etc/ssh/ssh_host_*_key
   echo ""
   echo "如果权限不是600,请运行:"
   echo "chmod 600 /etc/ssh/ssh_host_*_key"
   echo "chmod 600 /usr/local/openssh-new/etc/ssh/ssh_host_*_key"
   exit 1
fi


# 启动测试SSH服务
/usr/local/openssh-new/usr/sbin/sshd -f /usr/local/openssh-new/etc/ssh/sshd_config -D &
TEST_SSHD_PID=$!

# 检查测试服务状态
sleep 2
ss -tlnp | grep :2222
if [ $? -eq 0 ]; then
   echo "✅ 测试SSH服务启动成功,端口2222"
else
   echo "❌ 测试SSH服务启动失败"
   kill $TEST_SSHD_PID 2>/dev/null
   exit 1
fi

# 检查版本
/usr/local/openssh-new/usr/sbin/sshd -V

6. 测试新服务

# 测试本地连接
ssh -F /dev/null -p 2222  -o StrictHostKeyChecking=no root@127.0.0.1
#测试远程连接(linux)
sh -F /dev/null -p 2222  -o StrictHostKeyChecking=no root@10.0.0.112
#测试远程连接(windows xshell)
ssh root@10.0.0.112 2222

# 检查新版本
/usr/local/openssh-new/usr/bin/ssh -V

7. 正式替换

第1步:保持新SSH服务运行,验证功能

# 确认新SSH服务正在运行
echo "=== 验证新SSH服务 ==="
ps aux | grep "openssh-new" | grep -v grep
ss -tlnp | grep :2222

# 测试所有功能
echo "=== 测试SSH连接 ==="
/usr/local/openssh-new/usr/bin/ssh -p 2222 -o StrictHostKeyChecking=no localhost "echo 'SSH连接测试成功'"

echo "=== 测试SCP ==="
echo "test file" > /tmp/test_scp.txt
/usr/local/openssh-new/usr/bin/scp -P 2222 -o StrictHostKeyChecking=no /tmp/test_scp.txt localhost:/tmp/test_scp_received.txt
ls -la /tmp/test_scp_received.txt

第2步:备份原有文件

echo "=== 备份原有SSH文件 ==="
BACKUP_DIR="/data/backup/ssh_backup_$(date +%Y%m%d_%H%M%S)"
mkdir -p $BACKUP_DIR/{bin,sbin,libexec}

# 备份二进制文件
cp /usr/bin/ssh* $BACKUP_DIR/bin/
cp /usr/sbin/sshd $BACKUP_DIR/sbin
cp -r /usr/libexec/openssh $BACKUP_DIR/libexec

# 备份配置文件
cp -r /etc/ssh $BACKUP_DIR/

echo "备份完成,位置: $BACKUP_DIR"
ls -la $BACKUP_DIR

第3步:替换二进制文件(保持服务运行)

echo "=== 开始替换二进制文件 ==="

# 1. 替换客户端工具(这些不会影响运行中的服务)
echo "替换客户端工具..."
mv /usr/bin/ssh /usr/bin/ssh.old
cp /usr/local/openssh-new/usr/bin/ssh /usr/bin/ssh

cp /usr/local/openssh-new/usr/bin/scp /usr/bin/scp
cp /usr/local/openssh-new/usr/bin/sftp /usr/bin/sftp
cp /usr/local/openssh-new/usr/bin/ssh-add /usr/bin/ssh-add
cp /usr/local/openssh-new/usr/bin/ssh-agent /usr/bin/ssh-agent
cp /usr/local/openssh-new/usr/bin/ssh-keygen /usr/bin/ssh-keygen
cp /usr/local/openssh-new/usr/bin/ssh-keyscan /usr/bin/ssh-keyscan

# 2. 替换服务器工具
echo "替换服务器工具..."
#备份旧sshd主程序
mv /usr/sbin/sshd /usr/sbin/sshd.old
cp /usr/local/openssh-new/usr/sbin/sshd /usr/sbin/sshd
# 删除软链接
rm /usr/libexec/openssh/sshd-auth
rm /usr/libexec/openssh/sshd-session
cp /usr/local/openssh-new/usr/libexec/openssh/* /usr/libexec/openssh/

# 修复ssh-keysign权限(在复制后设置)
chown root:ssh_keys /usr/libexec/openssh/ssh-keysign
chmod 2755 /usr/libexec/openssh/ssh-keysign

echo "文件替换完成"

第7步:验证替换结果

echo "=== 验证替换结果 ==="

# 检查版本
echo "新SSH版本:"
ssh -V

echo "新sshd版本:"
/usr/sbin/sshd -V

# 检查服务状态
echo "服务状态:"
systemctl status sshd
ss -tlnp | grep :22

# 测试连接
echo "测试系统SSH连接..."
ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no localhost "echo 'SSH 10.2升级成功!'" && echo "✅ 系统SSH正常" || echo "❌ 系统SSH异常"

# 如果系统SSH正常,可以关闭测试服务
if ssh -o ConnectTimeout=5 localhost "exit" 2>/dev/null; then
   echo "系统SSH正常,关闭测试服务..."
  pkill -f "openssh-new.*sshd"
   echo "✅ 升级完成!"
else
   echo "❌ 系统SSH异常,保持测试服务运行"
   echo "可通过端口2222连接进行故障排除"
fi

第8步:清理和最终验证

echo "=== 最终验证和清理 ==="

# 全面功能测试
echo "SSH客户端工具测试:"
ssh -V
# scp 测试(不使用 --help)
echo "test" > /tmp/testfile
scp /tmp/testfile localhost:/tmp/testfile2 && echo "✅ scp正常" || echo "❌ scp异常"

# sftp 测试(使用正确的参数)
echo "quit" | sftp localhost >/dev/null 2>&1 && echo "✅ sftp正常" || echo "❌ sftp异常"

echo "SSH服务测试:"
ssh localhost "uname -a"

# 显示备份信息
echo "备份文件位置: $BACKUP_DIR"
echo "如需回滚,可执行:"
echo "systemctl stop sshd"
echo "cp $BACKUP_DIR/sshd /usr/sbin/"
echo "cp $BACKUP_DIR/ssh* /usr/bin/"
echo "cp -r $BACKUP_DIR/openssh /usr/libexec/"
echo "cp $BACKUP_DIR/sshd_config /etc/ssh/"
echo "systemctl start sshd"

echo "=== OpenSSH升级完成 ==="

# 清理临时文件
rm -rf /tmp/openssh-10.2p1*
rm -rf /usr/local/openssh-new

# 确保SSH服务开机自启
systemctl enable sshd

8. 回滚方案

如果出现问题,执行以下回滚:

# 回滚脚本
cat > /tmp/ssh_rollback.sh << 'EOF'
#!/bin/bash
echo "开始回滚SSH..."

# 停止服务
systemctl stop sshd

# 恢复备份文件
cp /usr/sbin/sshd.backup.* /usr/sbin/sshd 2>/dev/null
cp /usr/bin/ssh.backup.* /usr/bin/ssh 2>/dev/null

# 恢复配置
BACKUP_DIR=$(ls -td /backup/ssh-upgrade-* | head -1)
if [ -d "$BACKUP_DIR" ]; then
   cp -r $BACKUP_DIR/ssh/* /etc/ssh/
fi

# 重装原SSH包
dnf reinstall -y openssh openssh-server

# 启动服务
systemctl start sshd
systemctl status sshd

echo "SSH回滚完成"
EOF

chmod +x /tmp/ssh_rollback.sh
echo "回滚脚本已准备: /tmp/ssh_rollback.sh"

注意事项

  1. 保持会话: 整个过程中至少保持一个SSH会话不要断开
  2. 防火墙: 确保防火墙允许SSH连接
  3. SELinux: 如果启用了SELinux,注意文件上下文
  4. 定期备份: 升级前的备份非常重要

自动化脚本

#!/bin/bash

# OpenSSH升级脚本 - 自动回滚版本
# 适用于Anolis OS 8.10系统

set -e  # 遇到错误时退出

echo "=== OpenSSH 升级脚本开始执行 ==="
echo "目标版本: OpenSSH 10.2p1"
echo "系统: Anolis OS 8.10"
echo "=================================="

# 获取用户凭据用于后续测试
echo "=== 获取测试凭据 ==="
read -p "请输入用于SSH测试的用户名 (建议使用root): " TEST_USER
read -s -p "请输入该用户的密码: " TEST_PASSWORD
echo ""
echo "凭据已保存,将用于自动化测试"

# 验证凭据
echo "正在验证凭据..."
if ! echo "$TEST_PASSWORD" | su - "$TEST_USER" -c "whoami" >/dev/null 2>&1; then
   echo "❌ 凭据验证失败,请检查用户名和密码"
   exit 1
fi
echo "✅ 凭据验证成功"

# 1. 准备工作
echo "=== 1. 准备工作 ==="
ssh -V
systemctl status sshd --no-pager -l
ss -tlnp | grep :22

mkdir -p /data/backup/ssh-upgrade-$(date +%Y%m%d-%H%M)
BACKUP_DIR="/data/backup/ssh-upgrade-$(date +%Y%m%d-%H%M)"

cp -r /etc/ssh/ $BACKUP_DIR/
cp /etc/passwd $BACKUP_DIR/
cp /etc/shadow $BACKUP_DIR/
cp /etc/group $BACKUP_DIR/
systemctl list-unit-files | grep ssh > $BACKUP_DIR/ssh-services.txt

ls -la /etc/ssh/ssh_host_*_key* > $BACKUP_DIR/original-key-permissions.txt
echo "当前SSH主机密钥权限已记录到备份目录"

echo "检查并修复SSH主机密钥权限..."
for key in /etc/ssh/ssh_host_*_key; do
   if [ -f "$key" ]; then
       chmod 600 "$key"
       echo "修复 $key 权限为 600"
   fi
done

for key in /etc/ssh/ssh_host_*_key.pub; do
   if [ -f "$key" ]; then
       chmod 644 "$key"
       echo "修复 $key 权限为 644"
   fi
done

echo "当前SSH主机密钥权限:"
ls -la /etc/ssh/ssh_host_*_key* | head -10

# 2. 安装编译依赖
echo "=== 2. 安装编译依赖 ==="
# 安装sshpass用于自动化SSH测试
dnf update -y
dnf groupinstall -y "Development Tools"
dnf install -y \
   gcc \
   make \
  openssl-devel \
  zlib-devel \
  pam-devel \
  rpm-build \
   wget \
  tar \
  systemd-devel \
  krb5-devel \
  sshpass \
  expect

rpm -qa | grep -E "(gcc|openssl-devel|zlib-devel|pam-devel)"

# 3. 下载源码
echo "=== 3. 下载源码 ==="
cd /tmp
# 清理可能存在的旧文件
rm -rf openssh-10.2p1*
# 添加超时和重试参数
wget --timeout=30 --tries=3 https://mirrors.aliyun.com/pub/OpenBSD/OpenSSH/portable/openssh-10.2p1.tar.gz

tar -xzf openssh-10.2p1.tar.gz
cd openssh-10.2p1

# 4. 配置和编译
echo "=== 4. 配置和编译 ==="
rpm -ql openssh-server | head -10

# 配置编译选项
./configure \
   --prefix=/usr \
   --sysconfdir=/etc/ssh \
   --libexecdir=/usr/libexec/openssh \
   --datadir=/usr/share/openssh \
   --with-xauth=/usr/bin/xauth \
   --with-default-path=/usr/local/bin:/bin:/usr/bin \
   --with-superuser-path=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin \
   --with-privsep-path=/var/empty/sshd \
   --with-pid-dir=/var/run \
   --with-pam \
   --disable-strip \
   --without-zlib-version-check \
   --with-ssl-engine \
   --with-ipaddr-display \
   --with-kerberos5=/usr \
   --with-gssapi

# 检查configure是否成功
if [ $? -ne 0 ]; then
   echo "❌ 配置失败,自动回滚..."
   cd /tmp
   rm -rf openssh-10.2p1*
   exit 1
fi

echo "开始编译..."
make -j$(nproc)

if [ $? -eq 0 ]; then
   echo "✅ 编译完成,检查主要文件:"
   ls -la ssh sshd ssh-keygen scp sftp
else
   echo "❌ 编译失败,自动回滚..."
   cd /tmp
   rm -rf openssh-10.2p1*
   exit 1
fi

make install DESTDIR=/usr/local/openssh-new
echo "✅ 安装到测试目录完成"

# 5. 双端口安装测试
echo "=== 5. 双端口安装测试 ==="
# 检查ssh_keys组是否存在,不存在则使用root
if getent group ssh_keys > /dev/null 2>&1; then
   chown root:ssh_keys /usr/local/openssh-new/usr/libexec/openssh/ssh-keysign
else
   chown root:root /usr/local/openssh-new/usr/libexec/openssh/ssh-keysign
fi
chmod 2755 /usr/local/openssh-new/usr/libexec/openssh/ssh-keysign

# 强制覆盖复制
cp -rf /etc/ssh/* /usr/local/openssh-new/etc/ssh/

# 修改测试端口配置
sed -i 's/^#*Port .*/Port 2222/' /usr/local/openssh-new/etc/ssh/sshd_config

echo "LogLevel INFO" >> /usr/local/openssh-new/etc/ssh/sshd_config
echo "PidFile /var/run/sshd-new.pid" >> /usr/local/openssh-new/etc/ssh/sshd_config

# 备份和修改系统配置
if [ -f /etc/crypto-policies/back-ends/openssh.config ]; then
   cp /etc/crypto-policies/back-ends/openssh.config /etc/crypto-policies/back-ends/openssh.config.backup
   mv /etc/crypto-policies/back-ends/openssh.config /etc/crypto-policies/back-ends/openssh.config.disable
fi

cp /usr/lib/systemd/system/sshd.service /usr/lib/systemd/system/sshd.service.backup
sed -i 's/ExecStart=\/usr\/sbin\/sshd -D \$OPTIONS \$CRYPTO_POLICY/ExecStart=\/usr\/sbin\/sshd -D/' /usr/lib/systemd/system/sshd.service

systemctl daemon-reload

echo "=== 检查系统原有组件 ==="
if [ -f "/usr/libexec/openssh/sshd-session" ] && [ ! -L "/usr/libexec/openssh/sshd-session" ]; then
   echo "⚠️ 系统已有 sshd-session,自动备份后替换"
   mv /usr/libexec/openssh/sshd-session /usr/libexec/openssh/sshd-session.backup
   if [ -f "/usr/libexec/openssh/sshd-auth" ]; then
       mv /usr/libexec/openssh/sshd-auth /usr/libexec/openssh/sshd-auth.backup
   fi
else
   echo "✅ 系统无冲突文件,符号链接安全"
fi

ln -sf /usr/local/openssh-new/usr/libexec/openssh/sshd-session /usr/libexec/openssh/sshd-session
if [ -f "/usr/local/openssh-new/usr/libexec/openssh/sshd-auth" ]; then
   ln -sf /usr/local/openssh-new/usr/libexec/openssh/sshd-auth /usr/libexec/openssh/sshd-auth
fi

echo "验证配置文件语法..."
/usr/local/openssh-new/usr/sbin/sshd -t -f /usr/local/openssh-new/etc/ssh/sshd_config

if [ $? -eq 0 ]; then
   echo "✅ 配置文件语法正确"
else
   echo "❌ 配置文件语法错误,自动修复权限..."
   chmod 600 /etc/ssh/ssh_host_*_key
   chmod 600 /usr/local/openssh-new/etc/ssh/ssh_host_*_key
   # 重新验证
  /usr/local/openssh-new/usr/sbin/sshd -t -f /usr/local/openssh-new/etc/ssh/sshd_config
   if [ $? -ne 0 ]; then
       echo "❌ 配置文件仍有问题,自动回滚..."
       cd /tmp
       rm -rf openssh-10.2p1*
       rm -rf /usr/local/openssh-new
       # 恢复备份文件
       if [ -f /etc/crypto-policies/back-ends/openssh.config.backup ]; then
           mv /etc/crypto-policies/back-ends/openssh.config.backup /etc/crypto-policies/back-ends/openssh.config
       fi
       exit 1
   fi
fi

# 启动测试SSH服务
echo "启动测试SSH服务..."
/usr/local/openssh-new/usr/sbin/sshd -f /usr/local/openssh-new/etc/ssh/sshd_config -D &
TEST_SSHD_PID=$!

sleep 5
ss -tlnp | grep :2222
if [ $? -eq 0 ]; then
   echo "✅ 测试SSH服务启动成功,端口2222"
else
   echo "❌ 测试SSH服务启动失败,自动回滚..."
   kill $TEST_SSHD_PID 2>/dev/null
   cd /tmp
   rm -rf openssh-10.2p1*
   rm -rf /usr/local/openssh-new
   # 恢复备份文件
   if [ -f /etc/crypto-policies/back-ends/openssh.config.backup ]; then
       mv /etc/crypto-policies/back-ends/openssh.config.backup /etc/crypto-policies/back-ends/openssh.config
   fi
   exit 1
fi

/usr/local/openssh-new/usr/sbin/sshd -V

# 6. 测试新SSH服务连接
echo "=== 6. 测试新SSH服务连接 ==="
echo "正在测试新SSH服务的连接功能..."

# 获取本机IP
LOCAL_IP=$(ip route get 8.8.8.8 | awk 'NR==1{print $7}')
if [ -z "$LOCAL_IP" ]; then
   LOCAL_IP="127.0.0.1"
fi

echo "使用IP: $LOCAL_IP, 端口: 2222"

# 创建expect脚本进行自动化SSH测试
cat > /tmp/ssh_test.exp << EOF
#!/usr/bin/expect
set timeout 30
spawn /usr/local/openssh-new/usr/bin/ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 $TEST_USER@$LOCAL_IP "echo 'SSH连接测试成功' && /usr/local/openssh-new/usr/sbin/sshd -V"
expect {
   "*password:" {
      send "$TEST_PASSWORD\r"
      expect {
           "*SSH连接测试成功*" {
              puts "✅ SSH连接测试通过"
              expect eof
               exit 0
          }
          timeout {
              puts "❌ SSH连接测试超时"
               exit 1
          }
      }
  }
  timeout {
      puts "❌ SSH连接超时"
       exit 1
  }
}
EOF

chmod +x /tmp/ssh_test.exp

# 执行SSH连接测试
if /tmp/ssh_test.exp; then
   echo "✅ 新SSH服务连接测试成功"
else
   echo "❌ 新SSH服务连接测试失败,自动回滚..."
   kill $TEST_SSHD_PID 2>/dev/null
   cd /tmp
   rm -rf openssh-10.2p1*
   rm -rf /usr/local/openssh-new
   rm -f /tmp/ssh_test.exp
   # 恢复备份文件
   if [ -f /etc/crypto-policies/back-ends/openssh.config.backup ]; then
       mv /etc/crypto-policies/back-ends/openssh.config.backup /etc/crypto-policies/back-ends/openssh.config
   fi
   exit 1
fi

# 7. 正式替换
echo "=== 7. 正式替换 ==="

# 第1步:验证新SSH服务
echo "=== 验证新SSH服务 ==="
ps aux | grep "openssh-new" | grep -v grep
ss -tlnp | grep :2222

echo "=== 自动化功能测试 ==="
echo "test file" > /tmp/test_scp.txt
echo "✅ 测试文件创建成功"

# 第2步:备份原有文件
echo "=== 备份原有SSH文件 ==="
BACKUP_DIR2="/data/backup/ssh_backup_$(date +%Y%m%d_%H%M%S)"
mkdir -p $BACKUP_DIR2/{bin,sbin,libexec}

# 强制复制,不提示覆盖
cp -f /usr/bin/ssh* $BACKUP_DIR2/bin/ 2>/dev/null || true
cp -f /usr/sbin/sshd $BACKUP_DIR2/sbin
cp -rf /usr/libexec/openssh $BACKUP_DIR2/libexec

cp -rf /etc/ssh $BACKUP_DIR2/

echo "备份完成,位置: $BACKUP_DIR2"
ls -la $BACKUP_DIR2

# 第3步:替换二进制文件(保持服务运行)
echo "=== 开始替换二进制文件 ==="

echo "替换客户端工具..."
mv /usr/bin/ssh /usr/bin/ssh.old
cp -f /usr/local/openssh-new/usr/bin/ssh /usr/bin/ssh

cp -f /usr/local/openssh-new/usr/bin/scp /usr/bin/scp
cp -f /usr/local/openssh-new/usr/bin/sftp /usr/bin/sftp
cp -f /usr/local/openssh-new/usr/bin/ssh-add /usr/bin/ssh-add
cp -f /usr/local/openssh-new/usr/bin/ssh-agent /usr/bin/ssh-agent
cp -f /usr/local/openssh-new/usr/bin/ssh-keygen /usr/bin/ssh-keygen
cp -f /usr/local/openssh-new/usr/bin/ssh-keyscan /usr/bin/ssh-keyscan

echo "替换服务器工具..."
mv /usr/sbin/sshd /usr/sbin/sshd.old
cp -f /usr/local/openssh-new/usr/sbin/sshd /usr/sbin/sshd

# 安全删除软链接并复制新文件
rm -f /usr/libexec/openssh/sshd-auth
rm -f /usr/libexec/openssh/sshd-session
cp -f /usr/local/openssh-new/usr/libexec/openssh/* /usr/libexec/openssh/

# 修复权限
if getent group ssh_keys > /dev/null 2>&1; then
   chown root:ssh_keys /usr/libexec/openssh/ssh-keysign
else
   chown root:root /usr/libexec/openssh/ssh-keysign
fi
chmod 2755 /usr/libexec/openssh/ssh-keysign

echo "文件替换完成"

# 验证替换结果
echo "=== 验证替换结果 ==="

echo "新SSH版本:"
ssh -V

echo "新sshd版本:"
/usr/sbin/sshd -V

echo "服务状态:"
systemctl status sshd --no-pager
ss -tlnp | grep :22

echo "关闭测试服务..."
kill $TEST_SSHD_PID 2>/dev/null
sleep 2

# 恢复正常端口配置
sed -i 's/^Port 2222/Port 22/' /etc/ssh/sshd_config

echo "重启SSH服务..."
systemctl restart sshd
sleep 5

echo "验证SSH服务状态:"
systemctl status sshd --no-pager
ss -tlnp | grep :22

if systemctl is-active --quiet sshd; then
   echo "✅ SSH服务正常运行"
   
   # 最终SSH连接测试
   echo "=== 最终SSH连接测试 ==="
   cat > /tmp/final_ssh_test.exp << EOF
#!/usr/bin/expect
set timeout 30
spawn ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $TEST_USER@$LOCAL_IP "echo 'SSH最终测试成功' && ssh -V"
expect {
   "*password:" {
      send "$TEST_PASSWORD\r"
      expect {
           "*SSH最终测试成功*" {
              puts "✅ SSH最终连接测试通过"
              expect eof
               exit 0
          }
          timeout {
              puts "❌ SSH最终连接测试超时"
               exit 1
          }
      }
  }
  timeout {
      puts "❌ SSH最终连接超时"
       exit 1
  }
}
EOF
   
   chmod +x /tmp/final_ssh_test.exp
   
   if /tmp/final_ssh_test.exp; then
       echo "✅ 升级完成并通过最终测试!"
   else
       echo "❌ 最终SSH测试失败,自动回滚..."
      systemctl stop sshd
       cp -f $BACKUP_DIR2/sbin/sshd /usr/sbin/sshd
       cp -f $BACKUP_DIR2/bin/ssh* /usr/bin/
       cp -rf $BACKUP_DIR2/libexec/openssh /usr/libexec/
       cp -rf $BACKUP_DIR2/ssh /etc/
       
       # 恢复系统服务配置
       if [ -f /usr/lib/systemd/system/sshd.service.backup ]; then
           cp /usr/lib/systemd/system/sshd.service.backup /usr/lib/systemd/system/sshd.service
       fi
       
       # 恢复crypto-policies配置
       if [ -f /etc/crypto-policies/back-ends/openssh.config.backup ]; then
           mv /etc/crypto-policies/back-ends/openssh.config.backup /etc/crypto-policies/back-ends/openssh.config
       fi
       
      systemctl daemon-reload
      systemctl start sshd
      systemctl status sshd
       echo "已成功回滚至原版本"
       rm -f /tmp/final_ssh_test.exp
       exit 1
   fi
   
else
   echo "❌ SSH服务异常,自动回滚..."
   echo "正在回滚至原版本..."
  systemctl stop sshd
   cp -f $BACKUP_DIR2/sbin/sshd /usr/sbin/sshd
   cp -f $BACKUP_DIR2/bin/ssh* /usr/bin/
   cp -rf $BACKUP_DIR2/libexec/openssh /usr/libexec/
   cp -rf $BACKUP_DIR2/ssh /etc/

   # 恢复系统服务配置
   if [ -f /usr/lib/systemd/system/sshd.service.backup ]; then
       cp /usr/lib/systemd/system/sshd.service.backup /usr/lib/systemd/system/sshd.service
   fi

   # 恢复crypto-policies配置  
   if [ -f /etc/crypto-policies/back-ends/openssh.config.backup ]; then
       mv /etc/crypto-policies/back-ends/openssh.config.backup /etc/crypto-policies/back-ends/openssh.config
   fi

  systemctl daemon-reload
  systemctl start sshd
  systemctl status sshd
   echo "已成功回滚至原版本"
   exit 1
fi

# 最终验证和清理
echo "=== 最终验证和清理 ==="

echo "SSH客户端工具测试:"
ssh -V

echo "备份文件位置: $BACKUP_DIR2"
echo "原始备份位置: $BACKUP_DIR"

echo "=== OpenSSH升级完成 ==="

# 清理临时文件
rm -rf /tmp/openssh-10.2p1*
rm -rf /usr/local/openssh-new
rm -f /tmp/test_scp.txt /tmp/ssh_test.exp /tmp/final_ssh_test.exp

systemctl enable sshd

echo "=== 准备回滚方案 ==="
cat > /tmp/ssh_rollback.sh << 'EOF'
#!/bin/bash
echo "开始回滚SSH..."

systemctl stop sshd

BACKUP_DIR2="/data/backup/ssh_backup_$(ls -t /data/backup/ | grep ssh_backup | head -1 | cut -d'_' -f3-)"
BACKUP_DIR2="/data/backup/$(ls -t /data/backup/ | grep ssh_backup | head -1)"

if [ -d "$BACKUP_DIR2" ]; then
   cp -f $BACKUP_DIR2/sbin/sshd /usr/sbin/sshd
   cp -f $BACKUP_DIR2/bin/ssh* /usr/bin/
   cp -rf $BACKUP_DIR2/libexec/openssh /usr/libexec/
   cp -rf $BACKUP_DIR2/ssh /etc/

   # 恢复系统服务配置
   if [ -f /usr/lib/systemd/system/sshd.service.backup ]; then
       cp /usr/lib/systemd/system/sshd.service.backup /usr/lib/systemd/system/sshd.service
   fi

   # 恢复crypto-policies配置
   if [ -f /etc/crypto-policies/back-ends/openssh.config.backup ]; then
       mv /etc/crypto-policies/back-ends/openssh.config.backup /etc/crypto-policies/back-ends/openssh.config
   fi

  systemctl daemon-reload
  systemctl start sshd
  systemctl status sshd

   echo "SSH回滚完成"
else
   echo "未找到备份目录"
   exit 1
fi
EOF

chmod +x /tmp/ssh_rollback.sh
echo "回滚脚本已准备: /tmp/ssh_rollback.sh"

echo "=== OpenSSH升级脚本执行完成 ==="
echo "当前SSH版本: $(ssh -V 2>&1)"

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部