在Docker容器中使用SSH密钥


324

我有一个应用程序可以使用Git执行各种有趣的操作(例如运行git clone和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命令,例如 git pull


3
遇到此问题的任何人都应该考虑一下最终游戏,因为它很容易造成安全漏洞,如果您不小心的话,这里就不用理会了。阅读所有答案并明智地选择。
乔什·哈布达斯

Answers:


144

如果您需要在构建时使用SSH,这将是一个更困难的问题。例如,如果你正在使用git clone,或在我的情况pip,并npm从私人仓库下载。

我发现的解决方案是使用该--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 .

Docker文件

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到build命令,该命令将合并各层,删除SSH密钥并从中隐藏它们docker history


13
这个GitHub问题线程将表明这种方法仍然不安全。另请参阅此评论以获取类似的解决方案。
eczajk

4
除了挤压之外,另一种解决方案是在同一RUN命令中添加和删除密钥,并且在添加和删除之间,可以将密钥用于所需的用途。
本杰明·哈默

2
也许您可以删除创建id_rsa.pub文件的行,因为它不是必需的。
LCB

1
代替挤压,而是使用多阶段图像构建
理查德·基弗

如果您的密钥受密码保护,请$(openssl rsa -in ~/.ssh/id_rsa)改用
BroiSatse

89

原来使用Ubuntu时,ssh_config不正确。您需要添加

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

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


2
您可能还需要设置正确的用户名,例如RUN echo " Host example.com" >> /root/.ssh/config RUN echo " User <someusername>" >> /root/.ssh/config
monofone

1
为什么有人将私钥从主机复制到容器。命令还可以,但是我做上述事情没有道理...
弗拉基米尔·朱里奇(Fladimir Djuricic)

12
这是不安全的!请参阅下面的解决方案,以获取最新的Docker 1.13版本。@ebensing
Daniel van Flymen

1
@VladimirDjuricic虽然有一些部署密钥。
Zelphir Kaltstahl '18年

实际上,您需要运行ssh-keygen -A才能在ubuntu最小容器上正确设置ssh。然后,您可以添加pub / priv键并启动sshd。我的dockerfile中有以下条目:'RUN ssh-keygen -A'作为步骤之一。
piotrektt

84

注意:仅对私有图像使用此方法,并且将始终如此

即使在添加后在层命令中删除了该密钥,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

91
这样会将您的密钥保留在图像中,请不要这样做。
CppLearner

12
@CppLearner,您是对的,这确实将密钥存储在映像中,在某些情况下这可能是安全问题。感谢您强调这一点。但是,在许多情况下,这是完全可以节省的。例如,对于存储在专用存储库中的映像,或直接在生产服务器上构建的将本地密钥复制到映像的映像。
Yellowcap

2
另外,如果您将供应商安装在Dockerfile中,那么一旦安装了供应商,也不会阻止您删除ssh密钥。
SebScoFr '16

2
@SebScoFr,即使您在以后的命令中删除了密钥,显然密钥也会存储在其中一层中(请参阅更新答案中的链接)。因此,映像将始终公开ssh密钥,并且解决方案仅应用于私有映像!
yellowcap

1
@yellowcap如果您不
压扁

56

如果您使用的是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

23
请注意,这不适用于Mac主机,无论是使用docker-machine(通过VirtualBox)还是Docker for Mac(使用xhyve),因为没有代理Unix域套接字。
乔·萧

SSH_AUTH_SOCK是一个变量,其中包含ssh代理的路径
Aistis


1
现在,macOS主机上还支持ssh-forwarding-而不是安装的路径$SSH_AUTH_SOCK,而必须安装此路径- /run/host-services/ssh-auth.sock
雅库布·库库尔

47

扩展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。请注意,已安装的源代码node_modulessources通过以下行从第一阶段生成的命名映像中复制的:

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

可能也可能是以下行:

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

node_modules这里只有第一个中间映像的目录,现在没有no 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在最终图像。


旧帖子,但我想强调一下,这是迄今为止在18.09之前完成此操作的最佳方法。壁球是不必要的,容易产生风险。使用多阶段,您知道您仅会引入所需的工件。将南瓜视为您不想使用的文件的选择退出,将多阶段视为选择加入。这个答案需要更高。在图像中烘烤ssh键是很糟糕的做法。
mritalian '19

@ezze非常感谢您提供这一非常有用的帖子:) SSH代理使我发疯,我做了与您相似的事情:我正确地在docker build日志中看到了,Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)但是当我签入另一个RUN或什至在同一RUN中时通过执行命令,ssh-add -l它告诉我“代理没有身份”。开始扯我的头发了,有什么想法吗?
亚历克斯

