420

I have an app that executes various fun stuff with Git (like running git clone & git push) and I'm trying to docker-ize it.

I'm running into an issue though where I need to be able to add an SSH key to the container for the container 'user' to use.

I tried copying it into /root/.ssh/, changing $HOME, creating a git ssh wrapper, and still no luck.

Here is the Dockerfile for reference:

#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 runs the git commands like git pull

4

34 回答 34

206

如果您需要在构建时使用 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.

于 2017-02-08T22:57:57.690 回答
95

结果在使用 Ubuntu 时,ssh_config 不正确。您需要添加

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

到您的 Dockerfile 以使其识别您的 ssh 密钥。

于 2013-08-09T00:19:13.667 回答
88

注意:只对私有的图像使用这种方法,并且永远是

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
于 2014-07-24T15:04:31.697 回答
74

如果您使用docker compose,一个简单的选择是像这样转发 SSH 代理:

something:
    container_name: something
    volumes:
        - $SSH_AUTH_SOCK:/ssh-agent # Forward local machine SSH key to docker
    environment:
        SSH_AUTH_SOCK: /ssh-agent
于 2016-04-15T13:24:24.267 回答
67

扩展Peter Grainger 的答案,我能够使用自 Docker 17.05 以来可用的多阶段构建。官方页面声明:

通过多阶段构建,您可以FROM在 Dockerfile 中使用多个语句。每条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 应用程序的源代码,并将其放置dist在下一个名为production. 请注意,installed 的源代码是从第一阶段生成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在第三阶段,我们通过仅包含dist来自名为的第二个中间图像的目录production并安装 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_KEY和。SSH_KEY_PASSPHRASE

于 2018-02-01T14:25:37.423 回答
39

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

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

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

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

于 2013-08-08T21:44:52.833 回答
26

一种跨平台解决方案是使用绑定挂载将主机的.ssh文件夹共享到容器:

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

与代理转发类似,这种方法将使容器可以访问公钥。另一个好处是它也可以与非 root 用户一起使用,并且可以让你连接到 GitHub。但是,需要考虑的一个警告是,文件夹中的所有内容(包括私钥).ssh都将被共享,因此这种方法仅适用于开发并且仅适用于受信任的容器映像。

于 2017-09-25T13:34:30.937 回答
19

docker API 1.39+(检查 API 版本docker version)开始,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

更多信息:

于 2019-11-15T19:47:59.613 回答
15

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

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

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

3) ssh-key 也一样:把它作为一个卷(如上所述)并在需要时将它链接到 git clone 服务

这样,克隆任务和密钥都是短暂的,仅在需要时才处于活动状态。

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

于 2015-06-23T00:37:32.643 回答
15

将 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因为在容器内使用除 root 以外的其他用户会git失败。

您可以将一些附加变量发布到容器的环境中:

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

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

于 2017-10-02T14:18:59.607 回答
14

这条线有问题:

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

于 2014-04-17T12:22:08.323 回答
14

在 docker build time 执行 npm install 时,我们遇到了类似的问题。

受到Daniel van Flymen解决方案的启发,并将其与 git url rewrite相结合,我们发现了一种更简单的方法来验证来自私有 github 存储库的 npm install - 我们使用 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
于 2017-04-27T13:02:37.243 回答
13

我今天遇到了同样的问题,并且对以前的帖子进行了一些修改,我发现这种方法对我更有用

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

所以我没有得到Bad owner or permissions on /root/.ssh/..@kross 指出的那个错误

于 2016-12-28T16:21:50.917 回答
13

从 18.09 版本开始就可以使用了!

根据文档

docker build 有一个 --ssh 选项,允许 Docker Engine 转发 SSH 代理连接。

以下是在容器中使用 SSH 的 Dockerfile 示例:

# 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

于 2021-02-21T11:01:11.573 回答
12

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

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

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

于 2020-03-26T09:32:45.823 回答
11

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

与 Docker 18.09 不同,您现在可以使用“构建机密”功能。在我的情况下,我使用我的主机 SSH 密钥克隆了一个私有 git repo,并在我的 Dockerfile 中包含以下内容:

# syntax=docker/dockerfile:experimental

[...]

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

[...]

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

export DOCKER_BUILDKIT=1

您需要将--ssh default参数添加到docker build.

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

于 2019-04-15T13:00:35.827 回答
10

这个问题真的很烦人。由于您无法在 dockerfile 上下文之外添加/复制任何文件,这意味着无法仅将 ~/.ssh/id_rsa 链接到图像的 /root/.ssh/id_rsa 中,并且当您肯定需要密钥来做一些 sshed 事情时就像来自私人回购链接的 git clone ...,在构建 docker 映像期间。

