在docker容器中使用SSH密钥

好吧,所以基本上我有一个应用程序,执行Git的各种有趣的东西(如运行git克隆和git推),我试图泊坞窗。

我遇到了一个问题,虽然我需要能够添加一个SSH密钥容器的容器“用户”使用。

有没有一个好的方法来做到这一点? 我试图将其复制到/root/.ssh/中,更改$ HOME,创build一个git ssh包装器,但仍然没有运气。

这里是Dockerfile供参考:

#DOCKER-VERSION 0.3.4 from ubuntu:12.04 RUN apt-get update RUN apt-get install python-software-properties python g++ make git-core openssh-server -y RUN add-apt-repository ppa:chris-lea/node.js RUN echo "deb http://archive.ubuntu.com/ubuntu precise universe" >> /etc/apt/sources.list RUN apt-get update RUN apt-get install nodejs -y ADD . /src ADD ../../home/ubuntu/.ssh/id_rsa /root/.ssh/id_rsa RUN cd /src; npm install EXPOSE 808:808 CMD [ "node", "/src/app.js"] 

app.jsgit pull一样运行git命令

在使用Ubuntu时发现,ssh_config不正确。 你需要添加

 RUN echo " IdentityFile ~/.ssh/id_rsa" >> /etc/ssh/ssh_config 

到您的Dockerfile为了得到它识别您的ssh密钥。

注意:只有使用这种方法的图像是私人的,将永远是! 即使您在添加图层后删除了图层中的图标,ssh密钥仍保存在图像中(请参阅本文中的注释)。

在我的情况下,这是好的,所以这就是我正在使用的:

 # Setup for ssh onto github RUN mkdir -p /root/.ssh ADD id_rsa /root/.ssh/id_rsa RUN chmod 700 /root/.ssh/id_rsa RUN echo "Host github.com\n\tStrictHostKeyChecking no\n" >> /root/.ssh/config 

为了注入你的密钥,在一个容器内,你有多个解决scheme:

  1. ADD指令中使用Dockerfile,可以在构build过程中注入它

  2. 简单地做一些像cat id_rsa | docker run -i <image> sh -c 'cat > /root/.ssh/id_rsa' cat id_rsa | docker run -i <image> sh -c 'cat > /root/.ssh/id_rsa'

  3. 使用docker cp命令,允许您在容器运行时注入文件。

如果您需要在构build时使用SSH,则是一个难题。 例如,如果你正在使用git clone ,或者在我的情况下使用pipnpm从私有存储库下载。

我find的解决scheme是使用--build-arg标志添加您的密钥。 然后,您可以使用新的实验--squash命令(添加1.13)来合并图层,以便在删除之后,这些密钥不再可用。 这是我的解决scheme:

构build命令

 $ docker build -t example --build-arg ssh_prv_key="$(cat ~/.ssh/id_rsa)" --build-arg ssh_pub_key="$(cat ~/.ssh/id_rsa.pub)" --squash . 

Dockerfile

 FROM python:3.6-slim ARG ssh_prv_key ARG ssh_pub_key RUN apt-get update && \ apt-get install -y \ git \ openssh-server \ libmysqlclient-dev # Authorize SSH Host RUN mkdir -p /root/.ssh && \ chmod 0700 /root/.ssh && \ ssh-keyscan github.com > /root/.ssh/known_hosts # Add the keys and set permissions RUN echo "$ssh_prv_key" > /root/.ssh/id_rsa && \ echo "$ssh_pub_key" > /root/.ssh/id_rsa.pub && \ chmod 600 /root/.ssh/id_rsa && \ chmod 600 /root/.ssh/id_rsa.pub # Avoid cache purge by adding requirements first ADD ./requirements.txt /app/requirements.txt WORKDIR /app/ RUN pip install -r requirements.txt # Remove SSH keys RUN rm -rf /root/.ssh/ # Add the rest of the files ADD . . CMD python manage.py runserver 

更新:如果您使用的是Docker 1.13,并且具有实验性function,则可以追加--squash到将合并图层的build命令,删除SSH密钥并将其从docker history隐藏起来。

如果您使用docker撰写一个简单的select是转发SSH代理那样:

 something: container_name: something volumes: - $SSH_AUTH_SOCK:/ssh-agent # Forward local machine SSH key to docker environment: SSH_AUTH_SOCK: /ssh-agent 

这条线是一个问题:

 ADD ../../home/ubuntu/.ssh/id_rsa /root/.ssh/id_rsa 