40

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

  1. 结合使用Dockerfile和ADD指令,可以在构建过程中注入它

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

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


2
因此,到目前为止,我已经尝试将其复制到/root/.ssh/id_rsa,但仍收到来自Git的“主机密钥验证失败。致命:远端意外挂起”错误,我敢肯定,这意味着出于任何原因都不使用密钥。所以我在想我还需要做其他事情来实际告诉系统使用它作为ssh密钥吗?不确定究竟该如何调试。(而且我知道此密钥有效,因为它可以正常运行,不受主机的
干扰

您可以确保/ etc / ssh / ssh_config目标正确的密钥文件吗?
creack

1
有没有检查Docker容器文件的好方法?还是我应该尝试复制有效的配置?
2013年

3
我只是尝试使用“基本”图像,apt-get install openssh-server将我的密钥放在/root/.ssh/id_rsa中,效果很好。您正在使用什么图像?
creack,

如果您需要检查容器的文件,最好的方法是使用'cat'提交并运行生成的图像。
creack,

15

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

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

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


1
这可能会起作用,但并非docker build仅在以下期间有效docker run
Alexander Mills

3
这就是重点。您不想将ssh密钥放入docker文件中。
穆罕默德·阿齐姆

2
鉴于SSH代理转发在Linux外部不起作用,这为在开发环境中正常运行提供了一个很好的解决方案,而无需大惊小怪。
乔什·哈布达斯

我正在docker-compose up本地Windows 10中运行docker 。在那种情况下,我应该如何使用您的解决方案?
llaaalu

本质上,您是在问如何在docker compose中映射卷。上面有一个答案。专为Windows这可能有助于stackoverflow.com/questions/41334021/...
穆罕默德·阿齐姆

14

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

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

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

3)与ssh-key相同:放入一个卷(如上所示),并在需要时将其链接到git clone服务

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

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


13

这行是个问题:

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


4
这也是安全性问题,因为它会将私钥放入易于忘记的图像中。
Mike D

docker cp只是将其放在容器中而不是图像中,对吗?
亚历山大·米尔斯

13

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

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

11

将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用户可以访问文件。


1
在较新的Docker版本中,您可以传递-u root:$(id -u $USER)至少与用户属于同一主要组的文件,这应使所有文件至少具有可读性,sudo除非有0600权限创建它们。
Dragon788

@ dragon788我认为您有错别字:-u root:$(id -u $USER)应该是-g
edupo '17

好决定!我似乎无法通过移动设备进行修复,将很快在台式机上尝试。
dragon788

/tmp/ssh_auth.sock: No such file or directory现在/tmp/ssh-vid8Zzi8UILE/agent.46016在主机上
vladkras

@vladkras该错误非常笼统。可能是由于/tmp容器内部的权限引起的。或在docker run命令上输入错误。确保bind语句正确-v $SSH_AUTH_SOCK:/tmp/ssh_auth.sock:顺序很重要,分号也很重要。请查看Docker文档以获取更多帮助。
edupo '17

10

正如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 [...]

[...]

为了能够使用它,您需要在运行之前启用新的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


1
最好的解决方案恕我直言。我必须做另外两件事才能使其正常工作:1)将我的私钥添加到ssh-agent中,ssh-add ~/.ssh/id_rsa以及2)将git主机添加到known_hosts中,即用于bitbucket:RUN ssh-keyscan -H bitbucket.org >> ~/.ssh/known_hosts
Moritz Ringler,

我根本无法使它正常工作。我仍然遇到权限错误:Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access and the repository exists.尽管--ssh default在我的docker build中传递了该标志,并--mount=type=ssh在我所在的run命令中使用了该错误git clone。我能够在构建机器上克隆相同的仓库没问题。它只是在docker build容器中失败。我怀疑Docker的Mac版本实际上没有传递ssh客户端。
PMende

@PMende能够找出您提到的问题,因为我也面临同样的问题。
Sadan A.19年

