在docker容器内使用SSH密钥

ebe*_*ing 289 ssh-keys docker

我有一个应用程序,使用Git执行各种有趣的东西(如运行git clone和git push),我正在尝试停靠它.

我遇到了一个问题,虽然我需要能够在容器中添加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"]
Run Code Online (Sandbox Code Playgroud)

app.js 像git一样运行git命令 git pull

Dan*_*men 125

如果您需要在构建时使用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 .
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

更新:如果您正在使用Docker 1.13并且具有实验性功能,则可以附加--squash到将合并图层的构建命令,删除SSH密钥并将其隐藏起来docker history.

  • [这个GitHub问题主题](https://github.com/moby/moby/issues/6396#issuecomment-267261192)表明这种方法仍然不安全.有关其他类似解决方案,请参阅[此评论](https://github.com/moby/moby/issues/6396#issuecomment-270550056). (11认同)
  • 除了挤压之外,另一种解决方案是在同一RUN命令中添加和删除密钥,并且在添加和删除之间,可以将密钥用于所需的用途。 (4认同)
  • 我收到“加载密钥“/root/.ssh/id_rsa”时出错:格式无效”。Echo 将为我删除换行符/添加双引号。这仅适用于 ubuntu 还是 alpine:3.10.3 有什么不同? (4认同)
  • 也许您可以删除用于创建 `id_rsa.pub` 文件的行,因为它不是必需的。 (3认同)
  • 不要挤压,而是使用[多阶段图像构建](https://medium.com/@tonistiigi/advanced-multi-stage-build-patterns-6f741b852fae)。 (3认同)

ebe*_*ing 84

使用Ubuntu时,ssh_config不正确.你需要添加

RUN  echo "    IdentityFile ~/.ssh/id_rsa" >> /etc/ssh/ssh_config
Run Code Online (Sandbox Code Playgroud)

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

  • 这不安全!请参阅下面的解决方案,了解Docker的最新1.13版本.@ebensing (10认同)
  • 为什么有人会将私钥从主机复制到容器。命令没问题,但我认为执行上述操作没有意义...... (3认同)
  • @VladimirDjuricic 虽然有部署密钥之类的东西。 (3认同)
  • 您可能还需要设置正确的用户名,例如`RUN echo"Host example.com">> /root/.ssh/config RUN echo"User <someusername>">>/root/.ssh/config` (2认同)

yel*_*cap 78

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

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
Run Code Online (Sandbox Code Playgroud)

  • 这将使您的密钥保留在图像中,不要这样做. (79认同)
  • @CppLearner你是对的,这确实将密钥存储在映像中,在某些情况下这可能是一个安全问题.感谢您突出这一点.但是,有很多情况可以完全保存.例如,对于存储在专用存储库中的图像,或直接在生产服务器上构建的图像,将本地密钥复制到映像. (12认同)
  • 我不得不从``echo``命令中删除``-e``. (6认同)
  • 此外,如果您在Dockerfile中安装供应商,那么在安装供应商后,没有什么能阻止您删除ssh密钥. (2认同)
  • @SebScoFr,显然密钥将存储在其中一个层中,即使您在以后的命令中删除它们(请参阅更新后的答案中的链接).因此图像将始终显示ssh键,解决方案应仅用于私有图像! (2认同)
  • @yellowcap 不是,如果您 --squash 构建 (2认同)

Ais*_*tis 53

如果你正在使用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
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这不适用于Mac主机,无论是使用docker-machine(通过VirtualBox)还是Docker for Mac(使用xhyve),因为unix域套接字未被代理. (22认同)
  • 关于`SSH_AUTH_SOCK`的更多细节 http://blog.joncairns.com/2013/12/understanding-ssh-agent-and-ssh-add/ (4认同)
  • macOS 主机现在也支持 ssh 转发 - 您必须安装此路径 - “/run/host-services/ssh-auth.sock”,而不是安装“$SSH_AUTH_SOCK”的路径。 (3认同)
  • 我认为值得指出的是,使用此解决方案,如果您在将所需密钥添加到主机上的代理之前尝试使用 SSH,则会在容器中出现错误。这是有道理的,您决定允许 SSH 访问而不在容器中放入任何密钥,但对于不熟悉您要解决的问题的人来说可能并不完全直观,因此最好将其记录在某处。 (2认同)

fun*_*man 46

自 18.09 版本起现已可用!

根据文档

docker 版本有一个 --ssh 选项,允许 Docker 引擎转发 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
Run Code Online (Sandbox Code Playgroud)

创建 Dockerfile 后,使用--ssh与 SSH 代理连接的选项:

$ docker build --ssh default .
Run Code Online (Sandbox Code Playgroud)

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

  • Linux 用户需要启用 BuildKit 才能使用它,因为默认情况下它似乎并未启用。这可以通过在运行构建之前运行 `export DOCKER_BUILDKIT=1` 来完成,或者通过将 `{ "features": { "buildkit": true } }` 放入文件中来配置 Docker 守护进程以默认启用它:`/etc/docker/daemon.json`(至少在 Ubuntu 20.04 上是这样的,其他发行版可能会有所不同。)文档:https://docs.docker.com/develop/develop-images/build_enhancements/#to -启用-buildkit-构建 (7认同)

cre*_*ack 40

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

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

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

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

  • 我只是尝试使用'base'图像,执行`apt-get install openssh-server`并将我的密钥放在/root/.ssh/id_rsa中,它运行正常.你用的是什么形象? (3认同)
  • 所以,截至目前,我已经尝试将其复制到/root/.ssh/id_rsa但仍然收到"主机密钥验证失败.致命:远程端意外挂断"来自Git的错误,我很确定这意味着它因为某种原因没有使用密钥.所以我想我还需要做些什么来实际告诉系统使用它作为ssh密钥?不确定如何调试这个.(我知道这个密钥有效,因为它在没有主机问题的情况下运行) (2认同)

Ezz*_*zze 38

扩展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"]
Run Code Online (Sandbox Code Playgroud)

.dockerignore重复.gitignore文件的内容(它会阻止node_modules并导致dist项目的结果目录被复制):

.idea
dist
node_modules
*.log
Run Code Online (Sandbox Code Playgroud)

构建映像的命令示例:

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

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

这是它的工作原理:

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

2).第二阶段构建并缩小Web应用程序的源代码,并将其放在dist下一个名为的中间图像的目录中production.请注意,已安装的源代码node_modulessources通过以下行从第一个阶段生成的图像中复制的:

COPY --from=sources /app/ /app/
Run Code Online (Sandbox Code Playgroud)

可能它也可能是以下行:

COPY --from=sources /app/node_modules/ /app/node_modules/
Run Code Online (Sandbox Code Playgroud)

我们只有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
Run Code Online (Sandbox Code Playgroud)

其中未标记的图像与第一和第二中间构建阶段相对应.

如果你跑

$ docker history ezze/geoport:0.6.0 --no-trunc
Run Code Online (Sandbox Code Playgroud)

你不会看到任何提及的SSH_KEY以及SSH_KEY_PASSPHRASE在最终图像.

  • 旧帖子,但我想强调这是迄今为止在 18.09 之前执行此操作的最佳方式。壁球是不必要的,而且容易发生风险。使用多阶段,您知道您只引入了您想要的工件。将壁球视为选择退出您不想要的文件,将多阶段视为选择加入。这个答案需要更高。在图像中烘焙 ssh 密钥是一种糟糕的做法。 (2认同)

que*_*o42 15

一开始,一些元噪音

\n

这里的两个高度评价的答案中有一个危险的错误建议。

\n

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

\n

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

\n

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

\n

这也得到了另一位网友的证实:

\n
\n

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

\n
\n
\n

1. 将私钥保留在镜像中的工作方式(不太好!)

\n

如果私钥存储在镜像中,需要注意将公钥从git网站删除,或者不要发布该镜像。如果你照顾好这一点,这是安全的。请参阅下面的 (2.) 了解更好的方法,您也可以“忘记注意”。

\n

Dockerfile 如下所示:

\n
FROM ubuntu:latest\nRUN apt-get update && apt-get install -y git\nRUN mkdir -p /root/.ssh && chmod 700 /root/.ssh\nCOPY /.ssh/id_ed25519 /root/.ssh/id_ed25519\nRUN chmod 600 /root/.ssh/id_ed25519 && \\\n    apt-get -yqq install openssh-client && \\\n    ssh-keyscan -t ed25519 -H gitlab.com >> /root/.ssh/known_hosts\nRUN git clone git@gitlab.com:GITLAB_USERNAME/test.git\nRUN rm -r /root/.ssh\n
Run Code Online (Sandbox Code Playgroud)\n
\n

2. 不将私钥保留在镜像中的工作方式(好!)

\n

下面是同样事情的更安全的方法,而是使用“多阶段构建”。\n如果您需要一个具有 git repo 目录但没有将私钥存储在其层之一的映像,则需要两个映像,并且您最后只使用第二个。这意味着,您需要FROM两次,然后您可以仅将第一个映像中的 git repo 目录复制到第二个映像,请参阅官方指南“使用多阶段构建”

\n

我们使用“alpine”作为尽可能小的基础图像,它apk使用apt-get; 您还可以使用apt-get上面的代码而不是使用FROM ubuntu:latest.

\n

Dockerfile 如下所示:

\n
# first image only to download the git repo\nFROM alpine as MY_TMP_GIT_IMAGE\n\nRUN apk add --no-cache git\nRUN mkdir -p /root/.ssh &&  chmod 700 /root/.ssh\nCOPY /.ssh/id_ed25519 /root/.ssh/id_ed25519\nRUN chmod 600 /root/.ssh/id_ed25519\n\nRUN apk -yqq add --no-cache openssh-client && ssh-keyscan -t ed25519 -H gitlab.com >> /root/.ssh/known_hosts\nRUN git clone git@gitlab.com:GITLAB_USERNAME/test.git\nRUN rm -r /root/.ssh\n\n\n# Start of the second image\nFROM MY_BASE_IMAGE\nCOPY --from=MY_TMP_GIT_IMAGE /MY_GIT_REPO ./MY_GIT_REPO\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

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

\n
\n

如何从 Dockerfile 构建镜像的指南

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

    \n
  • \n
  • 打开命令提示符(PowerShell、终端……)。

    \n
  • \n
  • 进入Dockerfile所在目录。

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

    \n
  • \n
  • 出于安全原因,请为每个密钥创建一个新的公共和私有 SSH 密钥对 - 即使您已经有另一个密钥对Dockerfile 运行在命令提示符下的 Dockerfile 文件夹中,输入(注意,这会覆盖而不询问):

    \n
      Write-Output "y" | ssh-keygen -q -t ed25519 -f ./.ssh/id_ed25519 -N \'""\'\n
    Run Code Online (Sandbox Code Playgroud)\n

    (如果您使用 PowerShell)或

    \n
      echo "y" | ssh-keygen -q -t ed25519 -f ./.ssh/id_ed25519 -N \'\'\n
    Run Code Online (Sandbox Code Playgroud)\n

    (如果您不使用 PowerShell)。

    \n

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

    \n
  • \n
  • 在编辑器中打开公钥,复制内容并将其发布到您的服务器(例如 GitHub / GitLab --> 配置文件 --> SSH 密钥)。您可以选择任何名称和结束日期。公钥字符串的最终可读注释(如果您没有-C在参数中添加注释,通常是您的计算机名称)ssh-keygen,通常是您的计算机名称)并不重要,只需将其留在那里即可。

    \n
  • \n
  • 开始(不要忘记末尾的“.”,它是构建上下文):

    \n

    docker build -t 测试。

    \n
  • \n
