SSH ProxyJump:经由跳板机登录内网服务器
有些服务器不能从办公电脑直接访问,但可以先登录一台跳板机,再由跳板机访问内网目标服务器。
一种做法是先登录跳板机,再在跳板机上执行第二次 ssh。SSH 本身支持这种连接路径,使用 -J(ProxyJump)就能把两次连接写成一条命令。
假设网络关系如下:
当前电脑
└── SSH ──> 跳板机 192.0.2.10:22022
└── SSH ──> 目标服务器 198.51.100.20:22
本文中的账号和地址都是脱敏示例:跳板机使用 jump-user@192.0.2.10:22022,目标服务器使用 target-user@198.51.100.20。请替换为实际环境的值。
假设当前电脑不能直接访问 198.51.100.20,但跳板机可以访问它。连接目标服务器只需要:
ssh -J jump-user@192.0.2.10:22022 target-user@198.51.100.20
-J 到底做了什么
命令里出现两个 SSH 地址:
ssh -J jump-user@192.0.2.10:22022 \
target-user@198.51.100.20
它们的角色不同:
-J jump-user@192.0.2.10:22022:先连接跳板机,用户名是jump-user,SSH 端口是22022target-user@198.51.100.20:最终要登录的目标服务器,未指定端口时使用默认的22
-J 的格式是:
-J [跳板机用户@]跳板机地址[:跳板机端口]
如果目标服务器的 SSH 端口不是 22,使用 -p 指定目标端口:
ssh -J jump-user@192.0.2.10:22022 \
-p 2222 \
target-user@198.51.100.20
这里的 -p 2222 属于目标服务器;跳板机的端口仍然写在 -J 后面。
连接过程
执行命令时,本地 SSH 客户端会先处理跳板机连接:
- 先使用本地的密钥或密码认证跳板机
- 请求跳板机上的
sshd建立一条到198.51.100.20:22的 TCP 通道
随后,本地 SSH 客户端通过这条通道和目标服务器完成真正的 SSH 握手与认证。
连接路径如下:
本地 ssh 客户端
│
│ 连接跳板机 192.0.2.10:22022
▼
跳板机上的 sshd
│
│ 连接 198.51.100.20:22
▼
目标服务器上的 sshd
跳板机只转发 TCP 字节流,交互式 shell 不会在跳板机上启动。目标服务器的私钥认证仍由当前电脑完成,目标私钥无需复制到跳板机。
它和下面这种手动操作的区别在于:
ssh -p 22022 jump-user@192.0.2.10
ssh target-user@198.51.100.20
手动方式会先进入跳板机,再从那里发起第二次连接。使用 -J 时,跳板机只作为目标连接的代理通道。
两台机器使用不同的账号和密钥
跳板机和目标服务器可以使用不同的账号和密钥。
例如跳板机使用 jump-key,目标服务器使用 target-key。可以把配置写入 ~/.ssh/config,分别为两个主机设置认证信息,让两台机器的配置彼此独立。
Host my-jump
HostName 192.0.2.10
User jump-user
Port 22022
IdentityFile ~/.ssh/jump-key
Host my-target
HostName 198.51.100.20
User target-user
IdentityFile ~/.ssh/target-key
ProxyJump my-jump
之后直接执行:
ssh my-target
这样,目标服务器地址、跳板机端口和密钥路径只需要维护一次。后续执行 scp、sftp 或其他 SSH 工具时也能复用这份配置。
例如使用 scp:
scp ./example.txt my-target:/tmp/
多级跳板机
如果目标服务器前面还有多层网络隔离,可以在 -J 中用逗号分隔多个跳板机:
ssh -J user1@jump-1:22022,user2@jump-2:22 \
user3@198.51.100.20
连接顺序是:
当前电脑 -> jump-1 -> jump-2 -> 198.51.100.20
也可以写成配置:
Host my-target
HostName 198.51.100.20
User user3
ProxyJump user1@jump-1:22022,user2@jump-2:22
每增加一层跳板,排查网络问题就多一层依赖。实际使用时,链路能短就不要再加中间节点。
连接失败时怎么排查
先确认跳板机本身可以登录:
ssh -p 22022 jump-user@192.0.2.10
再从跳板机检查它能否访问目标服务器的 SSH 端口:
nc -vz 198.51.100.20 22
如果跳板机没有 nc,也可以直接在跳板机上尝试:
ssh -v target-user@198.51.100.20
最后在本地打开详细日志:
ssh -vv \
-J jump-user@192.0.2.10:22022 \
target-user@198.51.100.20
日志通常能看出问题位于哪一段:
- 跳板机认证失败:检查跳板机用户名、端口和密钥
- 跳板机无法连接目标端口:检查目标服务器路由、防火墙和
sshd - 目标服务器认证失败:检查目标服务器的用户、密钥和
authorized_keys - 出现 host key 警告:确认目标 IP 没有被重新分配给另一台机器
目标 SSH 连接仍由当前电脑端到端建立。因此第一次连接目标服务器时,当前电脑仍然可能看到目标服务器的 host key 确认提示。
和端口转发有什么区别
-J 解决的是“登录目标服务器”:
本地电脑 -> 跳板机 -> 目标服务器
登录成功后,得到的是目标服务器上的 shell。
如果要访问目标服务器上的 HTTP、数据库或其他 TCP 服务,又不需要登录 shell,可以使用 -L 本地端口转发,把本地程序接到目标服务:
本地程序 -> 本地端口 -> SSH 隧道 -> 目标服务器上的服务
两者可以同时使用:-J 负责“怎么到达目标服务器”,-L 负责“到达目标服务器后再转发哪个服务端口”。
安全边界
ProxyJump 只改变到达目标服务器的网络路径,目标服务器仍然会独立校验用户和密钥。
部署时检查:
- 跳板机必须允许连接目标服务器的 SSH 端口
- 目标服务器的 host key 应该在当前电脑上验证并保存
- 尽量使用密钥认证,目标服务器私钥不要放到跳板机
- 只给跳板机开放必要的目标网段和端口
- 把跳板机限制在明确的目标范围内,不要把它当成通用代理
将“必须经过某台机器才能到达”的路径写进 SSH 命令或配置文件后,ssh、scp 和 sftp 都可以复用这套设置。
