第 10 章SSH 隧道

数据库只允许内网访问时,通过一台跳板机把连接转发进去。 配置好之后,用户不需要在终端里手动开隧道——连接行为和直连完全一样。

它是怎么工作的

SSH 隧道工作原理 你的 Mac TableLite MySQL 客户端 127.0.0.1:53142 随机挑一个本机端口 (对 TableLite 来说,数据库就在这里) 跳板机 bastion.example.com deploy@:22 系统 ssh 进程 ssh -N -L 53142:… (TableLite 启动的子进程) 数据库服务器 10.0.2.5:3306 只在跳板机的内网里可达 MySQL / MariaDB 只有内网能连 SSH 加密 内网 MySQL 这条路径对你完全不可见。你在 TableLite 里填的还是「主机 = 10.0.2.5,端口 = 3306」。 本地端口是随机挑的,不会显示在主界面上,只在悬停详情里能看到。
图 10-1 SSH 隧道的连接路径。TableLite 启动一个系统 ssh 子进程做端口转发。
用的是系统的 ssh

TableLite 不自己实现 SSH 协议,而是调用 macOS 自带的 /usr/bin/ssh 做本地端口转发(-L)。这样做有三个好处:

  • 你的 ~/.ssh/configknown_hosts、ssh-agent 全部直接生效,和在终端里连一模一样。
  • 各种密钥类型、跳板机、代理,系统都已经处理好了。
  • 不用维护一份 SSH 实现。

代价是:需要在界面上管好这个子进程,退出时必须清理干净,不能留后台进程。

配置项

都在连接配置表单的「SSH 隧道」区域里。

SSH 隧道配置 SSH 隧道 通过 SSH 连接 总开关。不勾的话下面这些字段不可用,连接走直连。 SSH 主机 bastion.example.com 端口 22 SSH 用户 deploy 认证方式 使用 ~/.ssh/config 与 ssh-agent (推荐) 主机、端口、用户、密钥、ProxyJump 全部交给系统 SSH 配置决定 使用私钥 ~/.ssh/id_ed25519 选择… 私钥有口令时,第一次连接会弹出输入框 使用密码 密码保存在系统钥匙串里 使用 ssh config 别名 勾上后,「SSH 主机」里可以填 ~/.ssh/config 里的 Host 名 跳板机 user@proxy:22 先连 A 再跳 B 改了这里的配置后需要重新连接才生效。
图 10-2 SSH 隧道配置区。
字段说明
通过 SSH 连接总开关。勾上后下面这些字段才可用
SSH 主机跳板机的域名或 IP。开启「使用 ssh config 别名」时,可以填 ~/.ssh/config 里的 Host 名
SSH 端口默认 22
SSH 用户登录跳板机的用户名
认证方式三选一,见下
使用 ssh config 别名勾选后完全交给系统 SSH 配置解析该主机(包括别名、端口、用户、密钥)
跳板机形如 user@proxy:22,用于「先连 A 再跳 B」的场景

三种认证方式

三种认证方式 ① 用 ~/.ssh/config 与 ssh-agent 推荐,最省事 适用场景: · 平时就是这么连的 · 已经在 ssh-agent 里加载了密钥 · 用了 ProxyJump 之类的高级配置 在 TableLite 里要填: 只需要 SSH 主机(可以填别名) 不需要填密码,也不用手动指定密钥 你的 ~/.ssh/config 改动会立即生效, 不需要在 TableLite 里重新配置。 行为等同于在终端里敲 ssh <别名> ② 用私钥 适用场景: · 不想动 ~/.ssh/config · 不同的跳板机用不同的密钥 · 密钥不在默认位置 在 TableLite 里要填: SSH 主机、端口、用户 私钥文件路径(默认目录是 ~/.ssh) 私钥有口令时: 第一次连接弹出输入框 可以勾「记住口令」,之后存在钥匙串里 支持未加密的 RSA / ECDSA / Ed25519, 以及带口令的同类密钥。 ③ 用密码 适用场景: · 跳板机只开了密码登录 · 临时连一台别人的机器 在 TableLite 里要填: SSH 主机、端口、用户、密码 密码保存在系统钥匙串里 为什么这个放最后: 密码认证需要借助系统的密码询问 机制,在某些环境(例如服务器禁用 了密码登录)会失败并提示。 失败时的提示:SSH 认证失败: Permission denied (password).
图 10-3 三种认证方式。默认选第一种。

连接过程中的提示

连接时状态栏依次显示两条:

  1. 正在建立 SSH 隧道…
  2. 正在连接 MySQL…

隧道建立成功后,状态栏的提示里会带上隧道信息,但只在悬停详情里显示—— 主界面不显示本地端口,避免干扰。

首次连接一台新主机

自动接受新指纹,但不接受变化的指纹

系统 SSH 会记录主机指纹。TableLite 的行为是:

  • 首次连接一台新主机时,自动接受它的指纹——等同于系统 SSH 默认的 accept-new。 这样你不用先在终端里连一次。
  • 如果主机指纹发生了变化(可能是服务器重装,也可能是中间人攻击), 直接失败并展示完整警告,不会静默忽略
主机指纹变化警告 SSH 连接失败 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Offending ECDSA key in /Users/hongbo/.ssh/known_hosts:42 服务器的 SSH 指纹与本地记录不一致。这可能意味着 服务器被重装过,也可能存在安全风险。 如果你确认服务器是安全的,请在终端里手动连接一次 并清理 ~/.ssh/known_hosts 中的旧记录。 查看详细输出 关闭 TableLite 不会帮你改 known_hosts。这个决定应该由你在终端里做。
图 10-4 主机指纹变化时的警告。原始输出原样展示,不做删减。

隧道断开

断开与退出时的清理

不能留后台 ssh 进程
  • 关闭连接时同时关掉隧道,不残留后台进程
  • 退出 App 时清理所有隧道。

这一点是要专门验证的:如果在终端里 ps aux | grep ssh 还能看到隧道进程,说明清理有 bug。

错误提示

SSH 错误提示 跳板机无法连通 无法连接到 SSH 主机 bastion.example.com:22(连接超时) 用户 / 密码错误 SSH 认证失败:Permission denied (password). 私钥错误或需要口令 SSH 认证失败:私钥需要口令,或密钥未被接受 目标数据库不可达 SSH 隧道建立成功,但无法从跳板机访问 10.0.2.5:3306 跳板机上没有权限 原样展示 SSH 的错误输出,例如:listen [::1]:53142: bind: Permission denied 每一个错误面板里都有一项「查看详细输出」,显示 SSH 进程的原始错误文本,方便排查。
图 10-5 SSH 相关的错误提示。第四种特别好用——说明隧道通了但目标端口不通。
情况提示
跳板机无法连通无法连接到 SSH 主机 bastion.example.com:22(连接超时)
用户 / 密码错误SSH 认证失败:Permission denied (password).
私钥错误或需要口令SSH 认证失败:私钥需要口令,或密钥未被接受
目标数据库不可达SSH 隧道建立成功,但无法从跳板机访问 10.0.2.5:3306
主机指纹变化见上方的警告面板
跳板机上没有权限原样展示 SSH 的错误输出

明确不做

关于 SSH 的边界
  • 不支持在界面里生成或管理 SSH 密钥(用 ssh-keygen
  • 不支持端口转发之外的其他 SSH 功能(远程执行命令、SFTP)
  • 不支持保存多个跳板机的层级——只支持一个「跳板机」字段
  • 不支持在 App 内编辑 ~/.ssh/config,请用文本编辑器
  • 不自动修改 known_hosts