\n

仅适用于 1.):

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

    \n
    \n

    如果任何人掌握了您的\n图像,他们就可以检索密钥...即使您在后面的层中删除\n该文件,b/c 他们也可以在您添加该文件时返回到步骤 7

    \n
    \n

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

    \n
  • \n
\n

仅适用于 2):

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

最后,一些元噪音

\n

至于危险的错误建议这里两个高度赞扬的答案中使用有问题的私钥回显方法的

\n\n

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

\n

在排名前 1 的答案的评论列表末尾,只有一条未投票的小评论,命名了相同的私钥回声问题(该答案也引用了该问题)。并且:该批评意见是在答复三年后提出的。

\n

我自己已经对排名第一的答案投了赞成票。后来我才意识到这对我不起作用。因此,群体智能正在发挥作用,但力度不大?如果有人可以向我解释为什么回显私钥可能对其他人有效,但对我无效,请发表评论。否则,326k 浏览量(减去 2 条评论;))将会忽略或忽略第 1 个答案的错误。如果私钥回显代码行不会花费我很多工作日,并且从网上的所有内容中挑选代码绝对令人沮丧,我就不会在这里写这么长的文本。

\n


Dan*_*der 14

这行是个问题:

ADD ../../home/ubuntu/.ssh/id_rsa /root/.ssh/id_rsa
Run Code Online (Sandbox Code Playgroud)

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