指定要复制到映像中的文件时,只能使用相对path – 相对于Dockerfile所在的目录。 所以你应该使用:

 ADD id_rsa /root/.ssh/id_rsa 

把id_rsa文件放到Dockerfile所在的目录下。

看看更多的细节: http : //docs.docker.io/reference/builder/#add

Docker容器应该被看作是自己的“服务”。 为了分离担忧,你应该分开function:

1)数据应该在一个数据容器中:使用一个链接的卷克隆回购。 那个数据容器可以被链接到需要它的服务。

2)使用一个容器来运行git克隆任务(即只有作业是克隆),当你运行它时,将数据容器连接到它。

3)对于ssh-key也是一样的:把它放在一个卷上(如上面所build议的那样),并在你需要的时候把它连接到git clone服务

这样,克隆任务和密钥都是短暂的,只有在需要的时候才会激活。

现在,如果您的应用程序本身是一个git界面,您可能需要直接考虑github或bitbucket REST API来完成您的工作:这就是他们的devise。

这个问题真的是一个令人讨厌的问题。 因为你不能在dockerfile上下文中添加/复制任何文件,这意味着不可能将〜/ .ssh / id_rsa链接到image的/root/.ssh/id_rsa,并且当你确实需要一个键来做一些事情时像git克隆从一个私人回购链接,在您的docker图像的build设期间。

无论如何,我find了一个解决方法,不是说服,但为我工作。

  1. 在你的dockerfile中:

    • 将此文件添加为/root/.ssh/id_rsa
    • 做你想做的,比如git clone,composer …
    • rm /root/.ssh/id_rsa结尾
  2. 一个脚本做一个拍摄:

    • 把你的密钥保存到dockerfile文件夹中
    • dockerbuild设
    • rm复制的密钥
  3. 任何时候你必须从这个映像运行一个容器与一些SSH要求,只需添加-v为运行命令,如:

    docker run -v〜/ .ssh / id_rsa:/root/.ssh/id_rsa –name container image command

这个解决scheme不会导致项目源和构build的docker映像都没有私钥,所以不用再担心安全问题了。

'你可以select让远程服务器访问你的本地ssh-agent,就好像它在服务器上运行一样'

https://developer.github.com/guides/using-ssh-agent-forwarding/

你也可以链接你的.ssh目录在主机和容器之间,我不知道这个方法是否有任何的安全隐患,但它可能是最简单的方法。 像这样的东西应该工作:

 $ sudo docker run -it -v /root/.ssh:/root/.ssh someimage bash 

请记住,docker运行与sudo(除非你不),如果是这样的话,你会使用根ssh密钥。

在Docker编译时间执行npm install时,我们遇到了类似的问题。

从Daniel van Flymen的解决scheme中得到启发,并将其与git url重写相结合,我们发现了一个简单的方法来从私有github 仓库validationnpm install – 我们使用了oauth2标记而不是密钥。

在我们的例子中,npm依赖被指定为“git + https://github.com/ …”

