我在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。
有没有办法做到这一点?此外,如果我的密钥受密码保护,有没有办法解锁它,所以每次注入后我都不必手动输入密码?
答案 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密钥。在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 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
不幸的是,对于OS X用户,Docker for Mac有很多缺点,其中之一就是它无法在Mac和Linux之间共享Unix套接字。有一个open issue in D4M Github。截至2019年2月,它仍然开放。
那么,这是死胡同吗?不,有一个解决方法。
幸运的是,这个问题并不新鲜。在Docker出现很久之前,就有一种在远程ssh会话中使用本地ssh密钥的方法。这称为ssh代理转发。这个想法很简单:您可以通过ssh连接到远程服务器,并且可以在那里使用所有相同的远程服务器,从而共享密钥。
使用Mac的Docker,我们可以使用一个巧妙的技巧:使用TCP ssh连接将ssh代理共享到docker虚拟机,然后将该文件从虚拟机挂载到需要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
让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)"
为安全起见,请移除中间容器。这将帮助您加油。