ssh 配置
样例
Windows 下是 %userprofile%\.ssh\config
。Linux 下自己对应一下。
- 含有
ForwardAgent
选项表示启用代理转发,相当于在连接它时自动添加了参数-A
。 - 含有
ProxyJump
表示先通过跳板机再连接到此主机,相当于在连接它时自动添加了参数-J
。
样例:
Host github
HostName github.com
IdentityFile ~/.ssh/id_rsa
Host jump
HostName <能访问的 IP>
User <用户>
Port <能访问的端口>
IdentityFile ~/.ssh/id_rsa
Host jump_docker
ProxyJump jump
HostName localhost
User root
Port 22275
其中 jump_docker
在局域网中,我们必须通过跳板 jump
来访问。这里 jump_docker
没有写 IdentityFile
,如果默认的密钥文件(比如 ~/.ssh/id_rsa 等)匹配不了,那么就只能通过密码登陆。
转发代理(-A
)不如代理跳转安全
Man page 的说法
man ssh-agent
:
它是一个在启动时记录私钥的程序,这样方便匹配公钥验证。
Connections to ssh-agent may be forwarded from further remote hosts using the -A option to ssh(1) (but see the caveats documented therein), avoiding the need for authentication data to be stored on other machines.
什么是 ssh-agent
ssh-agent 在内存中记录私钥,然后完成公钥指纹匹配请求。根据文章 https://www.cnblogs.com/f-ck-need-u/p/10484531.html,如果密钥不是规范密钥(比如 ~/.ssh/id_rsa),就要手动指定具体的 IdentityFile,否则可以考虑使用 ssh-agent。
Behind the scenes, ssh-agent binds to a Unix domain socket to communicate with other programs (
$SSH_AUTH_SOCK
environment variable).
ssh-agent 只需要对私钥解密一次。也就是说如果私钥由密码保护,只需要输入一次密码,直到 ssh-agent 停止,都不用再次输入密码。
什么是 ForwardAgent
代理转发则是指连接服务器后将服务器上 ssh-agent 收到的请求转发到本地来。这样我们先 ssh 到 A,打开 shell 之后,在 A 的 shell 中 ssh B,也是能登陆的(假设本地能过 A 和 B 的密钥检查,但是仅 A 不能通过 B 的密钥检查;另一方面,本地能够直接连接到 A,A 也能直接连接到 B,但是 本地 不能直接连接到 B)。
https://www.infoworld.com/article/3619278/proxyjump-is-safer-than-ssh-agent-forwarding.html
根据上面的网页,转发代理允许目标机器对 client 的 key challenge(从已知公钥构造)转发到本地机器上,这需要打开一个 socket,这样特权用户就能通过 socket 获取本地的 ssh-agent 的信息,攻击者也能通过构造密钥来以 agent 认可的身份完成登陆;而代理跳转是通过 ssh 加密传输 stdin 和 stdout 的数据,所以更加安全。
http://www.unixwiz.net/techtips/ssh-agent-forwarding.html
这篇文章是最清楚的,介绍了从 ssh 密码连接、公钥连接到 ssh-agent、agent 转发以及 key challenge 构造。它将 ssh agent 描述为在 ssh 建立连接过程中替代 ssh 完成 key challenge 的第三方程序。构造好 key response 之后还是从 ssh 发回去。
它们解决了什么问题?
以下讨论假设本机是 A,中间机器是 B,目标机器是 C。其中 A 可以访问 B,B 可以访问 C,但 A 不能直接访问 C。
ForwardAgent 和 ProxyJump 都解决了密钥验证问题,允许在密钥集中存储在本地的情况下经过中间机器去访问目标机器。ProxyJump 还解决了连接问题,在本机和目标机器之间形成逻辑上直接连接的信道;而 ForwardAgent 是在登陆上中间机器后使用的,本身就不存在连接问题。
使用 ForwardAgent 时,一般情况下意图工作机器是 B,仅部分操作需要登陆机器 C 或者让机器 C 验证身份。使用 ProxyJump 时,意图工作机器只能是 C,B 仅充当连接跳板。这个时候虽然 ForwardAgent 也能达到目标,但是 ProxyJump 更好:首先是它使用起来更加方便,允许直接自动连接目标服务器,而不需要先手动连接到中间服务器、再手动连接到目标服务器,也不需要开启 ssh-agent、加载密钥,不需要修改 /etc/ssh/sshd_config 中的 AllowAgentForwarding
;其次它也更加安全,直接转发了 stdin 和 stdout,就像本地 ssh 直接和最终目标机通信一样,不需要 ssh-agent 的参与。
实验:通过 ForwardAgent 访问 GitHub
本小节参考 GitHub 的官方教程。因为 ProxyJump 比较简单所以略去实验。
假设本机已经生成了公钥。首先需要在 GitHub 个人设置中添加本机的公钥,然后添加以下配置到 ~/.ssh/config 中:
Host github
HostName github.com
IdentityFile ~/.ssh/id_rsa
然后运行 ssh -T git@github.com
,确保能够成功登陆。
用以下配置创建一个新的镜像(用 root 登陆,密码是 123456):
# Image name: mysshd.
FROM debian:trixie
RUN apt update && apt install -y --no-install-recommends openssh-server neovim && rm -rf /var/lib/apt/lists/*
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config
RUN sed -i 's/#AllowAgentForwarding yes/AllowAgentForwarding yes/g' /etc/ssh/sshd_config
RUN echo root:123456 | chpasswd
# Needs privilege separation directory.
RUN mkdir /run/sshd
# Needs absolute path.
ENTRYPOINT [ "/usr/sbin/sshd", "-D" ]
用以下命令去构建和运行镜像(入口是 /usr/sbin/sshd -D
,不会有任何输出,并不是程序卡住了):
docker build . -t mysshd
docker run -it --rm -p 45522:22 mysshd
开启一个新的终端,启动 ssh-agent 并加载默认密钥:
eval `ssh-agent`
ssh-add -k
连接之前容器中启动的 sshd
(注意要加 -A
打开转发代理,而且当前终端需要有 ssh-agent 产生的环境变量 SSH_AUTH_SOCK
):
ssh root@localhost -p 45522 -A
然后测试是否能够正常连接 Github:
$ ssh -T git@github.com
# Attempt to SSH in to github
> Hi USERNAME! You've successfully authenticated, but GitHub does not provide
> shell access.
再试试不用选项 -A
连接之前的容器,就会提示访问被拒绝(因为容器并没有配置 GitHub 的连接信息)。