使用 VEX 创建例外
漏洞可利用性交换 (VEX) 是一个标准格式,用于在软件包或产品的上下文中记录漏洞。Docker Scout 支持 VEX 文档,以便为镜像中的漏洞创建例外。
注意
您还可以使用 Docker Scout 仪表板或 Docker Desktop 创建例外。GUI 提供了一个用户友好的界面来创建例外,并且可以轻松管理多个镜像的例外。它还允许您一次为多个镜像或整个组织创建例外。更多信息,请参阅使用 GUI 创建例外。
前提条件
要使用 OpenVEX 文档创建例外,您需要
- 最新版本的 Docker Desktop 或 Docker Scout CLI 插件
vexctl
命令行工具。- containerd 镜像存储必须启用
- 对存储镜像的注册表仓库具有写入权限
VEX 介绍
VEX 标准由美国网络安全和基础设施安全局 (CISA) 的工作组定义。VEX 的核心是可利用性评估。这些评估描述了产品中给定 CVE 的状态。VEX 中可能的漏洞状态有
- 不受影响:不需要对该漏洞进行任何修复。
- 受影响:建议采取措施修复或解决该漏洞。
- 已修复:这些产品版本包含该漏洞的修复。
- 调查中:尚不确定这些产品版本是否受该漏洞影响。将在后续版本中提供更新。
VEX 有多种实现和格式。Docker Scout 支持 OpenVex 实现。无论具体实现如何,核心思想是一致的:提供一个框架来描述漏洞的影响。无论实现如何,VEX 的关键组件包括
- VEX 文档
- 一种安全公告,用于存储 VEX 声明。文档的格式取决于具体实现。
- VEX 声明
- 描述产品中漏洞的状态,是否可利用,以及是否有方法修复该问题。
- 理由和影响
- 根据漏洞状态,声明包含理由或影响声明,描述为什么产品受或不受影响。
- 行动声明
- 描述如何修复或减轻漏洞。
vexctl
示例
以下示例命令创建一个 VEX 文档,说明:
- 此 VEX 文档描述的软件产品是 Docker 镜像
example/app:v1
- 镜像包含 npm 包
express@4.17.1
- npm 包受已知漏洞
CVE-2022-24999
影响 - 镜像不受该 CVE 影响,因为在此镜像运行的容器中,易受攻击的代码从未被执行
$ vexctl create \
--author="author@example.com" \
--product="pkg:docker/example/app@v1" \
--subcomponents="pkg:npm/express@4.17.1" \
--vuln="CVE-2022-24999" \
--status="not_affected" \
--justification="vulnerable_code_not_in_execute_path" \
--file="CVE-2022-24999.vex.json"
以下是此示例中选项的说明
--author
- VEX 文档作者的电子邮件。
--product
- Docker 镜像的包 URL (PURL)。PURL 是一种标准化格式的镜像标识符,在 PURL 规范中定义。
Docker 镜像 PURL 字符串以
pkg:docker
类型前缀开头,后跟镜像仓库和版本(镜像标签或 SHA256 摘要)。与镜像标签(其中版本指定方式如example/app:v1
)不同,在 PURL 中,镜像仓库和版本由@
分隔。 --subcomponents
- 镜像中易受攻击包的 PURL。在此示例中,漏洞存在于 npm 包中,因此
--subcomponents
PURL 是 npm 包名称和版本的标识符 (pkg:npm/express@4.17.1
)。如果同一个漏洞存在于多个包中,
vexctl
允许您在单个create
命令中多次指定--subcomponents
标志。您也可以省略
--subcomponents
,在这种情况下 VEX 声明将适用于整个镜像。 --vuln
- VEX 声明针对的 CVE ID。
--status
- 这是漏洞的状态标签。这描述了软件(
--product
)和 CVE(--vuln
)之间的关系。OpenVEX 中状态标签的可能值有not_affected
affected
fixed
under_investigation
在此示例中,VEX 声明断言 Docker 镜像不受该漏洞影响 (
not_affected
)。not_affected
状态是唯一导致 CVE 抑制(即 CVE 从分析结果中过滤掉)的状态。其他状态对于文档记录很有用,但不能用于创建例外。有关所有可能状态标签的更多信息,请参阅 OpenVEX 规范中的 状态标签。 --justification
- 合理解释
not_affected
状态标签,说明产品为何不受该漏洞影响。在此情况下,给出的理由是vulnerable_code_not_in_execute_path
,表明该漏洞无法在该产品的使用场景下被执行。在 OpenVEX 中,状态理由可以有以下五种可能值
component_not_present
vulnerable_code_not_present
vulnerable_code_not_in_execute_path
vulnerable_code_cannot_be_controlled_by_adversary
inline_mitigations_already_exist
有关这些值及其定义的更多信息,请参阅 OpenVEX 规范中的 状态理由。
--file
- VEX 文档输出的文件名
JSON 文档示例
这是此命令生成的 OpenVEX JSON
{
"@context": "https://openvex.dev/ns/v0.2.0",
"@id": "https://openvex.dev/docs/public/vex-749f79b50f5f2f0f07747c2de9f1239b37c2bda663579f87a35e5f0fdfc13de5",
"author": "author@example.com",
"timestamp": "2024-05-27T13:20:22.395824+02:00",
"version": 1,
"statements": [
{
"vulnerability": {
"name": "CVE-2022-24999"
},
"timestamp": "2024-05-27T13:20:22.395829+02:00",
"products": [
{
"@id": "pkg:docker/example/app@v1",
"subcomponents": [
{
"@id": "pkg:npm/express@4.17.1"
}
]
}
],
"status": "not_affected",
"justification": "vulnerable_code_not_in_execute_path"
}
]
}
理解 VEX 文档应该如何结构化可能有些费力。 OpenVEX 规范描述了文档和声明的格式以及所有可能的属性。有关完整详情,请参阅该规范,了解有关可用字段以及如何创建结构良好的 OpenVEX 文档的更多信息。
要了解有关 vexctl
CLI 工具的可用标志和语法以及如何安装它,请参阅 vexctl
GitHub 仓库。
验证 VEX 文档
要测试您创建的 VEX 文档是否结构良好并产生预期结果,请使用带有 `--vex-location` 标志的 `docker scout cves` 命令,以便使用 CLI 将 VEX 文档应用于本地镜像分析。
以下命令调用本地镜像分析,该分析使用 `--vex-location` 标志,并包含指定位置中的所有 VEX 文档。在此示例中,CLI 被指示在当前工作目录中查找 VEX 文档。
$ docker scout cves <IMAGE> --vex-location .
docker scout cves
命令的输出会显示结果,其中考虑了在 `--vex-location` 位置下找到的任何 VEX 声明。例如,状态被标记为 not_affected
的 CVE 会从结果中过滤掉。如果输出似乎没有考虑 VEX 声明,这表明 VEX 文档可能以某种方式无效。
需要注意的事项包括
- Docker 镜像的 PURL 必须以
pkg:docker/
开头,后跟镜像名称。 - 在 Docker 镜像 PURL 中,镜像名称和版本由
@
分隔。名为example/myapp:1.0
的镜像具有以下 PURL:pkg:docker/example/myapp@1.0
。 - 记得指定
author
(这是 OpenVEX 中的必填字段) - OpenVEX 规范描述了如何以及何时在 VEX 文档中使用
justification
、impact_statement
和其他字段。以不正确的方式指定这些字段会导致文档无效。请确保您的 VEX 文档符合 OpenVEX 规范。
将 VEX 文档附加到镜像
当您创建了 VEX 文档后,可以通过以下方式将其附加到您的镜像
VEX 文档一旦添加到镜像就无法移除。对于作为证明附加的文档,您可以创建一个新的 VEX 文档并再次将其附加到镜像。这样做会覆盖之前的 VEX 文档(但不会移除证明本身)。对于 VEX 文档已嵌入镜像文件系统的镜像,您需要重建镜像才能更改 VEX 文档。
证明
要将 VEX 文档作为证明附加,您可以使用 `docker scout attestation add` CLI 命令。使用证明是将例外附加到镜像时的推荐选项。
您可以将证明附加到已推送到注册表的镜像。您不需要再次构建或推送镜像。此外,将例外作为证明附加到镜像意味着使用者可以直接从注册表检查镜像的例外。
将证明附加到镜像
构建镜像并将其推送到注册表。
$ docker build --provenance=true --sbom=true --tag <IMAGE> --push .
将例外作为证明附加到镜像。
$ docker scout attestation add \ --file <cve-id>.vex.json \ --predicate-type https://openvex.dev/ns/v0.2.0 \ <IMAGE>
此命令的选项包括
--file
:VEX 文档的位置和文件名--predicate-type
:OpenVEX 的 in-totopredicateType
镜像文件系统
将 VEX 文档直接嵌入到镜像文件系统中是个不错的选择,如果您在构建镜像之前就已经知道这些异常。这相对来说也很简单;只需在 Dockerfile 中使用 COPY
命令将 VEX 文档复制到镜像中即可。
这种方法的缺点是您以后无法更改或更新异常。镜像层是不可变的,因此您放入镜像文件系统中的任何内容都会永久存在。将文档作为证明附加则提供了更好的灵活性。
注意
对于包含证明的镜像,嵌入在镜像文件系统中的 VEX 文档将不被考虑。如果您的镜像包含任何证明,Docker Scout 将仅在证明中查找异常,而不会在镜像文件系统中查找。
如果您想使用嵌入在镜像文件系统中的 VEX 文档,则必须从镜像中移除证明。请注意,镜像可能会自动添加来源(provenance)证明。为确保镜像不添加任何证明,您可以在构建镜像时使用
--provenance=false
和--sbom=false
标志明确禁用 SBOM 和来源证明。
要将 VEX 文档嵌入到镜像文件系统中,请在镜像构建过程中使用 COPY
命令将文件复制到镜像中。以下示例展示了如何将构建上下文中的 .vex/
目录下的所有 VEX 文档复制到镜像中的 /var/lib/db
目录。
# syntax=docker/dockerfile:1
FROM alpine
COPY .vex/* /var/lib/db/
VEX 文档的文件名必须匹配 *.vex.json
的全局模式。文件存储在镜像文件系统中的任何位置都可以。
请注意,复制的文件必须是最终镜像文件系统的一部分。对于多阶段构建,文档必须在最终阶段中保留。