好的,根据你的系统是 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
- https://mirrors.aliyun.com/pub/OpenBSD/OpenSSH/portable/openssh-10.2p1.tar.gz
- 需要修复: 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"
注意事项
- 保持会话: 整个过程中至少保持一个SSH会话不要断开
- 防火墙: 确保防火墙允许SSH连接
- SELinux: 如果启用了SELinux,注意文件上下文
- 定期备份: 升级前的备份非常重要
自动化脚本
#!/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)"