# Proxyjump原理和使用配置


{{< admonition type=info title="内容简介" open=true >}}
介绍SSH ProxyJump的原理和配置。
{{< /admonition >}}

SSH ProxyJump 是 OpenSSH 原生支持的一种现代网络代理功能，专门用于通过中间服务器（通常称为“跳板机”或“堡垒机”）安全地连接到无法直接访问的目标服务器。

## 背景

在日常运维或开发工作中，我们常常需要访问部署在内网的服务器。然而出于安全策略或网络拓扑的限制，内网服务器并不会直接向外部暴露端口，导致我们无法直连。此时，跳板机（Jump Host/Bastion Host）就成了必不可少的中转：

- 先通过 SSH 登录跳板机
- 再从跳板机登录到目标服务器

虽然这样的流程能保证安全隔离，但也带来了一定程度上的不便：每次都要进行两次登录，甚至手动输入多次密码或在多个终端窗口间切换。如果有上传文件到目标服务器的需求，则需要先将文件上传到跳板机，再从跳板机传到目标服务器，操作非常繁琐。

## ProxyJump 原理

当你使用 ProxyJump 时，你的本地客户端会首先与跳板机建立 SSH 连接。接着，客户端会在跳板机上启动一个临时的 SSH 子进程连接到目标主机。客户端将自身的输入输出通过加密隧道转发给这个子进程，从而在本地和目标服务器之间建立一条端到端的安全通道。关键点：整个过程中，跳板机仅负责透明地转发 TCP 流量，它不解密数据，也无法看到传输的具体内容。所有的身份认证（如密钥验证）都在你的本地机器和最终目标服务器之间直接完成。

兼容性与版本要求：
- ProxyJump（-J）需要 OpenSSH 7.3+。
- ProxyCommand 适用于更早版本的 SSH，兼容性更好，但配置稍微复杂一些。

这里更推荐使用 ProxyJump。在 ProxyJump 出现之前，通常需要使用传统的 ProxyCommand 结合 nc (netcat) 命令来实现类似功能，配置相对繁琐。ProxyJump 的优势在于：
- 配置极简：语法更简洁，性能更好，无需在跳板机上启动额外的 nc 进程。
- 兼容工具：不仅支持 SSH 登录，还能完美兼容 scp、sftp 等文件传输工具，甚至可以直接配合 VS Code 等现代开发工具使用。
- 安全性高：中间跳板机不需要保存目标服务器的私钥，所有认证请求都由客户端发起。

## 常见误区和注意事项

1. 跳板机通常位于受控网络的边缘，是唯一对外开放 SSH/端口访问的安全中转站。使用 ProxyJump 方案传输文件时，跳板机仅仅作为中转站，跳板机既看不到你传了什么文件，也无法篡改文件内容。数据流：本地电脑 ➡️ 跳板机 ➡️ 目标服务器。
2. 因为跳板机仅仅作为数据流的中转站，所以跳板机不需要保存目标服务器的私钥或配置免密登录。所有的 SSH 认证请求，都是由你的本地电脑直接发起的。正确的密钥配置关系是：
   - 关系一（必须）：本地电脑 ➡️ 跳板机（配置免密）
   - 关系二（必须）：本地电脑 ➡️ 目标服务器（配置免密）
   - 关系三（不需要）：跳板机 ➡️ 目标服务器（完全不需要配置任何免密或密钥）
3. 虽然跳板机到目标服务器无需配置任何免密或密钥，但是数据流最终是路过跳板机后再到目标服务器上，所以跳板机和目标服务器要在同一内网，并且防火墙或者安全组对跳板机开放22端口访问。

## 配置方法

### 跳板机配置

```bash
vim /etc/ssh/sshd_config

# 1. 安全加固：禁用密码登录，强制使用密钥认证
PasswordAuthentication no
PubkeyAuthentication yes

# 2. 安全加固：禁止 root 用户直接远程登录
PermitRootLogin no

# 3. 核心功能：允许 TCP 端口转发（ProxyJump 依赖此功能）
AllowTcpForwarding yes

# 4. 安全加固：允许 SSH Agent 转发（可选，方便免密透传）
AllowAgentForwarding yes

# 5. 安全加固：禁用 X11 图形转发，减少攻击面
X11Forwarding no

# 配置完成后重启SSH服务使配置生效
systemctl restart sshd
```

### 客户端配置（本地电脑）

1. 生成 SSH 密钥
   ```bash
   ssh-keygen -t ed25519 -C "your_email@example.com"
   ```
2. 部署跳板机 SSH 密钥
   ```bash
   # 配置免密连接跳板机
   ssh-copy-id -i ~/.ssh/id_ed25519.pub jump-user@jump-server-ip
   ```
   - jump-user：跳板机的用户名
   - jump-server-ip：跳板机的地址
3. 编辑本地 SSH 配置文件
   ```bash
   vim ~/.ssh/config

   # 1. 定义跳板机
   Host jump-server
       HostName 123.456.789.123       # 跳板机的公网 IP
       User jump-user                 # 跳板机登录用户名
       Port 22                        # 跳板机 SSH 端口
       IdentityFile ~/.ssh/id_ed25519 # 本地对应的私钥路径
       ServerAliveInterval 60         # 每60秒发送心跳，防止连接断开
       ServerAliveCountMax 3          # 3次无响应则断开

   # 2. 定义内网目标服务器
   Host target-server
       HostName 192.168.1.100         # 目标服务器的内网 IP
       User target-user               # 目标服务器登录用户名
       IdentityFile ~/.ssh/id_ed25519 # 目标服务器对应的私钥路径
       ProxyJump jump-server          # 指定通过上面定义的 'jump-server' 主机进行跳转
   ```
4. 设置本地配置文件权限
   ```bash
   chmod 600 ~/.ssh/config
   ```
5. 部署目标服务器 SSH 密钥
   ```bash
   # 配置免密连接目标服务器
   ssh-copy-id -i ~/.ssh/id_ed25519.pub target-server
   ```
### 验证测试
1. 验证ssh登录
   ```bash
   ssh target-server
   ```
2. 验证文件上传
   ```bash
   scp -r my_folder target-server:/remote/path/
   ```
   - -r：代表递归（recursive）。这是传输文件夹的必加参数，它会让 scp 复制整个目录及其包含的所有子文件夹和文件。
   - /remote/path/：目标服务器上的绝对路径.
   - 路径末尾的斜杠：如果目标路径写为 /remote/path/（带斜杠），文件夹 my_folder 会作为子目录被放入该路径下（即 /remote/path/my_folder）。如果写为 /remote/path（不带斜杠），my_folder 里的所有内容会被直接平铺放入 /remote/path 中。建议始终带上斜杠以避免文件散落。

---

> 作者: [beneliu](https://github.com/beneliu)  
> URL: https://benelin.site/posts/devops/1180278/  

