1. SSH agent forwarding 是什么
SSH agent forwarding 的作用是:让你在"跳板机"上也能使用本地电脑里的 SSH 私钥 去登录其他机器,而不用把私钥拷到跳板机。
常见场景:
- 本地电脑 → 跳板机
<jump_host> - 再从跳板机 → 内网机器
<target_host>
如果配置正确,那么在跳板机上执行:
ssh <target_user>@<target_host>
会继续使用你本地电脑的私钥完成认证。
跳板机概念(Jump Host / Bastion Host)
| 概念 | 说明 |
|---|---|
| 跳板机 | 位于公网和内网之间的"中转站",有双网卡或路由能力,是进入内网的唯一入口 |
| 堡垒机 | 带审计、权限控制、录像等安全功能的"增强版跳板机",企业级场景常用 |
| 为什么需要 | 内网机器不暴露公网 IP,必须通过跳板机作为"桥梁"才能访问 |
没有 Agent Forwarding 的困境
传统做法(不安全):
1) 登录跳板机
2)把私钥复制到跳板机(危险!)
3)在跳板机上使用私钥登录内网机
风险:
-
私钥留在跳板机磁盘上,可能被其他用户读取
-
如果跳板机被攻破,你的私钥直接泄露
-
多台跳板机 = 私钥复制多份 = 风险倍增
2. 本地准备
启动 ssh-agent
有些系统已经自动启动了,可以直接跳过这一步。
eval "$(ssh-agent -s)"
把私钥加入 agent
ssh-add ~/.ssh/id_rsa
或者:
ssh-add ~/.ssh/id_ed25519
查看当前 agent 中的 key:ssh-add -l
3. 临时开启 agent forwarding
连接跳板机时使用:ssh -A <jump_user>@<jump_host>
注意:
-A是开启 agent forwarding-a是禁用 agent forwarding,不要写错
4. 永久开启 agent forwarding(可选)
在本机 ~/.ssh/config 里配置:
Host <jump_host>
ForwardAgent yes
或者更通用:
Host *
ForwardAgent yes
然后重新连接:
ssh -A <jump_user>@<jump_host>
参考如图

5. 如何检查跳板机是否收到了 agent forwarding
登录到 <jump_host> 后检查:
echo $SSH_AUTH_SOCK
ssh-add -l
正常情况:
echo $SSH_AUTH_SOCK应该有值ssh-add -l应该能看到本地 agent 中加载的 key 指纹
例如:
SSH_AUTH_SOCK=/tmp/ssh-xxxxxx/agent.12345
3072 SHA256:xxxx <key_comment> (RSA)
6. 常见异常及含义
情况 1:ssh-add -l 报错
Could not open a connection to your authentication agent.
含义:
- 当前 shell 里的
SSH_AUTH_SOCK不可用
常见原因:
- agent forwarding 没成功
- tmux 里拿的是旧的
SSH_AUTH_SOCK - 外层 ssh 已断开,旧 socket 失效
情况 2:ssh-add -l 显示
The agent has no identities.
含义:
- 当前能连到 agent
- 但 agent 里没有加载任何私钥
处理:ssh-add ~/.ssh/id_rsa或ssh-add ~/.ssh/id_ed25519
7. 如何确认第二跳是否能真正免密
在跳板机上执行:ssh -o BatchMode=yes <target_user>@<target_host> 'echo ok'
如果输出:ok
说明当前环境下第二跳确实可以无密码认证。
如果失败,例如:Permission denied (publickey,password)
说明虽然你可能能手动 ssh,但当前环境下并没有真正实现 agent 免密认证。
8. tmux 为什么容易出问题
tmux 会保留旧 session 的环境变量。
如果这个 session 是很早以前开的,那么其中的SSH_AUTH_SOCK很可能还是旧值。
一旦承载 agent forwarding 的外层 ssh 连接断开,这个旧 socket 就会失效,于是会出现:
Error connecting to agent: No such file or directory 或 Could not open a connection to your authentication agent.
9. tmux 中修复 SSH_AUTH_SOCK
先在 tmux 外同步新的环境
在远端、但不在 tmux 里面的 shell 执行:
tmux set-environment -g SSH_AUTH_SOCK "$SSH_AUTH_SOCK"
再到 tmux 当前 pane 中刷新当前 shell
export SSH_AUTH_SOCK="$(tmux show-environment -g SSH_AUTH_SOCK | sed -n 's/^SSH_AUTH_SOCK=//p')"
然后验证:
ssh-add -l
ssh -o BatchMode=yes <target_user>@<target_host> 'echo ok'
10. 外层 ssh 能不能关
如果你依赖的是本地 agent forwarding,那么承载这次 forwarding 的外层 ssh 连接不能断。
例如通过以下命令进来的:
ssh -A <jump_user>@<jump_host>
那么这条连接断开后:
- 远端
SSH_AUTH_SOCK可能还在环境变量里 - 但对应的 socket 文件已经失效
- tmux 里的 agent 也就不能用了
所以更准确的说法是:不是 tmux 不能用,而是 agent forwarding 这条链路断了。
11. 如果外层 ssh 已断,怎么恢复
本地重新连接
ssh -A <jump_user>@<jump_host>
在远端 tmux 外更新环境
tmux set-environment -g SSH_AUTH_SOCK "$SSH_AUTH_SOCK"
在 tmux 当前 pane 中刷新
export SSH_AUTH_SOCK="$(tmux show-environment -g SSH_AUTH_SOCK | sed -n 's/^SSH_AUTH_SOCK=//p')"
这样就恢复了。
12. 一组最实用的排查命令
本地检查 agent
ssh-add -l
跳板机检查 forwarding
echo $SSH_AUTH_SOCK
ssh-add -l
检查第二跳是否真的免密
ssh -o BatchMode=yes <target_user>@<target_host> 'echo ok'
tmux 中刷新当前 shell 的 SSH_AUTH_SOCK
export SSH_AUTH_SOCK="$(tmux show-environment -g SSH_AUTH_SOCK | sed -n 's/^SSH_AUTH_SOCK=//p')"
13. 建议的占位符规范
为了让文档长期可复用,建议统一使用以下占位符:
<jump_host>:跳板机地址<jump_user>:跳板机用户名<target_host>:目标机器地址<target_user>:目标机器用户名<key_comment>:SSH key 注释<local_private_key>:本地私钥路径
例如:
ssh -A <jump_user>@<jump_host>
ssh -o BatchMode=yes <target_user>@<target_host> 'echo ok'
14. 经验总结
ssh -A才是开启 agent forwarding- 本地私钥仍然在本地,不会自动复制到跳板机
tmux常见问题不是 ssh 本身坏了,而是SSH_AUTH_SOCK过期- 外层 ssh 断开后,旧 tmux session 中的 agent socket 往往会失效
- 恢复方式通常是:重新 ssh -A 登录 + 更新 tmux 环境变量
15. 常见误区澄清
| 误区 | 真相 |
|---|---|
| "Agent Forwarding 把私钥传到跳板机" | ❌ 私钥从未离开 本地电脑,只转发认证请求 |
| "跳板机上能看到我的私钥" | ❌ 跳板机只能看到 agent 的 socket 文件,看不到私钥内容 |
| "Agent Forwarding 和 scp 私钥效果一样" | ❌ scp 私钥是复制文件(危险),Forwarding 是转发请求(安全) |
| "用了 -A 就不用输入密码" | ⚠️ 仍需输入本地私钥的密码(如果有),只是不用重复输入 |