在docker容器内使用SSH密钥

我有一个应用程序,执行各种有趣的东西与Git(像运行Git克隆&git push),我正在尝试docker-ize它。

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

我试着把它复制到/root/.ssh/,改变$HOME,创建一个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.js运行类似git pull的git命令

474560 次浏览

为了在容器中注入ssh密钥,你有多种解决方案:

  1. 使用带有ADD指令的Dockerfile,你可以在构建过程中注入它

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

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

在使用Ubuntu时,ssh_config是不正确的。你需要加上

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

来让Dockerfile识别你的ssh密钥。

最简单的方法,获得一个发射台帐户并使用:ssh-import-id

我试图用另一种方式解决这个问题:向映像添加公共ssh密钥。但在我的试验中,我发现“docker cp”是用于从容器复制到主机的。creak回答的第3项似乎在说你可以使用docker cp向容器中注入文件。看到https://docs.docker.com/engine/reference/commandline/cp/

摘录

从容器的文件系统复制文件/文件夹到主机路径。 路径相对于文件系统的根目录

  Usage: docker cp CONTAINER:PATH HOSTPATH


Copy files/folders from the PATH to the HOSTPATH

“你可以选择性地让远程服务器访问你的本地ssh-agent,就像它在服务器上运行一样”

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

这一行是个问题:

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

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

ADD id_rsa /root/.ssh/id_rsa

将id_rsa文件放到Dockerfile所在的目录中。

查看更多详细信息:http://docs.docker.io/reference/builder/#add

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

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

记住docker使用sudo运行(除非你不这样做),如果是这种情况,你将使用根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

在一个运行的docker容器中,你可以使用docker -i (interactive)选项发出ssh-keygen。这将转发容器提示,在docker容器中创建密钥。

这个问题真的很烦人。由于您不能在dockerfile上下文中添加/复制任何文件,这意味着不可能只链接~/。Ssh /id_rsa到镜像的/root/目录下。Ssh /id_rsa,当你确实需要一个密钥来做一些事情,比如从一个私有的repo链接克隆git…,在构建docker映像期间。

不管怎样,我找到了一个变通的办法,不那么有说服力,但对我来说确实有效。

  1. 在你的dockerfile:

    • 将此文件添加为/root/.ssh/id_rsa
    • 做你想做的,比如git克隆,作曲家…
    • rm /root/.Ssh /id_rsa
    • 李< / ul > < / >
    • 一个脚本做一个拍摄:

      • Cp你的密钥文件夹持有dockerfile
      • 码头工人建造
      • Rm复制的密钥
      • 李< / ul > < / >
      • 任何时候你需要从这个镜像运行一个有SSH要求的容器,只要为运行命令添加-v,比如:

        Docker运行-v ~/.ssh/id_rsa:/root/。Ssh /id_rsa——name容器镜像命令

        . sh

这个解决方案在项目源代码和构建的docker映像中都没有私钥,因此不再需要担心安全问题。

Docker容器应该被视为它们自己的“服务”。为了分离关注点,你应该分离功能:

1)数据应该在数据容器中:使用链接卷将repo克隆到。然后可以将该数据容器链接到需要它的服务。

2)使用一个容器来运行git克隆任务(即它唯一的任务是克隆),当你运行它时将数据容器链接到它。

3) ssh-key也一样:把它作为一个卷(如上所述),当你需要它时链接到git克隆服务

这样,克隆任务和密钥都是临时的,只在需要时才活动。

现在,如果你的应用程序本身是一个git接口,你可能会考虑直接使用github或bitbucket REST api来完成你的工作:这就是它们的设计目的。

如果你正在使用码头工人组成,一个简单的选择是像这样转发SSH代理:

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

或等价地,如果使用docker run:

$ docker run --mount type=bind,source=$SSH_AUTH_SOCK,target=/ssh-agent \
--env SSH_AUTH_SOCK=/ssh-agent \
some-image

我今天遇到了同样的问题,对之前的帖子做了一点修改,我发现这种方法对我更有用

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

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

在容器内,我现在可以运行:

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

所以我没有得到@kross注意到的Bad owner or permissions on /root/.ssh/..错误

如果您需要在构建时使用SSH,那么这个问题就更难解决了。例如,如果你使用git clone,或者在我的情况下pipnpm从私有存储库下载。

