ssh代理转发本质是本地ssh-agent签名能力逐跳透传,私钥始终驻留本机内存;ssh -i绕过agent导致无法转发,必须用ssh-add加载密钥并配置每跳forwardagent yes及跳板机allowagentforwarding yes。

SSH代理转发不是把私钥“发过去”,而是让本地 ssh-agent 的签名能力逐跳透传;私钥必须始终留在你本机内存里,中间任何跳板机都接触不到磁盘私钥文件。
为什么 ssh -i 无法用于代理转发
OpenSSH 明确禁止将磁盘上的私钥通过 ForwardAgent yes 暴露——这是硬性安全限制,不是配置问题。直接用 ssh -i ~/.ssh/id_rsa user@jump 登录后,再从跳板机连内网机,ssh-add -l 在目标端一定为空。
-
ssh -i绕过了ssh-agent,不设置SSH_AUTH_SOCK,子进程无法继承认证上下文 - 只有先运行
ssh-add把解密后的私钥载入本地 agent,后续连接才能透传 - 验证是否生效:登录跳板机后执行
echo $SSH_AUTH_SOCK,非空才说明 agent 已透传到这层
如何在 ~/.ssh/config 中正确声明多跳转发
每跳都必须显式启用 ForwardAgent yes,ProxyJump 会自动继承该设置,但只限于它直接跳转的目标节点。
- 第一跳(跳板机)Host 块中必须有
ForwardAgent yes - 第二跳(如内网应用服务器)若通过
ProxyJump bastion连接,则无需重复写ForwardAgent yes(自动继承) - 但如果要在跳板机上手动再连第三台机器(比如
ssh db-server),则db-server的 Host 块也必须单独加ForwardAgent yes - 避免
Host *放在 config 开头,否则会覆盖后续具体 Host 的ForwardAgent设置
跳板机 sshd_config 必须允许代理继续转发
跳板机不是终点,它是中转站;它自己不使用私钥,但必须允许把 agent socket 请求继续往下传,否则链路在它这里就断了。
- 检查
/etc/ssh/sshd_config是否含AllowAgentForwarding yes(默认开启,但加固模板常设为no) - 不需要重启
sshd,改完保存即生效 - 务必禁用密码登录:
PasswordAuthentication no,防止攻击者绕过密钥认证降级攻击 -
~/.ssh/authorized_keys权限必须是600,目录权限700,否则 OpenSSH 拒绝读取公钥
验证是否真正在最末端服务器拿到签名能力
只看 $SSH_AUTH_SOCK 有值不够,要确认远端能实际调用本地私钥完成签名。
- 登录最后一跳后,运行
ssh-add -l,输出应与本地ssh-add -l完全一致(指纹相同) - 或从倒数第二跳执行:
ssh -o LogLevel=DEBUG2 target-host,日志中出现debug2: key: /home/user/.ssh/id_rsa (0x...)才算成功 - 如果
ssh-add -l在目标端为空,常见原因是跳板机的sshd_config关了AllowAgentForwarding,或它的~/.ssh/config没给目标 Host 加ForwardAgent yes
最容易被忽略的是:跳板机本身不需要、也不应该运行 ssh-add,它不持有私钥;所有密钥加载和生命周期管理,都只发生在你的本地终端里。转发链越长,每一跳的 AllowAgentForwarding 和 ForwardAgent yes 就越不能漏掉一个。