ADD id_rsa /root/.ssh/id_rsa
Run Code Online (Sandbox Code Playgroud)

并将id_rsa文件放入Dockerfile所在的目录中.

有关详细信息,请查看此内容:http://docs.docker.io/reference/builder/#add

  • 这也是安全问题,因为它将私钥放入可以轻易忘记的图像中. (4认同)

Edi*_*ngo 14

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

构建命令

export DOCKER_BUILDKIT=1
docker build --ssh default=~/.ssh/id_rsa .
Run Code Online (Sandbox Code Playgroud)

文件

# 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
Run Code Online (Sandbox Code Playgroud)

更多信息:

  • 波形符扩展对我不起作用;我得到:`无法解析 ssh:[default=~/.ssh/id_rsa]:stat ~/.ssh/id_rsa:没有这样的文件或目录`。如果不起作用,请使用完整路径。 (2认同)
  • @CameronHudson我相信在这种情况下,您可以创建一个从主机到容器的绑定卷,并在该卷中添加 SSH 密钥。 (2认同)

MrE*_*MrE 13

Docker容器应该被视为自己的"服务".要分开关注点,您应该分开功能:

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

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

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

这样,克隆任务和密钥都是短暂的,只有在需要时才有效.

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


小智 13

在docker构建时进行npm install时遇到了类似的问题.