我发现的解决方案是使用--build-arg标志添加你的键。然后你可以使用新的实验--squash命令(添加1.13)来合并层,这样键删除后就不再可用了。以下是我的解决方案:

建造的命令

$ 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并且有实验特性,你可以将--squash附加到构建命令中,该命令将合并层,删除SSH密钥并对docker history隐藏它们。

你可以通过共享文件夹将授权密钥传递到你的容器中,并使用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运行包含如下内容,与容器共享主机上的认证目录(持有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并在容器中执行命令的另一种方式。

我们在docker构建时进行npm安装时也遇到了类似的问题。

丹尼尔·范·弗莱曼的解决方案中受到启发,并将其与Git url重写结合起来,我们发现了一个更简单的方法来验证从私有github回购的npm安装-我们使用oauth2令牌而不是密钥。

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

对于容器中的身份验证,url需要重写以适合ssh身份验证(ssh://git@github.com/)或令牌身份验证(https://${GITHUB_TOKEN}@github.com/)

构建命令:

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

不幸的是,我在docker 1.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 run -v /home/<host user>/.ssh:/home/<docker user>/.ssh <image>

与代理转发类似,这种方法将使容器可以访问公钥。另外一个好处是,它也适用于非根用户,并将使您连接到GitHub。然而,需要注意的是,.ssh文件夹中的所有内容(包括私钥)都将被共享,因此这种方法仅适用于开发,且仅适用于可信容器映像。

将ssh认证套接字转发给容器:

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,因为在容器内使用其他用户而不是根用户会导致git失败。

你可以将一些额外的变量发布到容器的环境中:

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

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

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

这里的大多数解决方案最终都将私钥保留在映像中。这很糟糕,因为任何访问映像的人都可以访问您的私钥。由于我们对squash的行为了解不够,即使你删除了键并压缩了该层,情况仍然可能是这样。

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

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

通过在单个命令中执行此操作,ssh密钥将不会存储在任何层中,但将存储预签名URL,这不是问题,因为URL将在5分钟后失效。

构建脚本看起来像:

# 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 run -v ~/.ssh:/mnt -it my_image /bin/bash -c "ln -s /mnt /root/.ssh; ssh user@10.20.30.40"

我不赞成使用Dockerfile来安装密钥,因为容器的迭代可能会留下私有密钥。

在docker(17.05)的后续版本中,您可以使用多阶段构建。哪个是最安全的选择,因为之前的构建只能被后续的构建使用,然后被销毁

更多信息请参见我的stackoverflow问题的答案

扩展彼得·格兰杰的回答,我可以使用自Docker 17.05以来可用的多级构建。官方页面说明:

对于多阶段构建,你在Dockerfile中使用多个FROM语句。每条FROM指令可以使用不同的基,并且每条指令都开始构建的一个新阶段。您可以有选择地将工件从一个阶段复制到另一个阶段,在最终图像中留下您不想要的所有东西。

记住这一点,这里是我的Dockerfile的例子,包括三个构建阶段。它的目的是创建客户端web应用程序的生产映像。

# Stage 1: get sources from npm and git over ssh
FROM node:carbon AS sources
ARG SSH_KEY
ARG SSH_KEY_PASSPHRASE
RUN mkdir -p /root/.ssh && \
chmod 0700 /root/.ssh && \
ssh-keyscan bitbucket.org > /root/.ssh/known_hosts && \
echo "${SSH_KEY}" > /root/.ssh/id_rsa && \
chmod 600 /root/.ssh/id_rsa
WORKDIR /app/
COPY package*.json yarn.lock /app/
RUN eval `ssh-agent -s` && \
printf "${SSH_KEY_PASSPHRASE}\n" | ssh-add $HOME/.ssh/id_rsa && \
yarn --pure-lockfile --mutex file --network-concurrency 1 && \
rm -rf /root/.ssh/


# Stage 2: build minified production code
FROM node:carbon AS production
WORKDIR /app/
COPY --from=sources /app/ /app/
COPY . /app/
RUN yarn build:prod


# Stage 3: include only built production files and host them with Node Express server
FROM node:carbon
WORKDIR /app/
RUN yarn add express
COPY --from=production /app/dist/ /app/dist/
COPY server.js /app/
EXPOSE 33330
CMD ["node", "server.js"]

.dockerignore重复.gitignore文件的内容(它防止项目的node_modules和由此产生的dist目录被复制):

.idea
dist
node_modules
*.log

创建镜像的命令示例:

$ docker build -t ezze/geoport:0.6.0 \
--build-arg SSH_KEY="$(cat ~/.ssh/id_rsa)" \
--build-arg SSH_KEY_PASSPHRASE="my_super_secret" \
./

如果您的私有SSH密钥没有密码短语,只需指定空SSH_KEY_PASSPHRASE参数。

它是这样工作的:

1).在第一阶段,只有package.jsonyarn.lock文件和SSH私钥被复制到名为sources的第一个中间映像。为了避免进一步的SSH密钥口令提示,它被自动添加到ssh-agent。最后,yarn命令从NPM安装所有必需的依赖项,并通过SSH从Bitbucket克隆私有git存储库。

2).第二阶段构建并缩小web应用程序的源代码,并将其放置在下一个名为production的中间映像的dist目录中。注意,安装的node_modules的源代码是从第一阶段生成的名为sources的映像中复制的:

