登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

ssh-add -h 怎么限制转发密钥只能用于指定主机

来源:17golang原创

时间:2026-10-13 10:35:43 268浏览 收藏

给密钥加载时重复传入 ssh-add -h,可以限定它从本机连接哪些主机,以及经过指定主机后还能认证到哪里。经跳板机登录部署服务器时,既要允许本机到跳板机,也要允许跳板机到目标服务器;只写最终服务器并不能自动放行中间一跳。

这限制的是 ssh-agent 中这一份密钥的使用,不是服务器防火墙,也不会修改目标账号的权限。下面仅用于本人获授权的测试主机,不在生产服务器直接试错。

OpenSSH 官方地址:https://www.openssh.com/

先把密钥授权范围写成明确的连接对

假设本机持有专用部署密钥,希望允许连接 bastion.example.net,并经该跳板机认证到 deploy@app.example.net。这些域名只是占位符,需要换成自己的真实主机。普通加载没有目的地约束;增加两条规则后,授权范围就变成两类明确连接,而不是“任何能接触代理的主机都可以尝试使用这把密钥”。

约束写法本例含义
bastion.example.net允许从代理所在本机认证到跳板机,未限定该跳目标用户名
bastion.example.net>deploy@app.example.net允许经跳板机认证到应用主机的 deploy 账号

src>dst 不是 Shell 重定向,所以必须把整个约束用引号包起来。多条规则表示允许的连接集合;不是从左到右执行的命令步骤。

本机代理、部署密钥、主机记录和两条目的地约束的静态关系
图1:约束配置结构图。可信主机记录为规则提供主机身份,代理保存密钥及允许的连接关系;不是操作截图。

准备可信主机密钥和可用的代理

约束中的主机身份最终以主机密钥识别,不只是比较一个域名字符串。本机执行 ssh-add 时,必须能从可信 known_hosts 文件找到跳板机与应用主机的主机密钥。通过管理员提供的指纹或组织的可信渠道确认记录;不要把未经核实的扫描输出直接当作信任依据。使用专门的记录文件时,通过 -H 指定。

# 查看客户端版本,并核对本地手册是否支持目的地约束
ssh -V
man ssh-add

# 在本机查看代理中的指纹;不能据此证明约束已经生效
ssh-add -l

# 检查可信文件中是否包含两台主机,缺失时先补充已核实的记录
ssh-keygen -F bastion.example.net -f ~/.ssh/known_hosts_deploy
ssh-keygen -F app.example.net -f ~/.ssh/known_hosts_deploy

目的地约束从 OpenSSH 8.9 引入。代理、加载工具、SSH 客户端都要支持;经转发代理认证还依赖相应客户端及服务器协议支持。发行版可能回移功能,不能只看版本字符串就下结论。应用主机记录也必须存在于本机,不能认为跳板机上有记录就足够。

给专用部署密钥添加两条约束

使用没有在其他代理中以无限制方式加载的专用密钥。若当前代理已装有同一密钥的普通身份,先移除该身份,再带约束添加;这一操作会影响使用该身份的新认证,应先确认没有其他任务依赖它。以下命令只处理这个身份,不清空全部密钥。

# 仅在该身份已经加载时执行;移除代理身份不会删除磁盘私钥
ssh-add -d ~/.ssh/id_ed25519_deploy.pub

# 本机允许到跳板机,随后允许经跳板机到应用主机的 deploy 账号
# -H 指定已核实的主机记录;-t 让本次代理身份最多保留一小时
ssh-add -H ~/.ssh/known_hosts_deploy -t 1h \
  -h 'bastion.example.net' \
  -h 'bastion.example.net>deploy@app.example.net' \
  ~/.ssh/id_ed25519_deploy

添加失败就停止后续操作,不要为了让连接成功改成普通 ssh-add。若还需第三跳,必须逐跳追加真正需要的约束,不能把整条链写成一个包含多个大于号的参数。