灵感来自Daniel van Flymen的解决方案并将其与git url重写相结合 ,我们发现了一个更简单的方法来验证来自私有github repos的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 . 
Run Code Online (Sandbox Code Playgroud)

不幸的是,我在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
Run Code Online (Sandbox Code Playgroud)


Moh*_*zim 11

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

docker run -v /home/<host user>/.ssh:/home/<docker user>/.ssh <image>
Run Code Online (Sandbox Code Playgroud)

与上述解决方案类似.但适用于非root用户.与github完美配合.

  • 这正是重点。您不想将 ssh 密钥放在 docker 文件中。 (9认同)
  • 鉴于 SSH 代理转发在 Linux 之外不起作用,这为在开发环境中启动和运行提供了一个很好的解决方案,无需太多麻烦。 (3认同)
  • 这可能会起作用,但仅在“docker run”期间不能在“docker build”期间起作用 (2认同)

Dev*_*esh 11

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

阶段 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
Run Code Online (Sandbox Code Playgroud)

第 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"] 
Run Code Online (Sandbox Code Playgroud)

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

   environment:
      - SSH_PRIVATE_KEY=${SSH_PRIVATE_KEY}
Run Code Online (Sandbox Code Playgroud)

然后像这样从构建脚本传递参数:

docker-compose build --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)"
Run Code Online (Sandbox Code Playgroud)

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

  • 这会将 SSH 密钥嵌入到 Docker 镜像中。这对于开发来说是可以的,但对于生产来说不应该这样做,因为任何有权访问该映像的人也将有权访问 SSH 密钥。 (3认同)
  • @CameronHudson您的评论是错误的,这个答案使用“COPY --from=sshImage”命令仅将所选文件夹从临时图像复制到新图像。其他任何东西(也意味着 ssh 密钥)都会被留下,并且临时映像会在“多阶段构建”中自动删除。因此,这个例子是安全的。我发现它太晚了,现在有一种[重复的答案](/sf/answers/4665397061/),也许它至少作为另一个例子是好的。 (2认同)

edu*_*upo 10

将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
Run Code Online (Sandbox Code Playgroud)

您的脚本将能够执行git clone.

额外:如果您希望克隆文件属于您需要使用的特定用户,chown因为在容器内使用除root之外的其他用户将导致git失败.