无论如何,我找到了解决方法,虽然不是那么有说服力,但确实对我有用。

  1. 在您的 dockerfile 中:

    • 将此文件添加为 /root/.ssh/id_rsa
    • 做你想做的事,比如 git clone、composer...
    • rm /root/.ssh/id_rsa 最后
  2. 一次拍摄的脚本:

    • cp 保存 dockerfile 的文件夹的密钥
    • 码头工人建造
    • rm 复制的密钥
  3. 任何时候你必须从这个镜像运行一个具有一些 ssh 要求的容器,只需为运行命令添加 -v,比如:

    docker run -v ~/.ssh/id_rsa:/root/.ssh/id_rsa --name 容器镜像命令

此解决方案导致您的项目源和构建的 docker 映像中没有私钥,因此无需担心安全问题。

于 2015-05-01T05:21:33.060 回答
8

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

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

请记住,docker 使用 sudo 运行(除非您不这样做),如果是这种情况,您将使用 root ssh 密钥。

于 2014-05-13T22:02:14.610 回答
8

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

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

于 2014-01-15T11:16:24.870 回答
8

此处详细介绍了Docker 容器中的 SSH 挑战的简要概述。为了在不泄露机密的情况下从容器内连接到受信任的遥控器,有几种方法:

除此之外,在使用 Compose 时,还可以使用在运行时可访问的单独 docker 容器中运行的密钥库。这里的缺点是额外的复杂性,因为创建和管理密钥库(例如HashiCorp 的 Vault)所需的机器

对于在独立 Docker 容器中使用 SSH 密钥,请参阅上面链接的方法,并根据您的特定需求考虑每种方法的缺点。但是,如果您在 Compose 中运行并希望在运行时共享应用程序的密钥(反映 OP 的实用性),请尝试以下操作:

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

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

其他资源:

于 2019-09-27T05:23:59.433 回答
7

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

这里的大多数解决方案最终都会将私钥留在图像中。这很糟糕,因为任何有权访问图像的人都可以访问您的私钥。由于我们对 的行为知之甚少squash,即使您删除密钥并压缩该层,情况仍可能如此。

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

在 dockerfile 中,我们有一个执行所有这些步骤的 RUN 命令:使用预唱 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"]
于 2017-10-03T06:29:42.520 回答
6

无需将密钥保存在 Docker 映像层或通过 ssh_agent 体操即可实现此目的的一种简单且安全的方法是:

  1. 作为 中的步骤之一Dockerfile,通过添加以下内容来创建.ssh目录:

    RUN mkdir -p /root/.ssh

  2. 下面表示您希望将 ssh 目录挂载为卷:

    VOLUME [ "/root/.ssh" ]

  3. 通过添加以下行确保您的容器ssh_config知道在哪里可以找到公钥:

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

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

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

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

    - "~/.ssh:/root/.ssh"

您的最终结果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" ]
于 2019-03-15T04:32:00.387 回答
6

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

您无需为此解决方案更改 Dockerfile。

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

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

# 之前做一些脚本的东西    

...

码头运行--rm \
   -v ~/.ssh:/root/.ssh \
   -v "$workspace":/工作空间\
   -w /工作区构建器\
   bash -cl "./scripts/build-init.sh $ executable"

...

# 之后做一些脚本的事情(即把构建的可执行文件拉出工作区,等等)

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

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

注意 1:为此,您需要确保您的 ssh 密钥没有密码,否则该ssh-add /root/.ssh/id_rsa行将要求输入密码并中断构建脚本。

注意 2:确保您对脚本文件设置了正确的文件权限,以便它们可以运行。

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

于 2020-11-11T18:30:59.287 回答
5

起初,一些元噪音

这里有两个高度赞成的答案有一个危险的错误建议。

我发表了评论,但由于我为此浪费了很多天,请注意:

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

使用COPYADD代替。有关详细信息,请参阅Docker 加载密钥“/root/.ssh/id_rsa”:格式无效

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

我收到错误加载密钥“/root/.ssh/id_ed25519”:格式无效。Echo 将为我删除双引号上的换行符/附加。这仅适用于 ubuntu 还是 alpine:3.10.3 有什么不同?


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 repo 目录但没有将私钥存储在其中一个层中的图像,则需要两个图像,最后只使用第二个。也就是说,你需要FROM两次,然后你可以只复制第一个镜像到第二个镜像的 git repo 目录,参见官方指南“使用多阶段构建”