@SadanArshad事实证明,仅当您从Linux计算机运行Docker时,当前才支持此功能。如果您从Mac(甚至可能是Windows,尽管我无法确认)上运行Docker命令,则该命令将不起作用。
PMende

太糟糕了,不适用于docker
Alexis Wilke

9

这个问题确实很烦人。由于您无法在dockerfile上下文之外添加/复制任何文件,这意味着仅将〜/ .ssh / id_rsa链接到映像的/root/.ssh/id_rsa是不可能的,并且当您确实需要使用密钥来执行某些隐藏操作时例如在构建docker映像期间,从私人仓库链接中获取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容器映像命令

该解决方案不会在您的项目源代码和已构建的docker映像中导致任何私钥,因此不再需要担心安全问题。


1
“由于您无法在dockerfile上下文之外添加/复制任何文件,”您看到了docker cp吗?它用于“在容器和主机之间复制文件/文件夹”。
乔纳森·莱因哈特

@JonathonReinhart,感谢您指出这一点。是的,docker cp可以解决问题。但是在这种情况下,我在构建映像时需要ssh_key,并且那时没有容器...无论如何都会更新我不清楚的表情。
ImLeo '16

9

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

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指出的错误


谢谢!这是让它对我有用的关键:将ssh-agent和ssh-add放在一个命令中,例如:ssh-agent bash -c "ssh-add..."。然后,我可以将其传递给docker run。我发现的所有先前示例都使用了eval ssh-agent,后面是ssh-add,我想不出一种eval通过docker run命令传递该示例的方法。
ryanman '17


6

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

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

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


使用此方法可在docker 0.11上使用,但如果使用fig,它将引发恐慌错误。我不知道为什么
Luis Elizondo 2014年

3
这将是一种首选方法,诀窍是使用我的非特权主机用户的密钥作为容器的根。如您所述,不要以主机root用户yield的方式进行操作Bad owner or permissions on /root/.ssh/config
kross 2015年

这只能在期间使用docker run,而不能在期间使用docker build
ccpizza

3
@ccpizza,我认为这是一种优势。这些答案中有许多将私钥存储在图像中。即使您在后续图层命令中删除了密钥,该密钥仍保持存储状态。通过仅在运行(而不是构建)期间引入私钥,它们只能存在于容器中(而不是映像)。
cowlinator

6

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

生成命令

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

Docker文件

# 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

更多信息:


1
波浪线扩展对我不起作用;我得到了:could not parse ssh: [default=~/.ssh/id_rsa]: stat ~/.ssh/id_rsa: no such file or directory。如果不起作用,请使用完整路径。
slhck

3

如果您不关心SSH密钥的安全性,那么这里有很多不错的答案。如果你这样做,最好的答案,我发现是从上面的评论的链接此GitHub的评论通过diegocsandrim。为了使其他人更有可能看到它,以防万一回购消失,以下是该答案的编辑版本:

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

我们生成一个预签名URL来使用aws s3 cli访问密钥,并将访问限制在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"]

1
该解决方案的问题在于,因为pre_sign_url每次都会更改,所以即使packages.json文件没有更改,也无法缓存npm安装。最好在build.sh中获取密钥并将其设置为构建参数,以使其每次都不更改
York Yang


3

此处详细概述了SSH在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应用程序),从环境访问公共密钥。

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

其他资源:


3

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

第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}

然后从构建脚本传递args,如下所示:

docker-compose build --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)"

为了安全起见,请卸下中间容器。 这将帮助您加油。


2

一个简单而安全的方法,无需将密钥保存在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" ]

1

我正在尝试以其他方式解决该问题:将公共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

该URL现在似乎已断开。
slm 2014年

这是过时的或不正确的。可以复制任何一个方向,最新版本为1.8.2。
乔纳森·莱因哈特

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目录(保存authorised_keys),然后打开ssh端口,该端口可通过主机上的端口7001进行访问。

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

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


1

坦率地说,晚了,如何处理这将使您的主机操作系统密钥可以在根目录下即时在容器内:

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

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


0

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

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

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

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


0

就我而言,我在远程存储库中遇到了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

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


1
然后什么?此后您将无法执行任何操作,因为您无权执行此操作。
乔纳森·莱因哈特

-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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.