COPY --from=sources /app/ /app/

也可能是下面这句话:

COPY --from=sources /app/node_modules/ /app/node_modules/

我们只有来自第一个中间图像的node_modules目录,不再有SSH_KEYSSH_KEY_PASSPHRASE参数。构建所需的所有其余内容都是从项目目录中复制的。

3).在第三阶段,我们缩小最终图像的大小,标记为ezze/geoport:0.6.0,只包括名为production的第二张中间图像的dist目录,并安装Node Express以启动web服务器。

列出图像给出如下输出:

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ezze/geoport        0.6.0               8e8809c4e996        3 hours ago         717MB
<none>              <none>              1f6518644324        3 hours ago         1.1GB
<none>              <none>              fa00f1182917        4 hours ago         1.63GB
node                carbon              b87c2ad8344d        4 weeks ago         676MB

其中非标记图像对应于第一和第二个中间构建阶段。

如果你跑了

$ docker history ezze/geoport:0.6.0 --no-trunc

你将不会在最终的图像中看到任何SSH_KEYSSH_KEY_PASSPHRASE的提及。

一个简单而安全的方法来实现这一点,而不需要将密钥保存在Docker镜像层中,或通过ssh_agent体操:

  1. 作为Dockerfile中的一个步骤,创建一个.ssh目录,添加:

    RUN mkdir -p /root/.ssh < / p >

  2. 以下表示您想要将ssh目录挂载为卷:

    VOLUME [ "/root/.ssh" ] < / p >

  3. 通过添加这一行来确保容器的ssh_config知道在哪里找到公钥:

    RUN echo " IdentityFile /root/.ssh/id_rsa" >> /etc/ssh/ssh_config < / p >

  4. 在运行时将本地用户的.ssh目录暴露给容器:

    docker run -v ~/.ssh:/root/.ssh -it image_name

    或者在dockerCompose.yml中,在服务的音量键下添加这个:

    - "~/.ssh:/root/.ssh" < / p >

最终的Dockerfile应该包含如下内容:

FROM node:6.9.1


RUN mkdir -p /root/.ssh
RUN  echo "    IdentityFile /root/.ssh/id_rsa" >> /etc/ssh/ssh_config


VOLUME [ "/root/.ssh" ]


EXPOSE 3000


CMD [ "launch" ]
您可以使用secrets来管理容器中的任何敏感数据 在运行时需要,但您不想存储在映像或源代码中 控制,例如:

  • 用户名及密码
  • TLS证书和密钥
  • SSH密钥
  • 其他重要数据,如数据库或内部服务器的名称
  • 通用字符串或二进制内容(大小不超过500kb)

https://docs.docker.com/engine/swarm/secrets/

我试图弄清楚如何将签名密钥添加到容器中,以便在运行时(而不是构建)使用,然后遇到了这个问题。Docker secrets似乎是我用例的解决方案,由于还没有人提到它,我将添加它。

正如eczajk已经在Daniel van Flymen的回答中评论的那样,删除键并使用--squash似乎不安全,因为它们仍然会在历史记录中可见(docker history --no-trunc)。

在Docker 18.09中,你可以使用“构建秘密”特性。在我的情况下,我克隆了一个私人git回购使用我的主机SSH密钥与以下在我的Dockerfile:

# syntax=docker/dockerfile:experimental


[...]


RUN --mount=type=ssh git clone [...]


[...]

为了能够使用它,你需要在运行docker build之前启用新的BuildKit后端:

