构建和转发SSH到Docker的秘密09/18

图片

使用Dockerfile,一直很难访问私有资源。 根本没有好的解决方案。 使用环境变量或仅在使用后删除秘密文件是不好的:它们保留在图像元数据中。 用户有时会花样:他们创建了多阶段程序集,但是,必须格外小心,以确保在最后阶段没有机密值,并且机密文件会存储在本地程序集缓存中,直到剪切为止。


Docker构建团队于9月18日发布了许多更新。 主要功能是出现了服务器部分实现的全新版本;它是Moby BuildKit项目的一部分。 BuildKit服务器应用程序已获得新功能,包括对Dockerfile构建机密的支持。


使用秘密


首先,您需要启用BuildKit服务器端。 版本18.09中的BuildKit是一个选择功能,可以在启动DOCKER_BUILDKIT=1 docker build之前使用DOCKER_BUILDKIT=1环境变量启用它。 在下一版本中,计划默认使BuildKit作为服务器部分。


 export DOCKER_BUILDKIT=1 

实现构建机密基于两个新的BuildKit功能。 其中之一是能够使用从注册表中的图像加载的用户界面。 第二个是在Dockerfile的RUN命令中使用挂载点的功能。 要使用支持秘密的实现功能(而不是标准的实现功能),请在Dockerfile第一行中使用语法指令定义链接器映像-指示要使用的容器的映像。 到目前为止,外部Dockerfile的稳定通道中的秘密尚不可用:您将需要实验通道中的版本之一,例如docker/dockerfile:experimentaldocker/dockerfile/1.0.0-experimental


 # syntax=docker/dockerfile:1.0.0-experimental 

如果作为Dockerfile的作者,您知道安装在Dockerfile中的RUN命令需要一个秘密值,请使用--mount标签,以指示该命令需要哪个秘密以及将其安装在何处。 --mount标签接受--mount逗号分隔的结构。


 # syntax=docker/dockerfile:1.0.0-experimental FROM alpine RUN --mount=type=secret,id=mysite.key command-to-run 

该标签表示在操作过程中,该命令可以通过路径/run/secrets/mysite.key访问秘密文件。 机密仅适用于带有安装标签的团队,而不适用于装配体的其他零件。 该文件中的数据是根据指定的标识符“ mysite.key”从秘密存储区下载的。 Docker命令行界面当前支持使用--secret标记公开本地客户端文件中的--secret


 docker build --secret id=mysite.key,src=path/to/mysite.key . 

如上所述,秘密默认情况下在/run/secrets ,但是,您可以使用“ target”键指定任何路径。 如果指定了“ target”,但未指定“ id”,则默认情况下,“ id”成为目标路径的基本名称。


不必局限于一个秘密。 您可以使用任意数量的它们,表示不同的标识符。


如果Dockerfile的作者指示RUN指令可以使用机密,并且调用程序集的用户未提供该机密,则该机密将被忽略,并且在指定路径上未安装任何文件。 如果不希望出现这种情况,请使用“ required”键:这将指示没有值的组装将失败。


 # syntax=docker/dockerfile:1.0.0-experimental FROM alpine RUN --mount=type=secret,id=mysite.key,required <command-to-run> 

实作


秘密文件仅自动安装在单独的tmpfs文件系统中,以防止最终映像或下一个命令泄漏,从而不会将其存储在本地构建缓存中。


秘密值也从构建缓存计算中排除,因此无法使用元数据缓存。


SSH


大多数情况下,他们可能尝试通过SSH协议访问私有存储库。 是的,您可以使用秘密元素来显示程序集的SSH私钥,但是有更好的解决方案。 SSH协议使用公钥加密,由于采用了这种设计,因此您无需向任何人透露私钥。 例如,如果您使用多台使用SSH的计算机,则无需传输密钥-只需通过ssh-A协议提供连接即可。


我们在--ssh docker build添加了类似的功能,您可以在其中使用--ssh标签将现有的SSH代理连接或密钥定向到链接器。 Docker并没有传输关键信息,而只是告诉链接程序它可用。 如果链接器需要通过SSH访问远程服务器,则他将与客户端联系,并要求确认连接所需的特定请求。 密钥本身不会离开客户端程序,并且在完成需要访问的程序之后,链接器中没有数据可用来重新连接远程连接。


通过SSH协议对文件传输的访问仅授予Dockerfile中直接通过指定type=ssh块请求访问SSH的命令。 其他命令在可用的SSH代理上没有数据。


还值得注意的是SSH的另一个方面-TOFU安全模型的使用。 首次连接SSH服务器时,它将请求有关未知主机的信息,因为它在本地没有可用于此服务器的公钥,因此无法检查远程方提供的公钥对该地址是否有效。


与Dockerfile组装时,无法验证此请求的正确性,因此,尝试使用SSH的容器中必须已经存在服务器的公钥。 有几种获取此公钥的方法。 例如,基础映像将提供它,或者您可以从构建上下文中复制它。 如果您想要一个更简单的解决方案,请运行ssh–keyscan作为程序集的一部分的ssh–keyscan程序–它会加载主机的当前公钥。


要请求SSH访问Dockerfile中的RUN命令,您必须指定一个“ ssh”类型的块。 然后,在此过程中,将安装对SSH代理具有只读访问权限的套接字。 这还将设置SSH_AUTH_SOCK环境变量,以便使用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 our private repository RUN --mount=type=ssh git clone git@github.com:myorg/myproject.git myproject 

在Docker客户端上,使用--ssh标签表示该程序集允许SSH转发。


 docker build --ssh default . 

标签接受一对密钥值,这些密钥值确定本地SSH代理或私钥的套接字位置。 如果要使用default=$SSH_AUTH_SOCK ,则可以将套接字路径保留为空。


在Dockerfile块中,您还可以使用id密钥来分隔同一程序集中的各种服务器。 例如,可以使用不同的部署密钥来访问Dockerfile中的各种存储库。 在这种情况下,您将在Dockerfile中使用:


 … RUN --mount=type=ssh,id=projecta git clone projecta … RUN --mount=type=ssh,id=projectb git clone projectb … 

并使用--ssh projecta=./projecta.pem --ssh projectb=./projectb.pem build --ssh projecta=./projecta.pem --ssh projectb=./projectb.pem扩展客户端数据。 请注意,即使您指定了实际密钥,也只会将代理连接发送到链接器,而不会发送这些私钥的实际内容。


至此,对Docker 18.09中构建密钥的新功能的评论完成了。 我希望这些新功能将有助于在项目中更多地使用Dockerfile的功能,并为装配线提供更高级别的安全性。

Source: https://habr.com/ru/post/zh-CN432682/


All Articles