SSH 跳板机配置实战:ProxyJump、密钥管理与审计留痕

服务器都在内网、对外只暴露一台跳板机,是最常见的运维网络形态。但跳板机用不好容易走极端:要么层层手动 ssh,效率低还容易跳错;要么为图方便开一堆后门,跳板机成了最大风险点。本文给出一套完整配置:客户端用 ProxyJump 一键直达目标机(含多级跳板),跳板机侧做最小化加固,密钥与 Agent 转发讲清安全取舍,最后补上连接审计的轻量做法。适用环境为 OpenSSH 7.3 以上版本(ProxyJump 自此引入),客户端与服务端均为 Linux。

前置条件

  • 一台有公网地址的跳板机(下文称 bastion.example.com)与若干仅内网可达的目标机;
  • 已为自己生成 SSH 密钥对,公钥已分发到跳板机与目标机(分发方式决定了要不要 Agent 转发,下面会讲);
  • 跳板机上可改 sshd 配置并能重启 sshd(操作前先保留一个已登录会话,防止改错把自己锁在外面);
  • 客户端 OpenSSH 版本不低于 7.3,用 ssh -V 确认。

一、架构与场景

跳板模式的数据流是:客户端先与跳板机建立 SSH 连接,在这条连接上再打开一个通道直达目标机的 22 端口,最终的登录认证发生在客户端与目标机之间。理解这点很关键:目标机看到的来源 IP 是跳板机,目标机的登录认证用的是你与目标机之间的密钥,跳板机只做 TCP 转发、不接触会话内容。ProxyJump 正是把这个"两段连接"封装成一个参数,连接细节写进 ~/.ssh/config 后,日常使用就是一条 ssh 目标机别名。

二、客户端配置:ProxyJump 与多级跳板

把跳板关系写进 config 文件是最推荐的方式,别名、用户、密钥、跳板链一次定义,之后所有工具(ssh、scp、sftp、rsync、Ansible)都能复用。ProxyJump 支持多级:用逗号分隔多个跳板,按从外到内的顺序写。

# ~/.ssh/config

# 第一级:公网跳板机
Host bastion
    HostName bastion.example.com
    User ops
    Port 22
    IdentityFile ~/.ssh/id_ed25519

# 第二级:内网中的中转机(经 bastion 到达)
Host relay
    HostName 192.0.2.20
    User ops
    ProxyJump bastion

# 最终目标机:经 bastion、relay 两级跳板到达
Host node-01
    HostName 192.0.2.31
    User ops
    ProxyJump bastion,relay

# 一段网络统一走跳板,避免逐台写
Host 192.0.2.*
    User ops
    ProxyJump bastion

临时使用不想改文件时,命令行等价写法是 ssh -J ops@bastion.example.com ops@192.0.2.31,多级跳板同样用逗号分隔。scp 与 rsync 因为走的是 ssh 通道,config 里定义好后直接用别名即可,不需要额外参数。

# 命令行临时跳板(不依赖 config)
ssh -J ops@bastion.example.com ops@192.0.2.31

# config 定义后,日常操作全部简化为别名
ssh node-01
scp ./fix.sh node-01:/tmp/
rsync -av ./conf/ node-01:/tmp/conf/

三、-W 与 ProxyCommand:老式写法与区别

在 ProxyJump 出现之前,实现跳板靠的是 ProxyCommand 配合 ssh -W:让第一段 ssh 以标准输入输出的方式把流量转发给目标。两者效果相同,但写法与可维护性差很多:ProxyCommand 要手写完整命令、处理引号与变量替换,多级跳板时嵌套得非常难读;ProxyJump 是 OpenSSH 内建语义,自动复用连接多路复用与认证流程。老写法如今只在客户端版本太旧或需要自定义转发命令(如经特殊代理)时才用,了解即可。

# 老式等价写法(仅作对照,新配置请用 ProxyJump)
Host node-01-old
    HostName 192.0.2.31
    User ops
    ProxyCommand ssh -W %h:%p ops@bastion.example.com

四、跳板机加固要点

跳板机的定位是"只做转发的中转站",加固原则是收窄它的一切其他能力。核心几条:只允许密钥登录并关闭密码认证;用 AllowUsers/AllowGroups 只放行运维账号;用 Match 块做细粒度控制——跳板机 sshd 必须保留 AllowTcpForwarding(ProxyJump 靠它工作),不能简单用 DisableForwarding 一关了之,因为那会把 ProxyJump 依赖的 TCP 转发也关掉;正确做法是给跳板用户只放行到内网目标网段的 22 端口(PermitOpen 限定可达地址与端口),同时禁止 X11 等无关能力。目标机的加固反而可以更严:只接受来自跳板机网段的连接。

# 跳板机 /etc/ssh/sshd_config 关键片段
PasswordAuthentication no
PermitRootLogin no
AllowGroups ops
X11Forwarding no
AllowAgentForwarding no

