Jenkins服务器更新密钥后任务构建不了?排查实录与解决方案

前言:在一次生产环境的 SSH 密钥轮换中,我遇到了一个极其令人困惑的问题:在 Jenkins 服务器上手动执行 ssh -i 命令测试新密钥到目标服务器,直接报 Permission denied;将同样的命令放入 Jenkins 任务脚本中,同样失败。 在排除了文件权限、换行符、known_hosts 等所有常见原因后,最终发现是 ssh-agent 缓存的老密钥在"作祟",而解决方法是在 ~/.ssh/config 中为堡垒机单独配置 IdentitiesOnly yes

本文记录了完整的排查过程,希望能帮助遇到类似"幽灵"故障的运维人员快速定位问题。


一、现象:手动测试失败,Jenkins 任务也失败

在 Jenkins 服务器上执行以下命令手动测试新密钥:

bash 复制代码
ssh -i ~/.ssh/id_ed25519_new -J user@bastion_ip:22222 target_ip "echo '连通'"

结果:Permission denied

再将同样的命令放入 Jenkins 任务脚本中:

bash 复制代码
scp -i ~/.ssh/id_ed25519_new -o 'ProxyJump user@bastion_ip:22222' ...

结果: Jenkins 控制台同样输出 Permission denied

手动与脚本表现一致------说明问题不在 Jenkins 任务执行环境,而在基础的 SSH 连接链路本身。


二、排查:绕过的弯路
  1. 检查服务器端 authorized_keys :确认新公钥已正确添加,权限为 600,文件末尾有换行符。
  2. 重置 known_hostsssh-keygen -R bastion_ip,无效。
  3. 在脚本中增加参数-o StrictHostKeyChecking=no,依然报 Permission denied
  4. 清空 ssh-agent 缓存ssh-add -D,依然无效。

这些操作均无法解决问题,说明问题不在表面,而在 SSH 认证的深层机制。


三、真相:SSH 的密钥优先级顺序

经过反复验证,发现 SSH 在认证时的密钥优先级是:

  1. 最高优先级ssh-agent 中缓存的密钥。
  2. 中间优先级:命令行 -i 参数指定的密钥。
  3. 最低优先级:~/.ssh/id_rsa 等默认密钥。

在 Jenkins 节点上,后台进程悄悄地启动了 ssh-agent,并将旧的 id_rsa 密钥加载了进去。

当我们在手动测试或 Jenkins 脚本中执行 ssh -i ~/.ssh/id_ed25519_new ... 时,SSH 客户端会优先问 ssh-agent:"你有能用的钥匙吗?"

ssh-agent 回答:"有,我这里有 id_rsa。"

于是 SSH 尝试用 旧密钥 id_rsa 去连接堡垒机。此时,堡垒机上的老公钥已被删除,认证失败,连接被服务端直接切断。切断后,SSH 根本没机会再去尝试你 -i 指定的新密钥。

这就是为什么手动测试和 Jenkins 任务都失败的根本原因。


四、终极解决方案:配置 ~/.ssh/config

在 Jenkins 节点上,修改 ~/.ssh/config 文件,为堡垒机添加强制隔离配置

bash 复制代码
Host bastion_ip
    IdentitiesOnly yes
    IdentityFile ~/.ssh/id_ed25519_new
    StrictHostKeyChecking no
    UserKnownHostsFile /dev/null

核心参数解析:

  • IdentitiesOnly yes:强制 SSH 客户端只使用 IdentityFile 指定的密钥 ,完全忽略 ssh-agent 中缓存的所有密钥。这是解决"-i 参数失效"的关键。
  • IdentityFile:指定要使用的新密钥文件。
  • StrictHostKeyChecking no & UserKnownHostsFile /dev/null:跳过主机指纹校验,避免 SSH 在自动化环境中卡住。

五、验证与成果

添加配置后,再次执行手动测试命令(不再需要 -i 参数):

bash 复制代码
ssh -J user@bastion_ip:22222 target_ip "echo '连通'"

结果: 成功输出 连通

直接重跑 Jenkins 任务------构建成功,密钥轮换完成


六、经验总结:下次轮换密钥该怎么做?
  1. 不要依赖脚本里的 -i 参数 :在 Jenkins 这种有 ssh-agent 的环境里,单独指定 -i 往往不可靠,因为 ssh-agent 的优先级更高。
  2. 善用 ~/.ssh/config :为跳板机或目标服务器单独配置 IdentitiesOnly yesIdentityFile,可以做到"一劳永逸"。
  3. 清理服务器端的旧公钥:确保新公钥是唯一可用的。
  4. 后续轮换 :下次更新密钥时,你只需要修改 ~/.ssh/config 里的 IdentityFile 路径,所有 Jenkins 任务会自动切换到新密钥,无需修改任何 Jenkins 脚本。

希望这篇博客能帮你快速定位这类 Jenkins 密钥更新后的连接失败问题。如果你也遇到过类似的"幽灵"报错,不妨试试在 ~/.ssh/config 里加上 IdentitiesOnly yes,或许能节省数小时的不必要排查。

相关推荐
虎头金猫13 小时前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
-梅16 小时前
linux(8) 软硬链接
linux·运维·服务器
Wang's Blog17 小时前
Java 项目实战: 外卖平台-文件下载与ServletOutputStream回写浏览器
服务器·项目开发
琥珀色糖17 小时前
SimlpeHttp
linux·服务器
第十人i17 小时前
Linux 日志管理系统:journald 配置与优化
linux·服务器
需要82618 小时前
JVM 内存区域与对象创建:一次 GC 从哪来
java·jvm·spring boot·spring·servlet·tomcat
ITxiaobing202319 小时前
IP 定位服务选型指南:从准确率到工程落地的技术考察
linux·服务器·网络
wuyk55519 小时前
【Socket 进阶之路】第 9 章 Linux 网络服务量产稳定性优化|心跳保活、TIME_WAIT、SO_LINGER、内存池、断线重连、完整异常防护框架
linux·服务器·开发语言·网络·物联网
Julien200419 小时前
Docker 容器存储原理(一)
linux·运维·服务器·ssh·学习方法
筝筝ba19 小时前
GUI 测试之只读用户恢复BMC出厂设置
服务器