您可以在容器的环境中发布一些其他变量:

docker run ...
        -e OWNER_USER=$(id -u) \
        -e OWNER_GROUP=$(id -g) \
        ...
Run Code Online (Sandbox Code Playgroud)

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


ImL*_*Leo 9

这个问题真的很烦人.因为你不能在dockerfile上下文之外添加/复制任何文件,这意味着不可能只将〜/ .ssh/id_rsa链接到图像的/root/.ssh/id_rsa,当你肯定需要一个键来做一些sshed的东西时喜欢来自私人仓库链接的git clone ...,在建造你的码头图像时.

无论如何,我找到了一个解决方法,不是那么说服,但确实对我有用.

  1. 在您的dockerfile中:

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

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

    docker run -v~/.ssh/id_rsa:/root/.ssh/id_rsa --name container image命令

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

  • *"因为你不能在 dockerfile 上下文之外添加/复制任何文件,"* 你见过 `docker cp` 吗?它用于“在容器和主机之间复制文件/文件夹”。 (2认同)

Jos*_*das 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 应用程序的情况下。

上述方法是开发和测试的理想选择,虽然它可以满足生产要求,但在生产中,您最好使用上述其他方法之一。

其他资源:


arr*_*che 7

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

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

  • 你能解释一下这个选项吗......第二次我看到了这种用法.谢谢 (5认同)
  • docker run -i -t -v $(readlink -f $SSH_AUTH_SOCK):/ssh-agent -e SSH_AUTH_SOCK=/ssh-agent ubuntu /bin/bash (4认同)
  • Fruitl00p 以这种方式创建了一个 docker-tunnel 容器:https://github.com/kingsquare/docker-tunnel (2认同)

小智 7

我今天遇到了同样的问题和以前的帖子稍微修改过的版本我发现这种方法对我来说更有用

docker run -it -v ~/.ssh/id_rsa:/root/.my-key:ro image /bin/bash
Run Code Online (Sandbox Code Playgroud)

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

在容器里面我现在可以运行:

ssh-agent bash -c "ssh-add ~/.my-key; git clone <gitrepourl> <target>"
Run Code Online (Sandbox Code Playgroud)

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


Sam*_* H. 7

如果您不关心 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 .
Run Code Online (Sandbox Code Playgroud)

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"]
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案的问题是,因为pre_sign_url每次都会改变,所以即使packages.json文件没有变化,也无法缓存npm install。最好在 build.sh 中获取 key 并将其设置为 build 参数,这样它就不会每次都改变 (3认同)

Lui*_*ndo 6

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

$ sudo docker run -it -v /root/.ssh:/root/.ssh someimage bash
Run Code Online (Sandbox Code Playgroud)

请记住,docker使用sudo运行(除非你没有),如果是这种情况你将使用root ssh密钥.

  • 这将是一种首选方法,诀窍是使用我的非特权主机用户的密钥作为容器的根.正如您所提到的那样,尝试这样做并不是因为主机root用户在/ root/.ssh/config`上产生了"错误的所有者或权限". (3认同)
  • @ccpizza,我认为这是一个优势。这些答案中有许多都将私钥存储在图像中。即使您在后续图层命令中删除了密钥,该密钥仍保持存储状态。通过仅在运行(而不是构建)期间引入私钥,它们只能存在于容器中(而不是映像)。 (2认同)

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

你的finalDockerfile应该包含如下内容:

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" ]
Run Code Online (Sandbox Code Playgroud)


小智 6

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

现在,可以在Docker 18.09中使用“构建机密”功能。就我而言,我使用主机SSH密钥在Dockerfile中使用以下命令克隆了一个私人git repo:

# syntax=docker/dockerfile:experimental

[...]

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

[...]
Run Code Online (Sandbox Code Playgroud)

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

export DOCKER_BUILDKIT=1
Run Code Online (Sandbox Code Playgroud)

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

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


cgo*_*ain 5

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

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

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

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

# 之前做一些脚本的东西    

...

码头工人运行--rm \
   -v ~/.ssh:/root/.ssh \
   -v "$workspace":/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
Run Code Online (Sandbox Code Playgroud)

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

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

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

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


归档时间:

查看次数:

228111 次

最近记录:

5 年,11 月 前