我们使用“alpine”作为最小可能的基本图像,它使用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命名空间)。

您现在可以发布或共享第二个图像,因为私钥不在其层中,并且您不必在使用一次后从 git 网站中删除公钥!因此,您无需在每次克隆存储库时都创建新的密钥对。当然,请注意,如果有人可能以另一种方式获取您的数据,那么无密码的私钥仍然是不安全的。如果您对此不确定,最好在使用后从服务器中删除公钥,并在每次运行时都有一个新的密钥对。


如何从 Dockerfile 构建映像的指南

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

  • 打开命令提示符(PowerShell、终端等)。

  • 转到 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 密钥)。您可以选择任何名称和结束日期。公钥字符串的最终可读注释(如果您没有-C在 的参数中添加注释,通常是您的计算机名称ssh-keygen)并不重要,只需将其留在那里即可。

  • 开始(不要忘记末尾的“。”是构建上下文):

    泊坞窗构建 -t 测试。

仅适用于 1。):

  • 运行后,从服务器上删除公钥(最重要,最多一次)。该脚本会从映像中删除私钥,您也可以从本地计算机中删除私钥,因为您不应再次使用该密钥对。原因:即使从图像中删除,也有人可以从图像中获取私钥。引用用户的评论:

    如果有人持有您的图像,他们可以检索密钥......即使您在稍后的层中删除该文件,b/c 他们可以在您添加它时返回第 7 步

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

仅适用于 2。):

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

最后,一些元噪音

至于此处两个高度赞成的答案中使用有问题的私钥回声方法的危险错误建议,以下是撰写本文时的投票:

我们在这里看到答案肯定有问题,因为前 1 个答案投票至少不是问题投票的水平。

在前 1 个答案的评论列表的末尾只有一个小的且未投票的评论,命名了相同的私钥回显问题(此答案中也引用了该问题)。并且:这个批评性评论是在回答三年后发表的。

我自己投票给了前 1 个答案。我后来才意识到它对我不起作用。因此,群体智能正在发挥作用,但在低火上?如果有人可以向我解释为什么回显私钥可能对其他人有用,但对我无效,请发表评论。否则,32.6 万次观看(减去 2 条评论;))会忽略或忽略前 1 个答案的错误。如果那个回显私钥代码行不会花费我很多工作日,我不会在这里写这么长的文本,从网上的所有东西中挑选绝对令人沮丧的代码。

于 2021-03-16T03:02:31.947 回答
4

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

有关更多信息,请参阅我的 stackoverflow 问题的答案

于 2018-01-15T12:22:13.410 回答
2

我正在尝试以另一种方式解决问题:将公共 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
于 2014-01-02T21:18:34.007 回答
1

您可以使用共享文件夹将授权密钥传递到您的容器中,并使用 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 run 包含类似以下内容的内容,用于与容器共享主机上的 auth 目录(保存授权密钥),然后打开可通过主机上的端口 7001 访问的 ssh 端口。

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

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

于 2017-04-10T08:33:10.530 回答
1

以下是我在使用 docker composer 构建映像期间使用 ssh 密钥的方法:

.env

SSH_PRIVATE_KEY=[base64 encoded sshkey]

码头工人-compose.yml

version: '3'
services:
  incatech_crawler:
    build:
      context: ./
      dockerfile: Dockerfile
      args:
        SSH_PRIVATE_KEY: ${SSH_PRIVATE_KEY} 

码头文件:...

# 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
于 2021-04-13T08:41:13.213 回答
1

就我而言,我遇到了来自远程存储库的 nodejs 和“npm i”问题。我修复了它,将“节点”用户添加到 nodejs 容器,并将 700 添加到容器中的 ~/.ssh。

Dockerfile:

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

运行.sh:

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

码头工人-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

之后它开始工作

于 2020-03-12T15:28:46.643 回答
1

诚然,迟到了,这将使您的主机操作系统密钥可用于容器内的 root,动态:

docker run -v ~/.ssh:/mnt -it my_image /bin/bash -c "ln -s /mnt /root/.ssh; ssh user@10.20.30.40"

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

于 2018-01-05T11:27:47.053 回答
0

您可以使用机密来管理容器在运行时需要但您不想存储在映像或源代码管理中的任何敏感数据,例如:

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

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

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

于 2019-03-31T23:12:29.140 回答
-1

对于 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
于 2019-07-13T11:13:02.513 回答
-2

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

于 2015-04-14T06:46:51.977 回答
-2

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

于 2013-11-24T02:50:53.603 回答