在Docker Compose中构建时的安全秘密

Python Web Developer课程开始之前准备了文章的翻译




构建Docker映像时,您可能需要一些秘密,例如私有软件包存储库的密码。您不希望这个秘密出现在图像中,因为这样,任何有权访问该图像的人都可以访问您的私有存储库。
注意:如果您认为“为什么不只使用环境变量?”,则在创建映像时将其用于运行时的机密。本文重点介绍在使用Docker文件创建映像时使用的构建机密。
较新版本的Docker使用实验性BuildKit服务维护秘密,在Docker Compose 1.25及更高版本中,您已经可以使用BuildKit创建映像。不幸的是,截至2020年3月,仍在开发安全处理Compose机密​​的功能

那么现在该怎么办?

在今天的文章中,我将展示如何使用相同的Dockerfile安全地创建秘密映像,而又不会失去使用Docker Compose进行快速开发的好处。

使用dockerfile的两个选项


在Docker Compose中使用相同的Dockerfile进行生产和本地开发非常方便。通常,您将Dockerfile与Compose的构建功能一起使用:

version: "3.7"
services:
  yourapp:
    build:
      context: "."	

然后,您可以执行以下操作:

$ docker-compose up

使用此命令,您可以(重新)组装映像,然后运行它。
为了在生产中使用,您可以收集图像并通过push发送

$ docker build -t myimage .
$ docker push myimage

一切顺利。但是,如果您需要秘密构建该怎么办?

第一次尝试(不安全)


假设您有一个需要秘密构建的脚本,例如,从私有DevPI存储库中下载Python软件包为简单起见,我们将在帮助下简单地推导出秘密,use-secret.sh以表明我们拥有该秘密

#!/bin/bash
set -euo pipefail

echo "Secret is: $THEPASSWORD"

您可以简单地使用Docker构建参数传递秘密,因为它在Docker Compose中得到了广泛支持。
注意:超出我们讨论的范围,我想说的是,在本文中使用Docker文件不是最佳实践,但是,过于复杂可能会干扰传达本文的主要含义。
因此,如果要在使用Docker的生产环境中运行Python应用程序,可以采用以下两种好的方法:


FROM python:3.8-slim-buster
# Using ARG for build secrets is INSECURE!
ARG THEPASSWORD
COPY use_secret.sh .
RUN ./use_secret.sh

我们可以编写docker-compose.yml,它将秘密传输:

version: "3.7"
services:
  yourapp:
    build:
      context: "."
      args:
        THEPASSWORD: "s3kr!t"

对于本地工作,可以使用Compose运行或构建映像:

$ docker-compose build | grep Secret
Secret is: s3kr!t

一切都很好。

我们还可以使用Docker组装映像,以准备将其移至映像注册表:

$ docker build -t myimage --build-arg THEPASSWORD=s3krit . | grep Secret
Secret is: s3krit

这样做是不安全的:永远不要这样做如果我们决定查看图像的各个层,就会发现其中隐藏着秘密!

$ docker history myimage
IMAGE               CREATED              CREATED BY                                      SIZE
c224231ec30b        47 seconds ago       |1 THEPASSWORD=s3krit /bin/sh -c ./use_secre…   0B
6aef62acf0db        48 seconds ago       /bin/sh -c #(nop) COPY file:7aa28bbe6595e0d5…   62B
f88b19ca8e65        About a minute ago   /bin/sh -c #(nop)  ARG THEPASSWORD              0B
...

有权访问该图像的任何人都可以识别您的密码。那该怎么办呢?

BuildKit的秘密(部分解决方案)


BuildKit是用于创建Docker映像的新的(仍在试验中)解决方案,除其他外,它还增加了在组装过程中安全使用机密的支持Docker Compose自v1.25起提供了BuildKit支持。

但是有一个问题:Docker Compose仍然不支持BuildKit secrets功能。现在对此工作正在进行中,但是截至2020年3月,还没有现成的解决方案,更不用说一个稳定的版本了。

因此,我们将结合这两种方法:

  • Docker Compose将继续使用构建参数来传递秘密。
  • 对于使用docker build构建的生产映像,我们使用BuildKit传递秘密。

这样,我们可以使用相同的Dockerfile在本地和生产环境中工作。
BuildKit可以按以下方式使用机密:带有机密的文件在执行RUN命令时会挂载在一个临时目录中,例如/var/secrets/thepassword由于它是在执行RUN命令期间安装的,因此不会将其添加到最终映像中。

我们将修改文件use_secret.sh以检查是否存在这样的临时文件。如果存在,它将使用其环境变量设置$THEPASSWORD如果文件不存在,那么我们将返回到环境变量。也就是说,$THEPASSWORD可以使用BuildKit或build参数安装

#!/bin/bash
set -euo pipefail
if [ -f /run/secrets/thepassword ]; then
   export THEPASSWORD=$(cat /run/secrets/thepassword)
fi

echo "Secret is: $THEPASSWORD"

然后,我们将修改Dockerfile以添加BuildKit并安装秘密:

# syntax = docker/dockerfile:1.0-experimental
FROM python:3.8-slim-buster
# Only use the build arg for local development:
ARG THEPASSWORD
COPY use_secret.sh .
# Mount the secret to /run/secrets:
RUN --mount=type=secret,id=thepassword ./use_secret.sh

docker-compose.yml我们不更改 文件

version: "3.7"
services:
  yourapp:
    build:
      context: "."
      args:
        THEPASSWORD: "s3kr!t"

现在,您需要定义两个环境变量,其中一个将告诉Docker您需要使用BuildKit,第二个环境是Compose需要使用Docker的CLI版本以及BuildKit。我们还将把机密写入文件:

$ export DOCKER_BUILDKIT=1
$ export COMPOSE_DOCKER_CLI_BUILD=1
$ echo 's3krit' > /tmp/mypassword

对于Compose,我们使用build参数:

$ docker-compose build --progress=plain \
    --no-cache 2>&1 | grep Secret
#12 0.347 Secret is: s3kr!t

请注意,--no-cache如果您自己执行上述所有操作,必须了解该映像将真正重建。在现实生活中,可以省略此参数。2>&1重定向stderrstdout正确的操作grep

当我们准备在生产环境上进行构建时,我们使用具有BuildKit秘密功能的docker build:

$ docker build --no-cache -t myimage \
    --secret id=thepassword,src=/tmp/mypassword \
    --progress=plain . 2>&1 | grep Secret
#12 0.359 Secret is: s3krit

安全吗?


让我们确保秘密不可见:

$ docker history myimage
IMAGE               CREATED             CREATED BY                                      SIZE
a77f3c32b723        25 seconds ago      RUN |1 THEPASSWORD= /bin/sh -c ./use_secret.…   0B
<missing>           25 seconds ago      COPY use_secret.sh . # buildkit                 160B
...

万岁!我们使用Compose和将秘密传递给了相同的Dockerfile docker build,在后一种情况下并未从程序集中揭示秘密。



了解有关该课程的更多信息。



All Articles