跳板机明明能连上,为什么内网服务器还是进不去?

周一早上接到发布窗口的告警时,跳板机 bastion-a 的 SSH 连接是绿色的,目标服务器 db-prod 却一直超时。很多人第一反应是再试一次密码,或者把目标端口从 22 改成一个"看起来更像数据库"的端口。这样做只会让日志变得更乱,因为此时还没有证明跳板机能替你访问目标地址。这就是典型的 SSH 跳板机连接失败现场,症状在目标,原因可能在任意一段。

多跳连接最容易制造一种错觉:本地到跳板机通了,于是整条路径应该都通。实际上,连接至少分成三段,本地到跳板机、跳板机到下一跳、最后一跳到目标。任意一段的 DNS、路由、认证或转发权限出问题,客户端都可能只给你一个笼统的超时。

我排这类问题时,会把"登录跳板机"和"从跳板机抵达目标"当成两个独立动作。这个顺序看起来慢一点,却能快速缩小范围,也能避免把生产凭据反复填进错误的连接配置。

先确认你连到的真是跳板机

本地先单独连接 bastion-a,不要一上来就叠加 -J

bash 复制代码
ssh -vvv ops@bastion-a

看到 shell 提示符后,先确认主机名、网卡地址和当前用户:

bash 复制代码
hostname
ip addr
whoami

如果这里都不稳定,目标服务器还没有进入排查范围。跳板机可能被 DNS 轮询到不同节点,也可能刚完成重装导致主机密钥变化。OpenSSH 10.3 起,命令行传入的 -J / ProxyJump 用户名和主机名会做更严格的校验;这能减少不可信输入带来的问题,但不会替你验证网络拓扑是否符合预期。此时先确认 SSH 跳板机本身的地址、用户和认证,再看下一跳。

图形工具可以把跳板连接保存起来,但我仍会在终端里做一次最小确认。连接名叫"生产跳板"不等于远端真的就是生产跳板,尤其是复制配置、切换 VPN 或调整 DNS 之后。

如果公司有多个出口或多个堡垒机集群,我还会记录本地实际使用的出口地址。相同的跳板主机名可能根据网络区域解析到不同节点,节点之间的安全策略和可达网段未必完全一致。把"我在办公室能连"直接推断成"家里 VPN 也能连",往往会把环境差异误认为目标故障。

"跳板机可达"不代表它能看见目标

确认第一段后,直接在跳板机上测试目标地址和端口。目标是判断网络层,不是登录目标:

bash 复制代码
getent hosts db-prod
nc -vz -w 3 10.30.8.12 22

如果系统没有 nc,可以用 Bash 的 TCP 探测做一个临时验证:

bash 复制代码
timeout 3 bash -c '</dev/tcp/10.30.8.12/22' && echo open || echo closed

这里的结果只说明端口是否能建立 TCP 连接,不代表 SSH 认证一定成功。若跳板机解析出的 db-prod 地址与工单记录不同,先处理 DNS 或 hosts 文件;若地址正确但端口不通,再看安全组、路由表和目标机防火墙。不要在本地反复执行 ssh -J,那样无法告诉你失败发生在哪一跳。

测试时最好保留一次成功和一次失败的完整输出。成功输出能证明某个时间点的路径和权限,失败输出则提供对照,尤其是 DNS 解析结果、连接目标地址和超时发生的秒数。只贴一句"连接超时"给网络同事,信息量远不够;把两段输出和目标端口一起交过去,定位速度会快很多。

ProxyJump 配置,顺序比选项更多重要

官方文档把多跳路径画成"本地电脑 -> 跳板机 -> 目标服务器",并支持继续串联第二台跳板机。配置时,跳板机要先作为普通 SSH 连接保存,再在目标连接里选择它。这样做的价值不只是界面整齐,而是每一跳可以使用各自的用户名、密钥和交互认证方式。

一个最小的 OpenSSH 配置可以这样写:

sshconfig 复制代码
Host bastion-a
    HostName bastion.example.net
    User ops
    IdentityFile ~/.ssh/ops_ed25519

Host db-prod
    HostName 10.30.8.12
    User dba
    ProxyJump bastion-a
    IdentityFile ~/.ssh/dba_ed25519