用同一把密钥比较允许和拒绝的连接

这里的效果指标是授权连接是否获准,不是延迟或吞吐。可在隔离测试环境记录四组认证:本机到跳板机、经跳板机到应用主机的 deploy 账号、本机直达应用主机、经跳板机到未授权的其他账号。前两组是规则许可;后两组不在这组规则之内。规则许可不等于一定登录成功,服务器仍可因账号、公钥或权限配置拒绝。

测试前在相应机器的可信记录文件核对服务器身份;服务器端为目标账号配置专用公钥。不要在跳板机复制部署私钥。若能用 ProxyJump 完成任务且不需要远端再使用代理,通常无需代理转发;本例演示的是确实需要在远端使用代理的情况。

# 在本机连接跳板机:仅对此次连接显式启用代理转发
# -i 选用公开身份,避免把磁盘私钥签名误当作代理签名
ssh -A -i ~/.ssh/id_ed25519_deploy.pub \
  -o IdentitiesOnly=yes -o PreferredAuthentications=publickey \
  -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no \
  -o UserKnownHostsFile=~/.ssh/known_hosts_deploy \
  ops@bastion.example.net

# 在跳板机的上述会话中执行;这里只保存公钥,不保存部署私钥
# 跳板机也应已有独立核实的应用主机记录,且没有其他可用身份干扰
ssh -i ~/.ssh/id_ed25519_deploy.pub \
  -o IdentitiesOnly=yes -o PreferredAuthentications=publickey \
  -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no \
  deploy@app.example.net

以上是复现示例,未声称已经在本文环境执行。公开身份文件需事先以可信方式放到跳板机。另做拒绝组时也要保持同一身份与认证设置,并只测试获授权的账号和服务器。单凭“登录成功”无法证明使用了受限代理:磁盘私钥、其他代理身份或额外认证方式都可能干扰判断。

转发认证请求与用户名、服务器主机密钥和允许路径之间的静态依赖
图2:转发认证边界结构图。认证请求与目标用户名及主机身份关联,代理依据允许连接关系判断能否使用密钥;不表示实测结果。

失败时先区分主机记录、协议和账号问题

现象首先检查
添加约束身份失败当前代理是否支持、可信文件是否包含正确主机密钥、域名是否匹配记录
跳板机能登录,应用主机失败是否遗漏跳板机到目标的规则、目标用户名是否一致、转发连接是否具备协议支持
拒绝组也成功是否真的使用专用代理身份、有无磁盘私钥或其他认证回退
更换服务器主机密钥后失败确认新指纹与变更合法性,更新可信记录,再重新加载受限身份

需要诊断时,可在读者自己的测试环境给 SSH 命令增加 -vv,观察实际身份和认证方式。不要把包含内部主机、用户名或其他敏感信息的完整日志公开;不要用关闭主机身份检查来修复问题。

理解代理限制不能替代的安全措施

受限密钥依然可能被拥有远端代理套接字访问权的人用于规则已允许的目的地。因此应缩小获准主机与账号范围、减少转发、使用专用密钥并控制远端账号权限。官方说明也强调:这些约束不能阻止远端套接字被再次转发,只是其用途仍受到目的地限制,不能把它宣传成绝对的路径隔离。

同一密钥在别处普通加载会怎样?

约束绑定这次加入代理的身份,不是给私钥文件永久打标记。别的代理或磁盘私钥仍须独立控制,测试也要排除这些来源。

能否用来签署 Git 提交?

不要把目的地受限身份当成通用签名密钥。OpenSSH 的设计说明将它限定于 SSH 用户认证;其他签名用途应采用独立身份与配置。

支持不完整时应不应该取消约束?

不应作为自动回退。先确定参与组件能力,再决定升级或采用不需要代理转发的方案;允许范围不应因为兼容失败而悄悄扩大。

官方文档:https://man.openbsd.org/ssh-add;https://www.openssh.com/agent-restrict.html。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>