如何使用 Docker 与 Kaniko 构建 Secret

tre*_*ong 9 gitlab-ci docker-secrets docker-in-docker kaniko docker-buildkit

语境

我们当前的构建系统在 docker 容器(Docker in Docker)内构建 docker 镜像。我们的许多 Docker 构建都需要凭据才能从私有工件存储库中提取。

我们已经使用 docker Secrets 处理了这个问题。将秘密传递给 docker build 命令,并在 Dockerfile 中,在需要的地方引用 RUN 命令中的秘密。这意味着我们正在使用 docker buildkit。 本文对此进行了解释。

我们正在迁移到不同的构建系统(GitLab),并且管理员已在 Docker 中禁用 Docker(安全原因),因此我们将迁移到Kaniko进行 docker 构建。

问题

Kaniko 似乎不像 docker 那样支持秘密。(没有命令行选项可以通过 Kaniko 执行器传递秘密)。

docker 构建所需的凭据存储在 GitLab 变量中。对于 DinD,您只需将这些变量作为秘密添加到 docker 构建中:

DOCKER_BUILDKIT=1 docker build . \
   --secret=type=env,id=USERNAME \
   --secret=type=env,id=PASSWORD \
Run Code Online (Sandbox Code Playgroud)

然后在 docker 中,使用秘密:

RUN --mount=type=secret,id=USERNAME --mount=type=secret,id=PASSWORD \
   USER=$(cat /run/secrets/USERNAME) \
    PASS=$(cat /run/secrets/PASSWORD) \
     ./scriptThatUsesTheseEnvVarCredentialsToPullArtifacts
...rest of build..
Run Code Online (Sandbox Code Playgroud)

如果没有 kaniko 执行器的 --secret 标志,我不确定如何利用 docker 秘密......我也不了解替代方案。我也想继续支持开发者构建。我们有一个“build.sh”脚本,负责收集凭据并将其添加到 docker build 命令中。

目前的解决方案

我找到了这篇文章并找到了一个可行的解决方案。我想请教专家,这是否有效,或者有什么替代方案。

我发现当 kaniko 执行器运行时,它似乎将一个卷安装到正在构建的映像中:/kaniko。构建完成后该目录不存在,并且似乎没有缓存在 docker 层中。

我还发现,如果没有通过 docker build 命令传入 Dockerfile 密钥,构建仍然会执行。

所以我的 gitlab-ci.yml 文件有以下摘录(REPO_USER/REPO_PWD 变量是 GitLab CI 变量):

- echo "${REPO_USER}" > /kaniko/repo-credentials.txt
- echo "${REPO_PWD}" >> /kaniko/repo-credentials.txt
- /kaniko/executor
  --context "${CI_PROJECT_DIR}/docker/target"
  --dockerfile "${CI_PROJECT_DIR}/docker/target/Dockerfile"
  --destination "${IMAGE_NAME}:${BUILD_TAG}"
Run Code Online (Sandbox Code Playgroud)

这里的关键部分是在调用执行器之前将凭据回显到 /kaniko 目录中的文件。该目录(暂时)安装到执行器正在构建的映像中。由于所有这些都发生在 kaniko 映像内部,因此当 kaniko (gitlab) 作业完成时,该文件将消失。

开发人员构建脚本(片段):

//to keep it simple, this assumes that the developer has their credentials//cached in a file (ignored by git) called dev-credentials.txt

DOCKER_BUILDKIT=1 docker build . \
   --secret id=repo-creds,src=dev-credentials.txt
Run Code Online (Sandbox Code Playgroud)

基本上和以前一样。必须将其放入文件而不是环境变量中。

dockerfile(片段):

RUN --mount=type=secret,id=repo-creds,target=/kaniko/repo-credentials.txt USER=$(sed '1q;d' /kaniko/repo-credentials.txt) PASS=$(sed '2q;d' /kaniko/repo-credentials.txt) ./scriptThatUsesTheseEnvVarCredentialsToPullArtifacts...rest of build..
Run Code Online (Sandbox Code Playgroud)

这有效!

在 Dockerfile 中,通过将密钥安装在 /kaniko 子文件夹中,它将与 DinD 开发人员构建以及 CI Kaniko 执行程序一起使用。

