Inject host's SSH keys into Docker Machine with Docker Compose
我在Mac OS X上使用docker和docker machine(使用默认的boot2docker machine),并使用docker compose设置开发环境。
假设其中一个容器称为"EDOCX1"(0)。现在我要做的是打电话:
1 | docker-composer run stack ssh [email protected] |
我的公钥(已添加到
有什么办法吗?另外,如果我的钥匙有密码保护,有没有办法解锁一次,这样每次注射后我就不必手动输入密码了?
您可以将此添加到docker-compose.yml中(假设容器中的用户是根用户):
1 2 | volumes: - ~/.ssh:/root/.ssh |
此外,您还可以使用ssh代理检查更高级的解决方案(我自己没有尝试过)。
Docker有一个称为Secrets的功能,在这里很有用。要使用它,可以在
1 2 3 4 5 6 7 8 9 10 11 | --- version: '3.1' # Note the minimum file version for this feature to work services: stack: ... secrets: - host_ssh_key secrets: host_ssh_key: file: ~/.ssh/id_rsa |
然后可以在
1 | RUN mkdir ~/.ssh && ln -s /run/secrets/host_ssh_key ~/.ssh/id_rsa |
机密文件不会复制到容器中:
When you grant a newly-created or running service access to a secret, the decrypted secret is mounted into the container in an in-memory filesystem
有关详细信息,请参阅:
- https://docs.docker.com/engine/swarm/secrets网站/
- https://docs.docker.com/compose/compose-file/机密
您可以转发ssh代理:
1 2 3 4 5 6 | something: container_name: something volumes: - $SSH_AUTH_SOCK:/ssh-agent # Forward local machine SSH key to docker environment: SSH_AUTH_SOCK: /ssh-agent |
如果你使用的是OSX和加密密钥,这将是PITA。这是我解决这个问题的步骤。
直截了当的方法有人可能认为没问题。只需安装ssh文件夹:
1 2 3 4 | ... volumes: - ~/.ssh:/root/.ssh:ro ... |
这应该是可行的,对吧?
用户问题接下来我们会注意到我们使用了错误的用户ID。好的,我们将编写一个脚本来复制和更改ssh密钥的所有者。我们还将在config中设置ssh用户,以便ssh服务器知道谁在连接。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ... volumes: - ~/.ssh:/root/.ssh-keys:ro command: sh -c ‘./.ssh-keys.sh && ...’ environment: SSH_USER: $USER ... # ssh-keys.sh 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中不起作用,因为每次我们启动一个容器时输入一个密码是不切实际的。我们可以删除一个密码短语(见下面的示例),但存在安全问题。
1 2 3 4 | openssl rsa -in id_rsa -out id_rsa2 # enter passphrase # replace passphrase-encrypted key with plaintext key: mv id_rsa2 id_rsa |
ssh代理解决方案
您可能已经注意到,在本地,您不需要在每次需要ssh访问时输入密码短语。为什么会这样?这就是ssh代理的作用。ssh代理基本上是一个服务器,它监听一个称为"ssh auth sock"的特殊文件unix socket。您可以在系统上看到它的位置:
1 2 | echo $SSH_AUTH_SOCK # /run/user/1000/keyring-AvTfL3/ssh |
ssh客户机通过这个文件与ssh代理通信,这样您只需输入一次密码。一旦它未加密,ssh代理将把它存储在内存中,并根据请求发送到ssh客户机。我们能在Docker里用吗?当然,只需挂载该特殊文件并指定相应的环境变量:
1 2 3 4 5 | environment: SSH_AUTH_SOCK: $SSH_AUTH_SOCK ... volumes: - $SSH_AUTH_SOCK:$SSH_AUTH_SOCK |
在这种情况下,我们甚至不需要复制密钥。要确认密钥可用,我们可以使用ssh add实用程序:
1 2 3 4 5 6 | if [ -z"$SSH_AUTH_SOCK" ]; then echo"No ssh agent detected" else echo $SSH_AUTH_SOCK ssh-add -l fi |
Mac Docker中的Unix套接字安装支持问题
不幸的是,对于OS X用户来说,Docker for Mac有许多缺点,其中之一就是它无法在Mac和Linux之间共享Unix套接字。在D4M Github中有一个未解决的问题。截至2019年2月,它仍在营业。
那么,这是一个死胡同吗?不,这里有一个简单的工作区。
ssh代理转发解决方案幸运的是,这个问题并不新鲜。在Docker之前很久,有一种方法可以在远程ssh会话中使用本地ssh密钥。这称为ssh代理转发。这个想法很简单:通过ssh连接到远程服务器,可以在那里使用所有相同的远程服务器,从而共享密钥。
使用Docker for Mac,我们可以使用一个智能技巧:使用tcpsh连接将ssh代理共享到Docker虚拟机,并将该文件从虚拟机装载到需要ssh连接的另一个容器。下面是演示解决方案的图片:
首先,我们通过TCP端口在Linux虚拟机的容器内创建一个到ssh服务器的ssh会话。我们在这里使用一个真正的ssh auth sock。
接下来,ssh服务器将我们的ssh密钥转发到容器上的ssh代理。ssh代理有一个unix套接字,它使用一个安装到linux vm上的位置。例如,Unix套接字在Linux中工作。Mac中不工作的Unix套接字文件不起作用。
之后,我们用ssh客户机创建有用的容器。我们共享本地ssh会话使用的Unix套接字文件。
有很多脚本可以简化这个过程:https://github.com/avsm/docker-ssh-agent-forward
结论让ssh在docker工作可能会容易些。但这是可以做到的。而且将来可能会有所改善。至少Docker开发人员知道这个问题。甚至为有构建时间秘密的dockerfiles解决了这个问题。还有一个如何支持Unix域套接字的建议。