使用Docker Compose将主机的SSH密钥注入Docker Machine

Rus*_*lan 23 ssh docker docker-compose docker-machine

我在Mac OS X上使用Docker与Docker Machine(使用默认的boot2docker机器),我使用docker-compose来设置我的开发环境.

假设其中一个容器名为" stack".现在我想做的是打电话:

docker-composer run stack ssh user@stackoverflow.com
Run Code Online (Sandbox Code Playgroud)

我的公钥(已添加到stackoverflow.com用于验证我的公钥)位于主机上.我希望这个密钥可以在Docker Machine容器中使用,这样我就能够stackoverflow在容器内使用该密钥进行身份验证.最好不要将我的密钥物理复制到Docker Machine.

有没有办法做到这一点?此外,如果我的密钥受密码保护,有没有办法解锁它一次,所以每次注入后我不必手动输入密码?

小智 37

您可以将它添加到docker-compose.yml(假设您的用户在容器内是root):

volumes:
    - ~/.ssh:/root/.ssh
Run Code Online (Sandbox Code Playgroud)

您还可以使用ssh代理检查更高级的解决方案(我自己没试过)

  • 请注意,如果您的SSH密钥属于主机上的用户,则此解决方案可能会失败 (13认同)
  • 虽然您可以在运行时执行此操作,但您将无法在构建时访问卷. (10认同)
  • 也不适用于 Windows。`'/root/.ssh/id_rsa' 的权限 0755 太开放了。` (3认同)
  • 您可以在此代码段的末尾添加 `:ro` 以只读方式挂载密钥,这通常会绕过 SSH 关于权限的警告,但是如果您的密钥有密码(它真的应该),您仍然需要做一些技巧使用 ssh 代理。 (2认同)

Ant*_*gun 22

Docker有一个名为secrets的功能,在这里可以提供帮助.要使用它,可以将以下代码添加到docker-compose.yml:

---
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
Run Code Online (Sandbox Code Playgroud)

然后可以Dockerfile像这样访问新的秘密文件:

RUN mkdir ~/.ssh && ln -s /run/secrets/host_ssh_key ~/.ssh/id_rsa
Run Code Online (Sandbox Code Playgroud)

秘密文件不会被复制到容器中:

当您授予新创建或正在运行的服务访问权限时,解密的机密将装入内存文件系统的容器中

有关详细信息,请参阅:

  • 请注意,秘密是“群体模式功能”,如 https://github.com/docker/compose/issues/4994 和 /sf/ask/3496887971/ 中指出的-when-using-docker-compose 。它不会在 docker-compose up 中安装秘密。 (2认同)

Van*_*uan 9

如果您使用的是OS X和加密密钥,则将是PITA。这是我解决此问题的步骤

直截了当的方法

有人可能会认为这没有问题。只需挂载ssh文件夹:

...
volumes:
  - ~/.ssh:/root/.ssh:ro
...
Run Code Online (Sandbox Code Playgroud)

这应该可行,对吗?

用户问题

接下来,我们会注意到我们使用了错误的用户ID。很好,我们将编写一个脚本来复制和更改ssh密钥的所有者。我们还将在配置中设置ssh用户,以便ssh服务器知道谁在连接。

...
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
Run Code Online (Sandbox Code Playgroud)

SSH密钥密码问题

在我们公司中,我们使用密码保护SSH密钥。在docker中这是行不通的,因为每次启动容器时都无法输入密码。我们可以删除密码短语(请参见下面的示例),但是存在安全隐患。

openssl rsa -in id_rsa -out id_rsa2
# enter passphrase
# replace passphrase-encrypted key with plaintext key:
mv id_rsa2 id_rsa
Run Code Online (Sandbox Code Playgroud)

SSH代理解决方案

您可能已经注意到,在本地不需要每次ssh访问都需要输入密码。这是为什么?这就是SSH代理的用途。SSH代理基本上是一个服务器,它侦听称为ssh auth sock的特殊文件unix套接字。您可以在系统上看到其位置:

echo $SSH_AUTH_SOCK
# /run/user/1000/keyring-AvTfL3/ssh
Run Code Online (Sandbox Code Playgroud)

SSH客户端通过此文件与SSH代理进行通信,因此您只需输入一次密码即可。解密后,SSH代理会将其存储在内存中,并根据请求发送到SSH客户端。我们可以在Docker中使用它吗?当然,只需挂载该特殊文件并指定相应的环境变量即可:

environment:
  SSH_AUTH_SOCK: $SSH_AUTH_SOCK
  ...