要在容器中进行身份validation,需要将URL重写为适合ssh身份validation(ssh://git@github.com/)或令牌身份validation(https:// $ {GITHUB_TOKEN} @ github.com /)

构build命令:

 docker build -t sometag --build-arg GITHUB_TOKEN=$GITHUB_TOKEN . 

不幸的是,我在docker1.9,所以–squash选项还没有,最终需要添加

Dockerfile:

 FROM node:5.10.0 ARG GITHUB_TOKEN #Install dependencies COPY package.json ./ # add rewrite rule to authenticate github user RUN git config --global url."https://${GITHUB_TOKEN}@github.com/".insteadOf "https://github.com/" RUN npm install # remove the secret token from the git config file, remember to use --squash option for docker build, when it becomes available in docker 1.13 RUN git config --global --unset url."https://${GITHUB_TOKEN}@github.com/".insteadOf # Expose the ports that the app uses EXPOSE 8000 #Copy server and client code COPY server /server COPY clients /clients 

我试图以另一种方式解决问题:将公共ssh密钥添加到图像。 但在我的试验中,我发现“docker cp”是用于从容器复制到主机。 项目3在吱吱响应似乎是说你可以使用docker cp将文件注入容器。 请参阅https://docs.docker.com/engine/reference/commandline/cp/

摘抄

将文件/文件夹从容器的文件系统复制到主机path。 path是相对于文件系统的根。

  Usage: docker cp CONTAINER:PATH HOSTPATH Copy files/folders from the PATH to the HOSTPATH 

我今天遇到了同样的问题,稍微修改了以前的post,我发现这种方法对我更有用

 docker run -it -v ~/.ssh/id_rsa:/root/.my-key:ro image /bin/bash 

(请注意,只读标志所以容器不会混乱我的ssh密钥在任何情况下)。

容器内我现在可以运行:

 ssh-agent bash -c "ssh-add ~/.my-key; git clone <gitrepourl> <target>" 

所以我没有得到Bad owner or permissions on /root/.ssh/..错误,这是由@kross指出的

您可以使用共享文件夹将授权密钥传递到您的容器,并使用像这样的docker文件设置权限:

 FROM ubuntu:16.04 RUN apt-get install -y openssh-server RUN mkdir /var/run/sshd EXPOSE 22 RUN cp /root/auth/id_rsa.pub /root/.ssh/authorized_keys RUN rm -f /root/auth RUN chmod 700 /root/.ssh RUN chmod 400 /root/.ssh/authorized_keys RUN chown root. /root/.ssh/authorized_keys CMD /usr/sbin/sshd -D 

你的docker运行包含如下的东西,以共享主机上的auth目录(持有authorised_keys)与容器,然后打开SSH端口,这将通过主机上的端口7001访问。

 -d -v /home/thatsme/dockerfiles/auth:/root/auth -–publish=127.0.0.1:7001:22 

您可能想要查看https://github.com/jpetazzo/nsenter ,这似乎是在容器上打开一个shell并在容器中执行命令的另一种方法。

将sshauthentication套接字转发到容器:

 docker run --rm -ti \ -v $SSH_AUTH_SOCK:/tmp/ssh_auth.sock \ -e SSH_AUTH_SOCK=/tmp/ssh_auth.sock \ -w /src \ my_image 

你的脚本将能够执行一个git clone

额外:如果你想要克隆的文件属于一个特定的用户,你需要使用chown因为在容器内使用除root之外的其他用户将会使git失败。

你可以做这个发布到容器的环境一些额外的variables:

 docker run ... -e OWNER_USER=$(id -u) \ -e OWNER_GROUP=$(id -g) \ ... 

克隆之后,必须在离开容器之前执行chown $OWNER_USER:$OWNER_GROUP -R <source_folder>设置正确的所有权,以便容器外部的非root用户可以访问这些文件。

最简单的方法,获取一个启动板帐户,并使用: ssh-import-id

一个解决scheme是使用以下选项将主机的ssh密钥安装到docker中:

 docker run -v /home/<host user>/.ssh:/home/<docker user>/.ssh <image> 

类似于上述解决scheme。 但与非root用户一起工作。 与github完美合作。

如果你不关心你的SSH密钥的安全性,这里有很多好的答案。 如果你这样做,我发现最好的答案是从上面评论的链接到diegocsandrim的 这个GitHub评论 。 所以其他人更有可能看到它,以防止回购永远消失,这是一个编辑版本的答案:

这里的大多数解决scheme最终将私钥留在图像中。 这是不好的,因为任何有权访问该映像的人都可以访问您的私钥。 由于我们对squash的行为不够了解,所以即使删除了密钥并挤压了这一层,情况仍然如此。

我们使用aws s3 cli生成一个pre-sign URL来访问密钥,并限制访问大约5分钟,我们将这个pre-sign URL保存到repo目录下的一个文件中,然后在dockerfile中将它添加到图像中。

在dockerfile中,我们有一个执行所有这些步骤的RUN命令:使用pre-sing URL获取ssh密钥,运行npm install,并删除ssh密钥。

通过在一个命令中执行此操作,ssh密钥不会被存储在任何图层中,但是预注册URL将被存储,并且这不是问题,因为该URL在5分钟后将无效。

构build脚本如下所示:

 # build.sh aws s3 presign s3://my_bucket/my_key --expires-in 300 > ./pre_sign_url docker build -t my-service . 

Dockerfile看起来像这样:

 FROM node COPY . . RUN eval "$(ssh-agent -s)" && \ wget -i ./pre_sign_url -q -O - > ./my_key && \ chmod 700 ./my_key && \ ssh-add ./my_key && \ ssh -o StrictHostKeyChecking=no git@github.com || true && \ npm install --production && \ rm ./my_key && \ rm -rf ~/.ssh/* ENTRYPOINT ["npm", "run"] CMD ["start"] 

在正在运行的docker容器中,可以使用docker -i(交互)选项发出ssh-keygen。 这将转发容器提示在docker容器内创build密钥。