export DOCKER_BUILDKIT=1

你需要将--ssh default参数添加到docker build中。

有关此的更多信息:https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066

对于debian / root / authorized_keys:

RUN set -x && apt-get install -y openssh-server


RUN mkdir /var/run/sshd
RUN mkdir -p /root/.ssh
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN  echo "ssh-rsa AAAA....yP3w== rsa-key-project01" >> /root/.ssh/authorized_keys
RUN chmod -R go= /root/.ssh

详细的在这里是Docker容器中SSH所面临挑战的一个简明概述。要从容器内连接到可信的远程而不泄漏机密,有以下几种方法:

除此之外,在使用Compose时,还可以使用在运行时可访问的独立docker容器中运行的密钥存储。这里的缺点是由于创建和管理诸如由HashiCorp制作这样的密钥存储库所需的机制而增加了复杂性。

对于在独立的Docker容器中使用SSH密钥,请参阅上面链接的方法,并根据您的具体需求考虑每种方法的缺点。然而,如果你在Compose中运行,并且想要在运行时共享一个应用程序的密钥(反映OP的实用性)试试这个:

  • 创建一个docker-compose.env文件并将其添加到你的.gitignore文件中。
  • 更新你的docker-compose.yml并为需要密钥的服务添加env_file
  • 在应用程序运行时从环境中访问公钥,例如在Node.js应用程序中是process.node.DEPLOYER_RSA_PUBKEY

上述方法非常适合开发和测试,虽然它可以满足生产需求,但在生产中,您最好使用上述其他方法之一。

额外的资源:

docker API 1.39+(使用docker version检查API版本)开始,docker build允许使用带有代理套接字或密钥的--ssh选项,以允许docker引擎转发SSH代理连接。

建造的命令

export DOCKER_BUILDKIT=1
docker build --ssh default=~/.ssh/id_rsa .

Dockerfile

# syntax=docker/dockerfile:experimental
FROM python:3.7


# Install ssh client (if required)
RUN apt-get update -qq
RUN apt-get install openssh-client -y


# Download public key for github.com
RUN --mount=type=ssh mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts


# Clone private repository
RUN --mount=type=ssh git clone git@github.com:myorg/myproject.git myproject

更多信息:

在我的情况下,我有一个问题与nodejs和'npm I '从一个远程存储库。我修复了添加'node'用户到nodejs容器和700到~/。容器中的SSH。

Dockerfile:

USER node #added the part
COPY run.sh /usr/local/bin/
CMD ["run.sh"]

run.sh:

#!/bin/bash
chmod 700 -R ~/.ssh/; #added the part

docker-compose.yml:

nodejs:
build: ./nodejs/10/
container_name: nodejs
restart: always
ports:
- "3000:3000"
volumes:
- ../www/:/var/www/html/:delegated
- ./ssh:/home/node/.ssh #added the part
links:
- mailhog
networks:
- work-network

在那之后,它开始工作

你可以使用多级构建来构建容器 这是你可以采取的方法:-

阶段1使用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)"

为了安全起见,删除中间容器。

我整理了一个非常简单的解决方案,适用于我使用“builder”的用例。Docker映像来构建单独部署的可执行文件。换句话说,我的“建造者”;Image永远不会离开我的本地机器,只需要在构建阶段访问私有回购/依赖。

对于这个解决方案,您不需要更改Dockerfile。

当你运行你的容器时,挂载你的~/.ssh目录(这避免了必须将键直接烘焙到映像中,而是确保它们在构建阶段只对单个容器实例短时间可用)。在我的例子中,我有几个构建脚本来自动化我的部署。

build-and-package.sh脚本中,我像这样运行容器:

# do some script stuff before


...


docker run --rm \
-v ~/.ssh:/root/.ssh \
-v "$workspace":/workspace \
-w /workspace builder \
bash -cl "./scripts/build-init.sh $executable"


...


# do some script stuff after (i.e. pull the built executable out of the workspace, etc.)


build-init.sh脚本看起来像这样:

#!/bin/bash


set -eu


executable=$1


# start the ssh agent
eval $(ssh-agent) > /dev/null


# add the ssh key (ssh key should not have a passphrase)
ssh-add /root/.ssh/id_rsa


# execute the build command
swift build --product $executable -c release