这里有两个容易漏掉的事实:目标服务器的 User 不会自动继承跳板机的用户,目标私钥也不一定和跳板机相同。若跳板机使用 2FA,认证对话框会先出现;完成第一跳认证后,客户端才会继续到目标。把验证码填错窗口,常常会被误判成"目标服务器拒绝登录"。

第二跳还可能使用不同的主机密钥校验文件。自动化环境里,如果 ProxyJump 由专用用户运行,读取到的 known_hosts、代理套接字和个人电脑不同;本地测试通过并不能证明流水线也通过。部署前我会用和任务相同的用户、相同的配置文件做一次只读连接,确认"人工路径"和"自动路径"没有悄悄分叉。

多跳链路变慢时,先算路径再谈性能

每增加一台跳板机,就增加一段网络延迟和一个可能断开的点。官方文档给出的近似关系是:总延迟约等于本地到 A、A 到 B、B 到目标的延迟之和。它不是精确性能模型,却足够帮助判断"偶尔卡住"是不是链路变长导致的。

我会给每一跳单独测一次:

bash 复制代码
ping -c 3 bastion-a
ssh bastion-a 'ping -c 3 10.30.8.12'

第二条命令依赖跳板机允许执行 ping,失败时不要直接结论为网络不通,可能只是 ICMP 被禁用。可以改成在跳板机上运行 TCP 探测。对真正的 SSH 连接,再加 -oConnectTimeout=5 让失败更快暴露,避免一个超时把整个发布窗口拖住。

超时值也不宜无限缩短。跨地域链路或需要人工输入 2FA 的跳板,连接建立本来就可能比内网直连慢。我的做法是把"快速失败"只用于网络探测,把正式登录的超时交给链路实际延迟决定,并在发布脚本里记录每一跳耗时。这样不会因为一个过于激进的 3 秒阈值,把可用但稍慢的路径误报成故障。

认证失败,先看是哪一把钥匙在说话

多跳场景里的"Permission denied"不一定来自目标服务器。第一跳密钥错误、第二跳要求密码、目标只接受另一把公钥,都会产生相似的终端提示。详细日志会显示当前尝试了哪一个身份文件:

bash 复制代码
ssh -vvv -J bastion-a dba@10.30.8.12

如果配置了多个 IdentityFile,客户端可能按顺序尝试多把钥匙,直到触发服务端的认证次数限制。可以用 IdentitiesOnly yes 把范围收窄:

sshconfig 复制代码
Host db-prod
    IdentitiesOnly yes
    IdentityFile ~/.ssh/dba_ed25519

收窄身份范围是为了让"哪一把钥匙失败"变得可观察。确认原因后,再决定是否需要 ssh-agent、FIDO 密钥或第二跳的独立凭据。不要为了绕过限制,把目标私钥复制到跳板机磁盘上;那会改变密钥的暴露边界。

使用 ssh-agent 时还要确认转发是否真的被请求。没有转发,目标服务器看不到本地代理里的钥匙;开启转发,又会把代理能力带到跳板机上。团队通常会根据堡垒机策略决定是否允许这件事,我不会把 ForwardAgent yes 当成连接失败的通用修复。需要临时转发时,应该绑定到单个主机块,并在窗口结束后关闭。

转发权限被关掉时,客户端再聪明也没用

ProxyJump 依赖跳板机为下一段连接提供转发通道。若服务端限制了 TCP 转发,或者安全策略只允许跳板机访问一小段网段,本地配置再正确也会失败。此时应让负责跳板机的人确认 AllowTcpForwarding、目标网段 ACL 和审计策略,而不是直接打开所有转发。

如果组织使用了堡垒机审计,跳板机可能只允许固定目标、固定端口或固定时间段。把 db-prod 的地址改成另一个内网 IP 进行"试试看",反而会触发更严格的拦截。排查时保留原始目标和工单编号,方便把日志中的拒绝事件对上具体操作。

在 Xterminal 这类连接管理工具中,可以先保存跳板机,再在目标连接的跳板机选项里按顺序添加它们。工具能够减少手工输入和重复配置,但转发权限仍由服务器策略决定。图形界面显示"已连接"通常只对应当前会话,不代表后台的每个目标端口都已放行。

