精通 SSH 代理和代理转发,实现无缝身份验证

安全使用ssh-agent和代理转发,处理带密码的密钥、跳板主机和多跳SSH工作流。

掌握SSH代理与代理转发,实现无缝认证

安全外壳(SSH)密钥认证比可重复使用的密码更安全,但当你连接多个主机时,密码短语可能会拖慢你的速度。ssh-agent通过在当前登录会话中保持解锁的密钥可用解决了这个问题,而代理转发则允许你通过受信任的跳板主机使用这些本地密钥。谨慎使用,这能让你在不将私钥复制到服务器的情况下获得更流畅的SSH访问。

理解SSH代理

ssh-agent是一个后台程序,它安全地将你的私有SSH密钥以解密状态保存在内存中,随时可用。你无需每次连接远程服务器时都输入密码短语,只需在将密钥添加到代理时输入一次。这显著提高了工作流效率,同时不牺牲密码短语保护所提供的安全性。

启动和管理SSH代理

启动代理并使其套接字可用于你的shell会话的过程至关重要。在大多数现代Linux和macOS系统上,代理通常由系统的初始化脚本或桌面环境自动启动。

如果需要手动启动,请使用以下命令序列。这确保了必要的环境变量(SSH_AUTH_SOCKSSH_AGENT_PID)为当前shell会话正确设置:

# 启动代理并输出必要的环境变量
eval "$(ssh-agent -s)"

向代理添加密钥

代理运行后,使用ssh-add命令将私钥加载到其内存中。如果密钥受密码短语保护,系统会提示你输入。

示例:添加默认密钥

ssh-add
# 按提示输入密码短语
# 身份已添加:/home/user/.ssh/id_ed25519 (user@localbox)

示例:添加特定密钥文件

ssh-add ~/.ssh/my_project_key

验证已加载的密钥

你可以使用-l标志检查代理当前管理的密钥:

ssh-add -l
# 输出示例:
2048 SHA256:abcdef1234567890... user@localbox (RSA)

在私钥上使用密码短语。代理仅节省你在会话期间重复输入密码的麻烦;它不会使磁盘上未受保护的私钥更安全。

解密SSH代理转发

代理转发是一个强大的功能,它允许你使用本地ssh-agent中加载的密钥来认证从第一个远程主机连接的第二个远程主机。

这对于多跳工作流非常有用,例如从笔记本电脑连接到堡垒主机,然后从该堡垒主机连接到内部服务器。

代理转发的工作原理

当你启用代理转发连接到主机A时,SSH会在主机A上创建一个特殊的UNIX域套接字。该套接字充当代理。当你尝试从主机A SSH到目标主机B时,主机A的SSH客户端通过此代理套接字将认证请求转发回本地机器上运行的ssh-agent。代理使用存储的私钥处理加密挑战,并将成功信号发送回去,从而完成对主机B的认证。

你的私钥不会离开本地机器。远程主机获得的是临时代理套接字的访问权限,而不是密钥文件本身。

启用代理转发

要在连接远程主机时启用代理转发,请在ssh命令中使用-A标志:

ssh -A user@bastion-host

你也可以在~/.ssh/config中为受信任的主机进行配置:

Host bastion-host
    Hostname 192.168.1.100
    User myuser
    ForwardAgent yes

测试代理转发

成功连接到启用了转发的堡垒主机后,测试代理套接字是否在远程机器上可用。你可以检查SSH_AUTH_SOCK环境变量是否存在,或在远程机器上使用ssh-add -l

在堡垒主机上:

# 检查密钥是否已转发(本地运行的代理应响应)
ssh-add -l
# 如果成功,你将看到本地代理管理的密钥。

现在,你可以从堡垒主机使用密钥认证SSH到内部目标主机,而无需在堡垒主机上存在私钥文件:

在堡垒主机上:

ssh user@target-host
# 通过转发的代理套接字,使用本地密钥无缝完成认证。

安全考虑

代理转发很方便,但它会改变你的风险状况。

当在远程主机上启用转发时,具有该主机root访问权限的用户通常可以在你的SSH会话打开期间访问你转发的代理套接字。他们无法从代理读取你的私钥,但可能能够要求代理为你可访问的其他服务器签署认证挑战。

缓解策略

  1. 默认关闭转发: 仅在需要特定多跳任务时使用-A
  2. ~/.ssh/config中限制转发: 仅为受信任的跳板服务器启用转发。
    Host trusted-jump
        ForwardAgent yes
    Host untrusted-server
        ForwardAgent no
    
  3. 要求敏感密钥确认: ssh-add -c ~/.ssh/keyname会在代理使用该密钥前要求确认。当转发的代理暴露给你管理但并非完全信任的主机时,这很有帮助。
  4. 不需要转发时优先使用ProxyJump 如果你的目标只是通过堡垒主机访问私有主机,ssh -J user@bastion user@target通常可以避免将代理转发到堡垒主机。

管理代理生命周期

管理代理的生命周期是一个好习惯,尤其是在手动操作时。当你关闭终端会话时,代理可能仍在后台运行,消耗资源并可能使套接字保持活动状态。

移除密钥

要从代理内存中移除特定密钥:

ssh-add -d ~/.ssh/my_project_key

要从代理中移除所有密钥:

ssh-add -D

停止代理

要终止代理进程并清除内存中所有加载的密钥:

ssh-agent -k

这会输出shell命令以取消设置相关的环境变量并杀死代理进程。如果你使用eval "$(ssh-agent -s)"启动了代理,请运行eval "$(ssh-agent -k)"以将清理应用于当前shell。

关键要点

日常密钥处理使用ssh-agent,并将代理转发保留给确实需要的受信任跳板主机。对于简单的堡垒主机访问,先尝试ProxyJump;对于转发的代理,保持会话简短,并使用ssh-add -dssh-add -D移除不再需要的密钥。