# 针对跳板用户组:只允许把流量转发到内网服务器网段的 22 端口
Match Group ops
    AllowTcpForwarding yes
    PermitOpen 192.0.2.0/24:22
    DisableForwarding no

改完配置先用 sshd -t 校验语法再 reload,不要直接 restart 中断现有会话。另外给跳板机登录加多因素认证、限制来源 IP(安全组只放行办公出口地址)属于基础设施层面的加固,条件允许都应该配上,这比 sshd 参数更管用。

五、密钥与 Agent 转发的安全取舍

这里有个必须想清的取舍:目标机的认证密钥放在哪。为每台目标机单独分发公钥(私钥只留在本地),跳板机上不落任何私钥,这是最安全的方式,缺点是公钥要逐台分发、人员变动时逐台回收。另一种是 Agent 转发(ForwardAgent yes / ssh -A):本地私钥不出机器,认证时跳板机把签名请求回传给本地 agent,看似两全,但风险在于——只要你连着跳板机,能访问你 agent socket 的人(如跳板机 root 或入侵者)都能借你的身份登录所有目标机,且你无感知。因此生产原则是:默认不用 Agent 转发,坚持公钥直达分发;确需转发时只在具体 Host 条目里单开、用完即关。配合 ssh-agent 时给密钥设 passphrase 并用 ssh-add -c 让每次使用都需要确认,是折中的加固手段。

# 仅对个别主机开启 Agent 转发(写在对应 Host 条目内,勿写全局)
ssh -A node-01

# 给 agent 中的密钥加使用确认与生存期,降低被盗用风险
ssh-add -c -t 3600 ~/.ssh/id_ed25519

六、审计留痕的轻量做法

审计的最低要求是回答三个问题:谁、在什么时间、从哪台跳板机连到了哪台目标机。本机层面开 sshd 的详细日志即可:把 LogLevel 调到 VERBOSE,登录事件会记录使用的密钥指纹,配合目标机上"来源只有跳板机"的日志,两段一拼就是完整链路。需要会话内容留痕(如合规要求录屏)时再上 script 命令或专用审计系统,以下是轻量方案:把跳板机与目标机的 auth 日志集中收集到一台日志机,并对成功登录做一条结构化记录。

# 跳板机与目标机 /etc/ssh/sshd_config 均设置,记录密钥指纹
LogLevel VERBOSE
# 在日志机上快速还原"谁经跳板机登录过目标机":先看跳板机的转发与登录记录
grep -E 'Accepted|forwarding' /var/log/secure | grep 'ops'

# 目标机侧按跳板机来源过滤登录事件
grep 'Accepted' /var/log/secure | grep 'from 192.0.2.20'

日志路径在 Debian/Ubuntu 系是 /var/log/auth.log,RHEL 系是 /var/log/secure。注意只记录"连接元数据"是轻量审计的边界;要录制会话内容请明确告知使用者并评估存储与合规,不要偷偷录。

验证

  • 一条命令直达:本地执行 ssh node-01 hostname 无需人工中转即可返回目标机主机名;
  • 链路正确:加 -v 执行一次,日志中能看到先连跳板机、再经通道连接目标机的完整过程,且目标机 auth 日志中的来源 IP 是最后一级跳板;
  • 加固生效:在跳板机上直接尝试访问 PermitOpen 之外的地址应被拒绝;用密码登录跳板机应被拒绝。

常见问题

  • 报 "channel 0: open failed: administratively prohibited"。转发被目标跳板拒绝:检查跳板机 sshd 的 AllowTcpForwarding 与 PermitOpen 是否放行了该目标,以及是否误开了 DisableForwarding。
  • 跳板机能登,目标机报 Permission denied (publickey)。密钥链断裂:你的公钥没有分发到目标机,或 IdentityFile 指定了错误的私钥。用 ssh -v node-01 看它到底拿哪把钥匙去认证,注意认证发生在本地与目标机之间,与跳板机无关。
  • 连接长时间卡住后超时。多为网络层不通或 MTU 问题:先直连跳板机确认第一段通,再从跳板机上手动 ssh 目标机验证第二段;分段验证比反复改 config 有效。
  • config 写了却不生效。Host 匹配按首个命中为准,通配规则要写在具体规则后面;用 ssh -G node-01 打印最终生效配置,一眼就能看出哪条没命中。

小结

跳板机配置的核心就三句话:客户端把跳板链一次性写进 config,ProxyJump 让多级跳板变成一个别名;跳板机只保留转发能力,用 PermitOpen 这类细粒度参数收窄可达范围;认证坚持公钥直达分发,Agent 转发默认关闭、按需单开。审计先做到元数据可追溯:谁、何时、经哪台跳板、到哪台目标,四要素齐了就不怕查无此人。把这套配置沉淀成团队统一的 config 模板,是跳板体系最省事的落地方式。

发表回复

后才能评论