出品丨Docker公司(ID:docker-cn)
编译丨小东
每周一、三、五晚6点10分 与您不见不散
前情回顾
创建安全的镜像供应链至关重要。每个组织都需要权衡所有可用选项并了解安全风险。可供选择的镜像过多大大增加了挑选难度。归根结底,每个组织都需要了解所有镜像的来源,即使它是来自于 store.docker.com 中的可信认的上游镜像时也是如此。将镜像导入基础架构后,很有必要进行漏洞扫描。而带镜像扫描功能的 Docker Trusted Registry 提供了深入了解漏洞的能力。最后,整个过程需要实现自动化以提供简单的审核线索,点击以下标题,回顾第一部分内容:
镜像提升策略
Docker Trusted Registry 2.3.0 发行版中添加了新的提升镜像的方法。您可以基于漏洞的阈值、标签匹配、软件包名称乃至许可证创建提升策略。它在自动化镜像流中发挥巨大作用。它也可以确保与策略不匹配的镜像无法进入生产环境。条件如下:
标签名称
软件包名称
所有漏洞
关键漏洞
重大漏洞
微小漏洞
所有许可证
您可创建策略并从源或目标进行查看。下面是所有漏洞的示例。它设置了在有零个漏洞时将 admin/flask_build 镜像仓库“提升”到 admin/flask 的提升策略。
首先,浏览至源镜像仓库,然后转至策略选项卡。从该选项卡中,选择新提升策略。在左侧,选择所有漏洞。然后单击小于或等于,在文本框中输入 0(零),并单击添加。现在,为此提升策略选择目标。在右侧,选择要作为目标的命名空间和镜像。单击保存并应用。应用要对源镜像仓库执行的策略。保存会将策略应用到未来的推送。
请留意目标中的标签名称。此选项提供根据部分变量更改标签的能力。建议您开始时不要更改标签名称。有关更多信息,请查看镜像提升策略文档。
请留意已提升徽章。需要注意的一点是 Notary 签名不随镜像一起提升。这意味着 CI 系统必须对已提升的镜像进行签名。这可通过使用 webhook 和提升策略来完成。
考虑基础镜像从 Jenkins 推送到 DTR 时的 DTR 设置。如果镜像有零个漏洞 — 良好的安全供应链的一部分,那么将扫描并提升它们。这就要说到镜像不可变性了。
镜像不可变性
DTR 2.3.0 和更高版本具有将镜像仓库设置为不可变更的选项。将镜像仓库设置为不可变更意味着标签将无法被覆盖。这是一个很好的功能,可保证基础镜像不会随着时间的推移更改。本示例为 Alpine 基础镜像。理想情况下,CI 将更新基础镜像并将其推送到 DTR(带有特定标签)。具有不可变性可保证无论何时查看特定标签,它都不会更改。可使用镜像提升策略来对此功能进行扩展。
镜像不可变性 + 提升策略
对不可变更的标签使用提升策略的一个很好的示例是直接从 Git 构建镜像。本示例使用了简单的 flask 应用。.gitlab-ci.yml具有三个基本步骤:构建、推送、删除。将启用了不可变性的 DTR 镜像仓库 dtr.example.com/admin/flask_build推送到私有镜像仓库。
GitLab 推送时使用构建号作为标签。格式类似于:dtr.example.com/admin/flask_build:66.由于启用了不可变性,无法覆盖标签 66。这将奠定牢固的基础。接下来,基于相同的阈值添加两个提升策略。第一个策略将镜像提升到公有镜像仓库 dtr.example.com/admin/flask,标签不变。第二个策略使用最新的标签进行提升。
结果是将镜像“提升”了两次。一次使用相同的标签,另一次使用最新的标签。
供应链中的下一个环节是 webhook。
Webhook
从 DTR 2.3.0 开始,可通过 GUI 管理 webhook。DTR 包含用于推送新标签或删除镜像等常见事件的 webhook。这使您可以从自己的 DTR 集群构建复杂的 CI 和 CD 管道。 您可订阅的 webhook 事件如下(特定于镜像仓库):
标签推送
标签删除
清单推送
清单删除
安全扫描已完成
安全扫描失败
从镜像仓库提升的镜像
Webhook 是按镜像仓库创建的。可在 Docker 文档中找到有关 webhook 的更多信息。DTR 也可以呈现 API,方法是浏览至右上方登录下面的菜单,然后选择 API 文档。
本示例是使用 dtr.example.com/admin/flask_build 镜像仓库的前一个示例的后续部分。现在,添加 webhook。要使用“从镜像仓库提升的镜像”事件添加,必须将 webhook 配置为可通知 GitLab 使用 Notary 以及对镜像进行签名。
为了提供参考,我们使用的 WEBHOOK URL 是http://gitlab.example.com/api/v4/projects/<^><PROJECT><^^>/trigger/pipeline?token=<^><TOKEN><^^>&ref=<^><REF><^^>。此处所需的三个字段为 <^><^^>、<^><^^>和 <^><^^>。<^><^^>应设置为分支名称。<^><^^> 应设置为您从 GitLab 获取的令牌。<^><^^> 可从触发器创建页面获取。可在[触发器](#gitlab-触发器)部分找到有关触发器的更多详细信息。webhook 和触发器的优势是它们可以启动新作业,与镜像签名相似。
Content Trust/镜像签名 — Notary
Notary 是可用来发布和管理可信的内容集合的工具。发布者可对集合进行数字签名,使用者可以验证内容的完整性和来源。此功能基于简单的密钥管理和签名界面构建,可创建经过签名的集合及配置受信任的发布者。
Docker Content Trust/Notary 为每个镜像提供了加密签名。签名提供了安全性,因此您获取的正是您期望的镜像。如果您对保护 Notary 安全的方式感兴趣,请参阅 Notary 的架构。由于 Docker EE 在“默认情况下是安全的”,Docker Trusted Registry 随附开箱即用的 Notary 服务器。
成功签名的镜像在 DTR GUI 中具有绿色的勾号标志。
使用 GitLab 签名
随着团队不断壮大,管理所有开发者密钥也变得越来越困难。可用来减轻管理负荷的方法之一是禁止开发者对镜像进行签名。使用 GitLab 来对即将用于生产环境的所有镜像进行签名可省去大部分密钥管理工作。但仍需要对 GitLab 服务器上的密钥进行保护和备份。
第一步是为您的 CI 系统创建用户帐户。例如,假设您使用的 CI 系统是 GitLab。浏览至 DTR 的 Web 界面。以管理员用户身份浏览至组织,然后选择新组织。将新组织命名为 ci。现在,添加 Jenkins 用户,方法是浏览至“组织”并选择添加用户。创建名为 gitlab 的用户并设置强密码。此操作将创建用户并将其添加到 ci 组织。接下来,向 GitLab 用户授予组织管理员身份,以使用户可以管理 ci 组织下的镜像仓库。再接下来,浏览至 UCP 的用户管理。在 ci 组织下创建名为 gitlab 的团队。
现在团队就设置好了,需要启用策略实施。浏览至管理员设置,然后选择 Docker Content Trust 部分。选中仅运行已签署的镜像复选框以启用 Docker Content Trust。在出现的选择框中,选择刚才创建的 ci 团队。保存设置。
此策略要求 docker pull、docker run 或 docker service create 中引用的每个镜像均由与该 gitlab 团队的成员对应的密钥签名。在此示例中,唯一的成员是用户 gitlab。
签名策略实施使用用户客户端证书包中颁发的证书将签名与用户相关联。使用无痕浏览器窗口(或以其他方式)登录您先前创建的用户帐户 gitlab。为此用户下载一个客户端证书包。此外,还建议您更改与 UCP 中存储的公钥相关联的说明,以便您将来能够识别用于签名的是哪个密钥。
请注意,每次用户检索新的客户端证书包时,均会生成一个新的密钥对。因此,有必要对用户选择指定为其签名证书包的特定证书包进行跟踪。
解压缩客户端证书包后,只需要将两个文件用于签名,cert.pem 和 key.pem。它们分别代表了用户的签名身份的公用和私有部分。将 key.pem 文件加载到 Jenkins 服务器,并使用 cert.pem 在 Trusted Collection 中为用户 gitlab 创建委派。
在 GitLab 服务器上,填充本地 /root/.docker/ 目录,然后初始化该 notary 镜像仓库。在 gitlab 服务器上,执行以下操作:
#become root
sudo -i
#change to the /root directory
cd /root
#make directory for CA
mkdir -p /root/.docker/tls/dtr.example.com/
#copy CA to the notary/docker location
curl -sk https://dtr.example.com/ca -o /root/.docker/tls/dtr.example.com/ca.crt
#get the notary client
wget https://github.com/docker/notary/releases/download/v0.4.3/notary-Linux-amd64
#chmod it
chmod 755 notary
#setup alias
alias notary="notary -s https://dtr.example.com --tlscacert /root/.docker/tls/dtr.example.com/ca.crt -d ~/.docker/trust"
#check notary
./notary key list
#init the repository.Make all the passwords the same to simplify things.
notary init -p dtr.example.com/admin/flask
# rotate snapshot key
notary key rotate dtr.example.com/admin/flask -r snapshot
# setup releases role
notary delegation add dtr.example.com/admin/flask targets/releases cert.pem --all-paths
# setup user role
notary delegation add dtr.example.com/admin/flask targets/gitlab cert.pem --all-paths
# publish changes
notary publish dtr.example.com/admin/flask
要启用自动签名,需要在 GitLab 项目中配置与“构建描述”变量相似的 DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE 变量。接下来,创建用于签名的 GitLab 项目。使用下面的 .gitlab-ci.yml 创建新项目。此项目使用本地 /root/.docker/trust 目录。
# Official docker image.
variables:
DOCKER_DRIVER: overlay2
image: docker:latest
before_script:
- docker login -u <^>$DTR_USERNAME<^^> -p <^>$DTR_PASSWORD<^^> <^>$DTR_SERVER<^^>
stages:
- signer
signer:
stage: signer
script:
- docker pull <^>$DTR_SERVER<^^>/admin/flask:latest
- export DOCKER_CONTENT_TRUST=1
- docker push <^>$DTR_SERVER<^^>/admin/flask:latest
- docker rmi <^>$DTR_SERVER<^^>/admin/flask:latest
签名项目的成功输出应类似于下面的截图:
现在,最后的几个步骤是为镜像签名项目创建管道触发器。使用带有“从镜像仓库提升的镜像”事件的 webhook。
总 结
实现自动化的 安全供应链 并没有那么困难。遵循本参考架构就可设置带有至少两个项目的 GitLab。一个项目针对代码、Dockerfile 和应用栈 yaml。另一个项目针对镜像签名组件。DTR 也具有两个镜像仓库。一个针对私有构建,另一个针对经过签名的已提升的镜像。
主要目标是构建一个已提升的(基于全面扫描)和经过签名的镜像(带有 Notary)(通过自动方式)。
虽然介绍了特定的工具,但是本参考架构有几个关键点:
自动化一切
挑选已知可靠源头
利用镜像扫描和提升
对镜像进行签名
任何人都不得将构建或部署直接投入生产的代码!
下面是工作流回顾。
仔细分析一下这些观念,可以使用组织拥有的工具来替换个别工具。
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/37d3721dfa90996719b9a52786a482d1.png)
点击下列标题,阅读更多干货
如果本文对你有帮助,欢迎分享到朋友圈!获取更多Docker实用技巧,扫描下图二维码!