因此,我们不直接在docker run命令中执行swift build命令(或任何与您的环境相关的构建命令),而是执行build-init.sh脚本,该脚本启动ssh-agent,然后将ssh密钥添加到代理,最后执行swift build命令。

注1:为了让这个工作,你需要确保你的ssh密钥没有密码短语,否则ssh-add /root/.ssh/id_rsa行将要求一个密码短语并中断构建脚本。

注意2:确保在脚本文件上设置了适当的文件权限,以便它们可以运行。

希望这为具有类似用例的其他人提供了一个简单的解决方案。

这是现在可用的18.09版!

根据文档:

docker构建有一个——ssh选项,允许docker引擎

.转发SSH代理连接

下面是Dockerfile在容器中使用SSH的例子:

# syntax=docker/dockerfile:experimental
FROM alpine


# Install ssh client and git
RUN apk add --no-cache openssh-client git


# Download public key for github.com
RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts


# Clone private repository
RUN --mount=type=ssh git clone git@github.com:myorg/myproject.git myproject

一旦Dockerfile被创建,使用--ssh选项来连接SSH代理:

$ docker build --ssh default .

另外,看看https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066

一开始,有些元噪声

这里有两个高度好评的答案是危险的错误建议

我评论道,但由于我为此损失了很多天,请注意:

不要将私钥回显到文件中(意思是:echo "$ssh_prv_key" > /root/.ssh/id_ed25519)。这将破坏所需的行格式,至少在我的例子中是这样。

使用COPYADD代替。详见Docker加载密钥“/root/”。Ssh /id_rsa ":无效格式

另一名用户也证实了这一点:

I get Error loading key "/root/.ssh/id_ed25519":无效格式。回声将 为我删除换行符/双引号。这仅仅适用于ubuntu吗 或者对于alpine:3.10.3有什么不同?< / p >


1. 一种将私钥保存在映像中的工作方式(不太好!)

如果私钥存储在映像中,则需要注意从git网站上删除公钥,或者不发布映像。如果你处理好了,就安全了。请看下面(2.)的更好的方法,你也可以“忘记注意”。

Dockerfile如下所示:

FROM ubuntu:latest
RUN apt-get update && apt-get install -y git
RUN mkdir -p /root/.ssh && chmod 700 /root/.ssh
COPY /.ssh/id_ed25519 /root/.ssh/id_ed25519
RUN chmod 600 /root/.ssh/id_ed25519 && \
apt-get -yqq install openssh-client && \
ssh-keyscan -t ed25519 -H gitlab.com >> /root/.ssh/known_hosts
RUN git clone git@gitlab.com:GITLAB_USERNAME/test.git
RUN rm -r /root/.ssh

2. 一种不将私钥保存在映像中的工作方式(好!)

以下是同样事情的更安全的方法,使用“多级构建”;代替。 如果你需要一个有git回收目录没有将私钥存储在其中一个层中的映像,你需要两个映像,并且最后只使用第二个映像。这意味着你需要FROM两次,然后你可以仅从第一个映像复制git repo目录到第二个映像,看到官方指南“使用多级建筑”;.

我们用“高山”;作为尽可能小的基本图像,使用apk而不是apt-get;你也可以在上面的代码中使用apt-get而不是FROM ubuntu:latest

Dockerfile如下所示:

# first image only to download the git repo
FROM alpine as MY_TMP_GIT_IMAGE


RUN apk add --no-cache git
RUN mkdir -p /root/.ssh &&  chmod 700 /root/.ssh
COPY /.ssh/id_ed25519 /root/.ssh/id_ed25519
RUN chmod 600 /root/.ssh/id_ed25519


RUN apk -yqq add --no-cache openssh-client && ssh-keyscan -t ed25519 -H gitlab.com >> /root/.ssh/known_hosts
RUN git clone git@gitlab.com:GITLAB_USERNAME/test.git
RUN rm -r /root/.ssh




# Start of the second image
FROM MY_BASE_IMAGE
COPY --from=MY_TMP_GIT_IMAGE /MY_GIT_REPO ./MY_GIT_REPO

我们在这里看到FROM只是一个命名空间,它就像它下面行的标题,可以用别名来寻址。如果没有别名,--from=0将是第一个图像(=FROM命名空间)。

因此,你不需要在每次克隆repo时都创建一个新的密钥对。当然,请注意,如果有人可能通过其他方式获得您的数据,那么无密码私钥仍然是不安全的。如果您不确定这一点,最好在使用后从服务器中删除公钥,并在每次运行时都有一个新的密钥对。