对于开发版本,DinD 秘密一如既往地工作。(必须将其更改为文件而不是我不喜欢的环境变量。)

构建由 Kaniko 运行时,我想由于未找到 RUN 命令中的秘密,它甚至不会尝试写入临时凭证文件(我预计这会使构建失败)。相反,因为我直接将变量写入临时安装的 /kaniko 目录,所以其余的运行命令很高兴。

建议

对我来说,这确实比预期的更糟糕。我想找出其他/替代解决方案。发现 /kaniko 文件夹在构建时已安装到映像中似乎打开了很多可能性。

Lar*_*Cai 2

问题已经包含了答案,我只是尝试显示完整的代码以供用户直接选择

$ cat Dockerfile 
# podman build --secret id=mysecret,src=./secret.txt .
# /kaniko/executor --context . --dockerfile Dockerfile --no-push
FROM alpine
RUN --mount=type=secret,id=netrc \
    cp /kaniko/netrc $HOME/.netrc || cp /run/secrets/netrc $HOME/.netrc \
    && cat $HOME/.netrc \
    && echo "now can run some scripts" \
    && rm $HOME/.netrc
RUN ls $HOME/.netrc || true
Run Code Online (Sandbox Code Playgroud)

如果你使用podman/ ,buildah你可以注入秘密并/run/secrets/netrc在里面使用,它不会存在于最终图像中

$ podman build --secret id=netrc,src=./secret.txt .
STEP 1/3: FROM alpine
STEP 2/3: RUN --mount=type=secret,id=netrc     cp /kaniko/netrc $HOME/.netrc || cp /run/secrets/netrc $HOME/.netrc     && cat $HOME/.netrc     && echo "now can run some scripts"     && rm $HOME/.netrc
cp: can't stat '/kaniko/netrc': No such file or directory
top secrets
now can run some scripts
--> 880d646a021
STEP 3/3: RUN ls $HOME/.netrc || true
ls: /root/.netrc: No such file or directory
COMMIT
--> 64a8b99ba19
64a8b99ba198d088f7cc678f160e29f5eae6ee90ff81dda2e292c55601cf4eb2
Run Code Online (Sandbox Code Playgroud)

对于 kaniko,/kaniko是用于此目的的文件夹

/workspace # cat /kaniko/netrc
top secret!
/workspace # /kaniko/executor --context . --dockerfile Dockerfile  --no-push
INFO[0000] Retrieving image manifest alpine 
...
INFO[0002] Unpacking rootfs as cmd RUN --mount=type=secret,id=netrc     cp /kaniko/netrc $HOME/.netrc || cp /run/secrets/netrc $HOME/.netrc     && cat $HOME/.netrc     && echo "now can run some scripts"     && rm $HOME/.netrc requires it. 
INFO[0002] RUN --mount=type=secret,id=netrc     cp /kaniko/netrc $HOME/.netrc || cp /run/secrets/netrc $HOME/.netrc     && cat $HOME/.netrc     && echo "now can run some scripts"     && rm $HOME/.netrc 
INFO[0002] Initializing snapshotter ...                 
INFO[0002] Taking snapshot of full filesystem...        
INFO[0002] Cmd: /bin/sh                                 
INFO[0002] Args: [-c cp /kaniko/netrc $HOME/.netrc || cp /run/secrets/netrc $HOME/.netrc     && cat $HOME/.netrc     && echo "now can run some scripts"     && rm $HOME/.netrc] 
INFO[0002] Running: [/bin/sh -c cp /kaniko/netrc $HOME/.netrc || cp /run/secrets/netrc $HOME/.netrc     && cat $HOME/.netrc     && echo "now can run some scripts"     && rm $HOME/.netrc] 
top secret!
now can run some scripts
INFO[0002] Taking snapshot of full filesystem...        
INFO[0002] RUN ls $HOME/.netrc || true                  
INFO[0002] Cmd: /bin/sh                                 
INFO[0002] Args: [-c ls $HOME/.netrc || true]           
INFO[0002] Running: [/bin/sh -c ls $HOME/.netrc || true] 
ls: /root/.netrc: No such file or directory
INFO[0002] Taking snapshot of full filesystem...        
INFO[0002] No files were changed, appending empty layer to config. No layer added to image. 
Run Code Online (Sandbox Code Playgroud)