如果采用图形连接中心,我会给每一跳写清楚区域、用途和允许的目标,例如"华东生产跳板 -> 数据库网段",而不是只写一个模糊的"跳板"。名称越具体,批量操作时越不容易误选。连接分组可以帮助管理配置,却不能替代网络团队对可达网段的授权记录。

反例:把目标端口改成 22,问题反而被藏起来

有些团队为了让探测命令"看起来成功",会把数据库端口临时写成 SSH 的 22。这样确实可能连到跳板机上的 SSH 服务,却完全没有验证目标数据库是否可达。过几分钟再把端口改回去,现场只剩下一串互相矛盾的日志。

更好的做法是明确记录每一段的目的:跳板机到目标的 22 端口用于 SSH,目标数据库的 3306 或 5432 另行测试。端口对应服务,测试结果才有解释空间。若必须通过隧道访问数据库,也先证明隧道的两端都建立,再测试本地映射端口:

bash 复制代码
ssh -N -L 13306:10.30.8.12:3306 bastion-a
nc -vz 127.0.0.1 13306

这条命令只建立本地转发,不会替你验证数据库账号。账号失败和隧道失败要分开记录。

本地端口也要避免和已有服务冲突。13306 只是示例,如果本机已经有进程监听它,SSH 可能在建立转发时直接失败,或者你连到的是另一个应用。先用 lsof -nP -iTCP:13306 -sTCP:LISTEN 检查监听者,再选择一个临时端口,并把端口映射写进发布记录。

我会在什么时候停止继续加跳板机

一条链路里,跳板机不应无限增加。官方文档建议跳板机数量控制在较少范围,并提醒任一跳板机断开都会导致整体连接中断。我的停止条件是:已经能在每一跳证明下一跳地址和端口可达;认证使用明确的用户和密钥;转发权限有负责人确认;再增加一跳不会带来新的网络隔离价值。

如果第一跳能连、第二跳端口不通,先修路由或 ACL;如果端口通但认证失败,检查目标用户和密钥;如果两者都通过却在长时间运行中断开,才去看心跳、连接复用和中间设备超时。按这个顺序,通常不需要把整个链路拆掉重建。每一段的结果都应写入发布记录,形成可回看的内网服务器连接证据。

当故障已经定位到目标服务器内部,例如 sshd 没有监听预期端口或本地防火墙拒绝连接,跳板配置就暂时冻结,不要继续改动。先恢复目标服务,再重新验证从跳板机到目标的单段路径。一次只改一个变量,才能知道是哪项变更让连接重新变绿。

回到开头的 bastion-adb-prod,绿色的第一段从来没有承诺第二段也会通。把路径拆开、把每个端口对应到具体服务、把每把密钥绑定到正确用户,才是多跳 SSH 真正可复用的排查方法。等每一段都能说清楚,再把配置放回连接中心,发布窗口才不会被一次模糊超时反复打断。

相关推荐
qq_3494479517 小时前
Linux系统,安装git,从使用git下载仓库(GitHub, Gitee, GitLab 等),并且使用ssh密钥,可以直接执行git pull
linux·git·ssh
刘梦薇2 天前
SSH连接失败connection reset解决办法
linux·运维·ubuntu·ssh·腾讯云
三言老师3 天前
秘诀-如何远程SSN访问家里的八台电脑(frp 实操方案)
linux·运维·ssh
柒号华仔3 天前
「速通Shell」聚砖成墙,Shell函数封装之道
linux·ssh·bash
整点bug3 天前
AI 运维该不该自动执行命令?
运维·ssh·openai
进击的码力3 天前
win11 使用ssh 遇到权限too open 无法登录服务器的问题
运维·服务器·ssh
zhengqiqiqinqin4 天前
Ubuntu16.04 升级ssl到3.5.7、升级ssh到9.8p1
网络协议·ssh·ssl
像风一样自由20205 天前
加强版VScode结合remote-ssh远程连接服务器开发指南
服务器·vscode·ssh
国际云,接待5 天前
云服务器 SSH 被扫爆了怎么办:安全组、密钥登录与 Fail2ban 的完整加固清单
服务器·安全·ssh