如果你正在使用OS X并且使用加密密钥,那么这将是个麻烦的事情。 这里 是我找出解决方法经历的步骤。
简单的方法
有人可能会认为这没有问题。只需挂载你的ssh文件夹:
...
volumes:
- ~/.ssh:/root/.ssh:ro
...
这应该能正常工作,对吧?
用户问题
接下来我们会注意到我们正在使用错误的用户 ID。没关系,我们将编写一个脚本来复制并更改 ssh 密钥的所有者。我们还将在配置文件中设置 ssh 用户,以便 ssh 服务器知道谁在连接。
...
volumes:
- ~/.ssh:/root/.ssh-keys:ro
command: sh -c ‘./.ssh-keys.sh && ...’
environment:
SSH_USER: $USER
...
mkdir -p ~/.ssh
cp -r /root/.ssh-keys/* ~/.ssh/
chown -R $(id -u):$(id -g) ~/.ssh
cat <<EOF >> ~/.ssh/config
User $SSH_USER
EOF
SSH密钥密码问题
我们公司使用密码保护SSH密钥。但在Docker中这不太实用,因为每次启动容器都需要输入密码。
我们可以移除密码(如下面的例子),但存在安全风险。
openssl rsa -in id_rsa -out id_rsa2
mv id_rsa2 id_rsa
SSH代理解决方案
您可能已经注意到,本地使用ssh时不需要每次输入密码。为什么呢?这就是SSH代理的作用。 SSH代理基本上是一个服务器,它监听一个名为“ssh auth sock”的特殊文件,即Unix套接字。您可以在系统中看到其位置:
echo $SSH_AUTH_SOCK
SSH客户端通过此文件与SSH代理进行通信,以便您只需输入一次口令。 一旦它被解密,SSH代理将在内存中存储它并在请求时向SSH客户端发送。
我们可以在Docker中使用吗?当然可以,只需挂载该特殊文件并指定相应的环境变量:
environment:
SSH_AUTH_SOCK: $SSH_AUTH_SOCK
...
volumes:
- $SSH_AUTH_SOCK:$SSH_AUTH_SOCK
在这种情况下,我们甚至不需要复制密钥。
要确认密钥是否可用,可以使用ssh-add实用程序:
if [ -z "$SSH_AUTH_SOCK" ]; then
echo "No ssh agent detected"
else
echo $SSH_AUTH_SOCK
ssh-add -l
fi
在Docker for Mac中使用Unix套接字挂载的问题
不幸的是,对于OS X用户来说,Docker for Mac存在许多缺点之一就是无法在Mac和Linux之间共享Unix套接字。在D4M Github上有一个开放的问题(链接),截至2019年2月它仍然未解决。
那么这是死路吗?不是的,有一个hacky的解决方法。
SSH代理转发解决方案
幸运的是,这个问题并不是新问题。早在Docker之前,有一种方法可以在远程ssh会话中使用本地ssh密钥,称为ssh代理转发。思路很简单:你通过ssh连接到远程服务器,你可以在那里使用所有相同的远程服务器,从而共享你的密钥。
使用Docker for Mac我们可以使用一个巧妙的技巧:使用TCP ssh连接将ssh代理共享到docker虚拟机,并将该文件从虚拟机挂载到需要该SSH连接的另一个容器中。以下是演示解决方案的图片:
![SSH forwarding](https://istack.dev59.com/OjgG7.webp)
首先,我们通过TCP端口在一个linux VM中的容器内部创建一个ssh会话到ssh服务器。在这里,我们使用真实的ssh auth sock。
接下来,ssh服务器将我们的ssh密钥转发到该容器上的ssh代理。SSH代理有一个Unix套接字,它使用挂载到Linux VM的位置。也就是说,Unix套接字在Linux中有效,Mac中不起作用。
然后我们创建一个带有SSH客户端的有用容器。我们共享本地SSH会话使用的Unix套接字文件。
有一堆脚本简化了该过程:(链接)
结论
让SSH在Docker中工作可能本可以更简单。但是它可以做到。并且未来很可能会得到改善。至少Docker开发人员已经意识到了这个问题。甚至为具有构建时机密的Dockerfiles解决了这个问题。并且有一些建议如何支持Unix域套接字。