volumes:
  - $SSH_AUTH_SOCK:$SSH_AUTH_SOCK
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我们甚至不需要复制密钥。为了确认密钥是否可用,我们可以使用ssh-add实用程序:

if [ -z "$SSH_AUTH_SOCK" ]; then
  echo "No ssh agent detected"
else
  echo $SSH_AUTH_SOCK
  ssh-add -l
fi
Run Code Online (Sandbox Code Playgroud)

Mac版Docker中的unix套接字安装支持问题

不幸的是,对于OS X用户,Docker for Mac有许多缺点,其中之一就是它无法在Mac和Linux之间共享Unix套接字。D4M Github中存在一个未解决的问题。截至2019年2月,它仍然开放。

那么,这是死胡同吗?不,有一个解决方法。

SSH代理转发解决方案

幸运的是,这个问题并不新鲜。在Docker出现很久之前,就有一种在远程ssh会话中使用本地ssh密钥的方法。这称为ssh代理转发。这个想法很简单:您可以通过ssh连接到远程服务器,并且可以在那里使用所有相同的远程服务器,从而共享密钥。

使用Mac的Docker,我们可以使用一个聪明的技巧:使用TCP ssh连接将ssh代理共享到docker虚拟机,然后将该文件从虚拟机挂载到需要SSH连接的另一个容器中。这是用于说明解决方案的图片:

SSH转发

首先,我们通过TCP端口在Linux VM中的容器内创建到ssh服务器的ssh会话。我们在这里使用真正的ssh auth袜子。

接下来,ssh服务器将我们的ssh密钥转发到该容器上的ssh代理。SSH代理具有Unix套接字,该套接字使用安装到Linux VM的位置。即Unix套接字可在Linux中使用。Mac中无法正常工作的Unix套接字文件无效。

之后,我们使用SSH客户端创建有用的容器。我们共享本地SSH会话使用的Unix套接字文件。

有很多脚本可以简化该过程:https : //github.com/avsm/docker-ssh-agent-forward

结论

在Docker中使用SSH可能更容易。但这是可以完成的。并且将来可能会得到改进。至少Docker开发人员知道此问题。甚至为带有构建时间秘密的Dockerfile解决了该问题。而且有一个建议,如何支持Unix域套接字。


Ais*_*tis 5

您可以转发SSH代理:

something:
    container_name: something
    volumes:
        - $SSH_AUTH_SOCK:/ssh-agent # Forward local machine SSH key to docker
    environment:
        SSH_AUTH_SOCK: /ssh-agent
Run Code Online (Sandbox Code Playgroud)

  • 您已经在这里给出了答案http://stackoverflow.com/a/36648428/228370还有一个注意事项:这不适用于Mac,如@ joe-saw所指出的那样,因为没有代理Unix域套接字 (3认同)

Dev*_*esh 5

您可以使用多阶段构建来构建容器这是您可以采取的方法:-

Stage 1 building an image with ssh

FROM ubuntu as sshImage
LABEL stage=sshImage
ARG SSH_PRIVATE_KEY
WORKDIR /root/temp

RUN apt-get update && \
    apt-get install -y git npm 

RUN mkdir /root/.ssh/ &&\
    echo "${SSH_PRIVATE_KEY}" > /root/.ssh/id_rsa &&\
    chmod 600 /root/.ssh/id_rsa &&\
    touch /root/.ssh/known_hosts &&\
    ssh-keyscan github.com >> /root/.ssh/known_hosts

COPY package*.json ./

RUN npm install

RUN cp -R node_modules prod_node_modules
Run Code Online (Sandbox Code Playgroud)

第 2 阶段:构建容器

FROM node:10-alpine

RUN mkdir -p /usr/app

WORKDIR /usr/app

COPY ./ ./

COPY --from=sshImage /root/temp/prod_node_modules ./node_modules

EXPOSE 3006

CMD ["npm", "run", "dev"] 
Run Code Online (Sandbox Code Playgroud)

在您的 compose 文件中添加 env 属性:

environment:
      - SSH_PRIVATE_KEY=${SSH_PRIVATE_KEY}
Run Code Online (Sandbox Code Playgroud)

然后从构建脚本传递参数,如下所示:

docker-compose build --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)"
Run Code Online (Sandbox Code Playgroud)

并移除中间容器以确保安全。这会帮助你欢呼。

  • 请注意,尽管密钥现在存储在图像中,即使您使用多级,密钥仍然存在于其中一层中。潜在的安全风险。 (3认同)