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

时间:2016-01-21 19:19:46

标签: ssh docker docker-compose docker-machine

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

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

docker-composer run stack ssh user@stackoverflow.com

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

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

6 个答案:

答案 0 :(得分:35)

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

volumes:
    - ~/.ssh:/root/.ssh

您也可以查看more advanced solution with ssh agent(我自己没试过)

答案 1 :(得分:20)

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

然后可以在Dockerfile中访问新的机密文件,如下所示:

RUN mkdir ~/.ssh && ln -s /run/secrets/host_ssh_key ~/.ssh/id_rsa

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

  

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

有关详细信息,请参阅:

答案 2 :(得分: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

答案 3 :(得分:4)

如果您使用的是OS X和加密密钥,则将是PITA。 Here are the steps我已经弄清楚了。

直截了当的方法

人们可能会认为这没问题。只需挂载您的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
...

# 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中这是行不通的,因为每次启动容器时都无法输入密码。 我们可以删除密码短语(请参见下面的示例),但是存在安全隐患。

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套接字。您可以在系统上看到其位置:

echo $SSH_AUTH_SOCK
# /run/user/1000/keyring-AvTfL3/ssh

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

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

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

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

SSH代理转发解决方案

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

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

SSH forwarding

首先,我们通过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

结论

让SSH在Docker中运行可能更加容易。但这是可以完成的。而且将来可能会有所改善。至少Docker开发人员知道此问题。甚至solved it for Dockerfiles with build time secrets。还有there's a suggestion如何支持Unix域套接字。

答案 4 :(得分:3)

Mac版Docker for Mac现在supports mounting the ssh agent socket

答案 5 :(得分:2)

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

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

第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"] 

在撰写文件中添加env属性:

environment:
      - SSH_PRIVATE_KEY=${SSH_PRIVATE_KEY}

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

docker-compose build --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)"

为安全起见,请移除中间容器。这将帮助您加油。