如何从Dockerfile构建映像的指南

  • 安装Docker Desktop;或者在VirtualBox中使用WSL2或Linux中的docker;或者在独立的Linux分区/硬盘驱动器中使用docker。

  • 打开命令提示符(PowerShell, terminal,…)

  • 进入Dockerfile所在目录。

  • 创建子文件夹“。ssh/”。

  • 出于安全原因,为运行每一个 Dockerfile创建一个公私SSH密钥对——即使你已经有了另一个密钥对。在命令提示符中,在Dockerfile的文件夹中,输入(注意,这是不需要询问的覆盖):

      Write-Output "y" | ssh-keygen -q -t ed25519 -f ./.ssh/id_ed25519 -N '""'
    

    (如果您使用PowerShell)或

      echo "y" | ssh-keygen -q -t ed25519 -f ./.ssh/id_ed25519 -N ''
    

    (如果您不使用PowerShell)。

    您的密钥对现在将位于.ssh/子文件夹中。这取决于你是否使用该子文件夹,你也可以将代码更改为COPY id_ed25519 /root/.ssh/id_ed25519;那么你的私钥需要在你所在的Dockerfile目录中。

  • 在编辑器中打开公钥,复制内容并发布到您的服务器(例如GitHub / GitLab—>概要——比;SSH密钥)。您可以选择任何名称和结束日期。公钥字符串的最后可读注释(通常是你的计算机名,如果你没有在ssh-keygen的参数中添加-C注释)并不重要,把它放在那里就好。

  • < p >开始(不要忘记"最后是构建上下文):

    Docker build -t test。

仅限1人使用。)

  • 运行后,从服务器中删除公钥(这是最重要的,而且最好立即删除)。该脚本从映像中删除私钥,您也可以从本地计算机中删除私钥,因为您不应该再使用该密钥对。原因:有人可以从映像中获取私钥,即使它已从映像中删除。引用一个用户的注释:

    如果有人得到你的 想象一下,他们可以找回钥匙……即使你删除了文件 后面的图层,b/c他们可以回到步骤7,当你添加它

    攻击者可以使用此私钥等待,直到您再次使用该密钥对。

仅限2人。)

  • 运行之后,由于第二个映像是构建之后剩下的惟一映像,因此我们不一定需要从客户机和主机中删除密钥对。我们仍然有一个小的风险,即无密码私钥是从某个地方的本地计算机中获取的。这就是为什么你仍然可以从git服务器中删除公钥。您也可以删除任何存储的私钥。但在许多项目中,它可能并不需要,因为这些项目的主要目标是自动化构建映像,而不是安全性。

最后,更多的元噪声

对于这里两个高度好评的答案中的危险的错误建议,它们使用了有问题的私钥回声方法,以下是撰写本文时的投票情况:

我们在这里看到答案中一定有错误,因为排名前1的答案投票至少不是在问题投票的水平上。

在排名前1的答案的评论列表的末尾,只有一个没有投票的小评论,命名了相同的私钥回声问题(在这个答案中也引用了这个问题)。而且,这一批评性评论是在给出答案三年后提出的。

我自己也给前1个答案投票。后来我才意识到这对我不起作用。因此,群体智能是在工作,但在低火焰?如果有人能向我解释为什么私钥回显对其他人有用,但对我没用,请评论。否则,326k次观看(减去2条评论;))将会监督或忽略前1个答案的错误。如果私钥的回声代码行不是花费了我很多工作日的话,我就不会在这里写这么长一篇文章了,因为我从网上的所有东西中挑选了非常令人沮丧的代码。

下面是我如何在使用docker composer构建图像时使用ssh键:

.env

SSH_PRIVATE_KEY=[base64 encoded sshkey]

docker-compose.yml

version: '3'
services:
incatech_crawler:
build:
context: ./
dockerfile: Dockerfile
args:
SSH_PRIVATE_KEY: ${SSH_PRIVATE_KEY}
< p > dockerfile: …< / p >
# Set the working directory to /app
WORKDIR /usr/src/app/
ARG SSH_PRIVATE_KEY
 

RUN mkdir /root/.ssh/
RUN echo -n ${SSH_PRIVATE_KEY} | base64 --decode > /root/.ssh/id_rsa_wakay_user