Help us learn about your current experience with the documentation. Take the survey.

容器扫描

  • 层级:免费版、高级版、旗舰版
  • 提供:GitLab.com、GitLab 自托管、GitLab 专用

容器镜像中的安全漏洞会在整个应用生命周期中产生风险。容器扫描能在这些风险到达生产环境前尽早检测到它们。当您的基础镜像或操作系统软件包中出现漏洞时,容器扫描会识别这些漏洞,并为可修复的部分提供补救路径。

容器扫描通常被视为软件成分分析(SCA)的一部分。SCA 可能包含检查代码所使用的项目的方面。这些项目通常包括应用程序和系统依赖项,这些依赖项几乎总是从外部来源导入的,而不是来自您自己编写的项目。

GitLab 提供了容器扫描和 依赖扫描,以确保覆盖所有这些依赖类型。为了尽可能多地覆盖您的风险区域,我们鼓励您使用所有安全扫描器。有关这些功能的比较,请参见 依赖扫描与容器扫描对比

GitLab 与 Trivy 安全扫描器集成,以对容器执行漏洞静态分析。

Grype 分析器不再维护,仅按我们的支持声明进行有限修复。现有的 Grype 分析器镜像当前主版本将继续更新最新的公告数据库和操作系统软件包,直到 GitLab 19.0,届时该分析器将停止工作。

## 功能

| 功能                                                                                                                                                                                                          | 在免费版和高级版中                                                                                                                   | 在旗舰版中                                                                                                    |
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
| 自定义设置([变量](#available-cicd-variables)、[覆盖](#overriding-the-container-scanning-template)、[离线环境支持](#running-container-scanning-in-an-offline-environment) 等) | 
 check-circle 
 是                                                                                                  | 
 check-circle 
 是                                                                           |
| 以CI作业工件形式查看[JSON报告](#reports-json-format)                                                                                                                                                     | 
 check-circle 
 是                                                                                                  | 
 check-circle 
 是                                                                           |
| 生成[CycloneDX 软件物料清单JSON报告](#cyclonedx-software-bill-of-materials)作为CI作业工件                                                                                                               | 
 check-circle 
 是                                                                                                  | 
 check-circle 
 是                                                                           |
| 能够在GitLab UI中通过合并请求启用容器扫描                                                                                                                                                   | 
 check-circle 
 是                                                                                                  | 
 check-circle 
 是                                                                           |
| [UBI镜像支持](#fips-enabled-images)                                                                                                                                                                         | 
 check-circle 
 是                                                                                                  | 
 check-circle 
 是                                                                           |
| Trivy支持                                                                                                                                                                                                 | 
 check-circle 
 是                                                                                                  | 
 check-circle 
 是                                                                           |
| [已停止支持的操作系统检测](#end-of-life-operating-system-detection)                                                                                                                                 | 
 check-circle 
 是                                                                                                  | 
 check-circle 
 是                                                                           |
| 包含GitLab安全公告数据库                                                                                                                                                                             | 仅限来自GitLab [advisories-communities](https://gitlab.com/gitlab-org/advisories-community/) 项目的延迟内容 | 是 - 来自[Gemnasium DB](https://gitlab.com/gitlab-org/security-products/gemnasium-db) 的所有最新内容 |

| 在合并请求和安全标签页中展示报告数据(CI 流水线作业) | dotted-circle 未完成 | check-circle 已完成 | | 漏洞解决方案(自动修复) | dotted-circle 未完成 | check-circle 已完成 | | 支持漏洞允许列表 | dotted-circle 未完成 | check-circle 已完成 | | 访问依赖项列表页面 | dotted-circle 未完成 | check-circle 已完成 |

开始使用

在 CI/CD 管道中启用容器扫描分析器。当管道运行时,应用程序所依赖的镜像会被扫描是否存在漏洞。你可以通过 CI/CD 变量来自定义容器扫描。

先决条件:

  • .gitlab-ci.yml 文件中需要有测试阶段。
  • 对于自托管 Runner,你需要一台带有 dockerkubernetes 执行器的 GitLab Runner(运行于 Linux/amd64 平台)。如果你在使用 GitLab.com 的实例 Runner,则该功能会默认启用。
  • 一个匹配 支持发行版 的镜像。
  • 构建并推送 Docker 镜像到项目的容器注册表中。
  • 如果你使用的是第三方容器注册表,你可能需要通过 CS_REGISTRY_USERCS_REGISTRY_PASSWORD 配置变量 提供认证凭证。有关如何使用这些变量的详细信息,请参阅 认证远程注册表

请查看下方详情了解 用户和项目特定要求

若要启用分析器,可选择以下方式之一:

  • 启用 Auto DevOps(其中包含依赖项扫描)。
  • 使用预配置的合并请求。
  • 创建一个 扫描执行策略,强制执行容器扫描。
  • 手动编辑 .gitlab-ci.yml 文件。

使用预配置的合并请求

该方法会自动准备一个合并请求,其中包含 .gitlab-ci.yml 文件中的容器扫描模板。之后你只需合并该请求即可启用依赖项扫描。

这种方法最适合没有现有 .gitlab-ci.yml 文件,或者只有极简配置文件的情况。如果你的 GitLab 配置文件较为复杂,可能会解析失败并报错。在这种情况下,请改用 手动 方法。

启用容器扫描的步骤如下:

  1. 在左侧边栏选择 搜索或前往 并找到你的项目。
  2. 选择 安全 > 安全配置
  3. 容器扫描 行中选择 用合并请求配置
  4. 选择 创建合并请求
  5. 审查合并请求,然后选择 合并

现在管道将包含一个容器扫描任务。

手动编辑 .gitlab-ci.yml 文件

该方法需要你手动编辑现有的 .gitlab-ci.yml 文件。如果你的 GitLab CI/CD 配置文件比较复杂,或者需要使用非默认选项,请采用此方法。

启用容器扫描的步骤如下:

  1. 在左侧边栏选择 搜索或前往 并找到你的项目。

  2. 选择 构建 > 管道编辑器

  3. 如果不存在 .gitlab-ci.yml 文件,请选择 配置管道,然后删除示例内容。

  4. 将以下内容复制粘贴到 .gitlab-ci.yml 文件的末尾。如果已存在 include 行,只需在其下方添加 template 行。

    include:
      - template: Jobs/Container-Scanning.gitlab-ci.yml
  5. 选择 验证 标签页,然后选择 验证管道

    若显示 模拟成功完成,则表明文件有效。

  6. 选择 编辑 标签页。

  7. 填写相关字段。不要将默认分支用作 分支 字段的值。

  8. 勾选 用这些更改创建新合并请求 复选框,然后选择 提交更改

  9. 根据你的标准工作流程填写字段,然后选择 创建合并请求

  10. 按照你的标准工作流程审查并编辑合并请求,等待管道通过后,选择 合并

现在管道将包含一个容器扫描任务。

理解结果

你可以在流水线中查看漏洞:

  1. 在左侧边栏,选择“搜索或前往”并找到你的项目。
  2. 在左侧边栏,选择“构建 > 流水线”。
  3. 选择该流水线。
  4. 选择“安全”选项卡。
  5. 选择一个漏洞以查看其详细信息,包括:
    • 描述:解释漏洞的原因、潜在影响及建议修复步骤。
    • 状态:指示漏洞是否已被分类或解决。
    • 严重性:根据影响程度分为六个级别。了解关于严重性级别的更多信息
    • CVSS 分数:提供与严重性对应的数值。
    • EPSS:显示漏洞在野外被利用的可能性。
    • 有已知利用(KEV):表示给定漏洞已被利用。
    • 项目:突出显示发现漏洞的项目。
    • 报告类型:解释输出类型。
    • 扫描器:识别检测到漏洞的分析器。
    • 镜像:提供与漏洞关联的镜像。
    • 命名空间:识别与漏洞关联的工作区。
    • 链接:漏洞在各种咨询数据库中被编目的证据。
    • 标识符:用于分类漏洞的参考列表,例如 CVE 标识符。

有关更多详情,请参阅流水线安全报告

查看容器扫描结果的额外方式:

推广实施

在对单个项目的容器扫描结果充满信心后,你可以将其实现扩展到其他项目:

支持的发行版

以下 Linux 发行版受支持:

  • Alma Linux
  • Alpine Linux
  • Amazon Linux
  • CentOS
  • CBL-Mariner
  • Debian
  • Distroless
  • Oracle Linux
  • Photon OS
  • Red Hat (RHEL)
  • Rocky Linux
  • SUSE
  • Ubuntu

FIPS 启用镜像

GitLab 还提供FIPS 启用的红帽 UBI版本的容器扫描镜像。因此,你可以将标准镜像替换为 FIPS 启用镜像。若要配置这些镜像,请将 CS_IMAGE_SUFFIX 设置为 -fips,或将 CS_ANALYZER_IMAGE 变量修改为标准标签加上 -fips 后缀。

当 GitLab 实例启用 FIPS 模式时,-fips 标志会自动添加到 CS_ANALYZER_IMAGE 中。

当启用 FIPS 模式时,不支持对认证注册表中的镜像进行容器扫描。当 CI_GITLAB_FIPS_MODE"true" 且设置了 CS_REGISTRY_USERCS_REGISTRY_PASSWORD 时,分析器会退出并报错,不会执行扫描。

配置

自定义分析器行为

若要自定义容器扫描,请使用CI/CD 变量

启用详细输出

当你需要详细了解依赖项扫描作业的执行过程(例如排查问题时),请启用详细输出。

在以下示例中,包含了容器扫描模板并启用了详细输出。

include:
  - template: Jobs/Container-Scanning.gitlab-ci.yml

variables:
    SECURE_LOG_LEVEL: 'debug'

扫描远程注册表中的镜像

若要扫描位于非项目注册表中的镜像,请使用以下 .gitlab-ci.yml

include:
  - template: Jobs/Container-Scanning.gitlab-ci.yml

container_scanning:
  variables:
    CS_IMAGE: example.com/user/image:tag
向远程注册表进行身份验证

扫描私有注册表中的镜像需要身份验证。在 CS_REGISTRY_USER 变量中提供用户名,在 CS_REGISTRY_PASSWORD 配置变量中提供密码。

例如,要扫描来自 AWS Elastic Container Registry 的镜像:

container_scanning:
  before_script:
    - ruby -r open-uri -e "IO.copy_stream(URI.open('https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip'), 'awscliv2.zip')"
    - unzip awscliv2.zip
    - sudo ./aws/install
    - aws --version
    - export AWS_ECR_PASSWORD=$(aws ecr get-login-password --region region)

include:
  - template: Jobs/Container-Scanning.gitlab-ci.yml

variables:
    CS_IMAGE: <aws_account_id>.dkr.ecr.<region>.amazonaws.com/<image>:<tag>
    CS_REGISTRY_USER: AWS
    CS_REGISTRY_PASSWORD: "$AWS_ECR_PASSWORD"
    AWS_DEFAULT_REGION: <region>

当启用 FIPS 模式时,不支持向远程注册表进行身份验证。

报告语言特定的发现

CI/CD 变量 CS_DISABLE_LANGUAGE_VULNERABILITY_SCAN 控制扫描是否报告与编程语言相关的发现。有关支持语言的更多信息,请参阅 Trivy 文档中的 Language-specific Packages

默认情况下,报告仅包含由操作系统(OS)包管理器(例如 yumaptapktdnf)管理的软件包。若要报告非 OS 软件包中的安全发现,需将 CS_DISABLE_LANGUAGE_VULNERABILITY_SCAN 设为 "false"

include:
  - template: Jobs/Container-Scanning.gitlab-ci.yml

container_scanning:
  variables:
    CS_DISABLE_LANGUAGE_VULNERABILITY_SCAN: "false"

当你启用此功能时,如果你的项目中启用了 Dependency Scanning,你可能会在 漏洞报告 中看到 重复发现。这是因为 GitLab 无法自动跨不同类型的扫描工具去重。要了解哪些类型的依赖项可能重复,请参阅 Dependency Scanning 与 Container Scanning 对比

在合并请求管道中运行作业

请参阅 使用安全扫描工具与合并请求管道

可用的CI/CD变量

若要自定义容器扫描,请使用CI/CD变量。下表列出了容器扫描特有的CI/CD变量。你也可以使用任何预定义的CI/CD变量

在将这些更改合并到默认分支前,请在合并请求中测试GitLab分析器的自定义。如果不这样做,可能会导致意外结果,包括大量误报。

CI/CD 变量 默认值 描述
ADDITIONAL_CA_CERT_BUNDLE "" 您想要信任的CA证书包。有关更多详细信息,请参阅使用自定义SSL CA证书颁发机构
CI_APPLICATION_REPOSITORY $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG 要扫描的镜像的Docker仓库URL。
CI_APPLICATION_TAG $CI_COMMIT_SHA 要扫描的镜像的Docker仓库标签。
CS_ANALYZER_IMAGE registry.gitlab.com/security-products/container-scanning:8 分析器的Docker镜像。不要将:latest标签与GitLab提供的分析器镜像一起使用。
CS_DEFAULT_BRANCH_IMAGE "" 默认分支上的CS_IMAGE名称。有关更多详细信息,请参阅设置默认分支镜像
CS_DISABLE_DEPENDENCY_LIST "false" warning 已移除(GitLab 17.0)。

| CS_DISABLE_LANGUAGE_VULNERABILITY_SCAN | "true" | 禁用对扫描镜像中安装的语言特定包的扫描。 | | CS_DOCKER_INSECURE | "false" | 允许在不验证证书的情况下通过HTTPS访问安全的Docker注册表。 | | CS_DOCKERFILE_PATH | Dockerfile | 用于生成修复方案的Dockerfile的路径。默认情况下,扫描器会在项目根目录下查找名为Dockerfile的文件。仅当你的Dockerfile位于非标准位置(例如子目录)时,才需要配置此变量。有关更多详情,请参阅漏洞解决方案。 | | CS_INCLUDE_LICENSES | "" | 如果设置此变量,将包含每个组件的许可证。它仅适用于cyclonedx报告,这些许可证由trivy提供 | | CS_IGNORE_STATUSES | "" | 强制分析器忽略以逗号分隔列表中指定状态的发现结果。允许以下值:unknown,not_affected,affected,fixed,under_investigation,will_not_fix,fix_deferred,end_of_life1 | | CS_IGNORE_UNFIXED | "false" | 忽略未修复的发现结果。被忽略的发现结果不会包含在报告中。 | | CS_IMAGE | $CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG | 要扫描的Docker镜像。如果设置了此变量,它将覆盖$CI_APPLICATION_REPOSITORY$CI_APPLICATION_TAG变量。 | | CS_IMAGE_SUFFIX | "" | 添加到CS_ANALYZER_IMAGE的后缀。如果设置为-fips,则使用FIPS-enabled镜像进行扫描。有关更多详情,请参阅FIPS启用镜像。 | | CS_QUIET | "" | 如果设置了此变量,将禁用在作业日志中输出vulnerabilities table。该功能于GitLab 15.1版本引入。 |

| CS_REGISTRY_INSECURE | "false" | 允许访问不安全的注册表(仅 HTTP)。仅在本地测试镜像时设置为 true。适用于所有扫描器,但 Trivy 工作时注册表必须监听 80/tcp 端口。 | | CS_REGISTRY_PASSWORD | $CI_REGISTRY_PASSWORD | 用于访问需要身份验证的 Docker 注册表的密码。默认值仅在 $CS_IMAGE 位于 $CI_REGISTRY 时设置。FIPS 模式下不支持。 | | CS_REGISTRY_USER | $CI_REGISTRY_USER | 用于访问需要身份验证的 Docker 注册表的用户名。默认值仅在 $CS_IMAGE 位于 $CI_REGISTRY 时设置。FIPS 模式下不支持。 | | CS_REPORT_OS_EOL | "false" | 启用 EOL 检测 | | CS_REPORT_OS_EOL_SEVERITY | "Medium" | 当 CS_REPORT_OS_EOL 启用时,分配给 EOL OS 发现的严重性级别。无论 CS_SEVERITY_THRESHOLD 如何,EOL 发现始终会被报告。支持的级别有 UNKNOWNLOWMEDIUMHIGHCRITICAL。 | | CS_SEVERITY_THRESHOLD | UNKNOWN | 严重性级别阈值。扫描器会输出严重性级别高于或等于此阈值的漏洞。支持的级别有 UNKNOWNLOWMEDIUMHIGHCRITICAL。 | | CS_TRIVY_JAVA_DB | "registry.gitlab.com/gitlab-org/security-products/dependencies/trivy-java-db" | 指定 trivy-java-db 漏洞数据库的替代位置。 | | CS_TRIVY_DETECTION_PRIORITY | "precise" | 使用定义的 Trivy 检测优先级 进行扫描。允许以下值:precisecomprehensive。 | | SECURE_LOG_LEVEL | info | 设置最低日志级别。此日志级别及更高级别的消息将被输出。按严重性从高到低排列,日志级别为:fatalerrorwarninfodebug。 |

| TRIVY_TIMEOUT | 5m0s | 设置扫描的超时时间。 | | TRIVY_PLATFORM | linux/amd64 | 若镜像支持多平台,则以 os/arch 格式设置平台。 |

Footnotes:

  1. 修复状态信息高度依赖软件供应商提供的准确修复可用性数据,以及容器镜像操作系统包的元数据。同时,该信息也受单个容器扫描器的解读影响。当容器扫描器误报漏洞对应修复包的可用性时,若启用此设置并使用 CS_IGNORE_STATUSES,可能导致发现结果出现假阳性或假阴性过滤。

覆盖容器扫描模板

如果你想覆盖作业定义(例如,更改像 variables 这样的属性),必须声明并在模板包含之后重写一个作业,然后指定任何额外的键。

这个示例将 GIT_STRATEGY 设置为 fetch

include:
  - template: Jobs/Container-Scanning.gitlab-ci.yml

container_scanning:
  variables:
    GIT_STRATEGY: fetch

设置默认分支的镜像

默认情况下,容器扫描假设镜像命名约定将任何与分支相关的标识符存储在镜像标签中,而不是镜像名称中。当默认分支和非默认分支之间的镜像名称不同时,以前检测到的漏洞会在合并请求中出现为新检测到的漏洞。

当同一个镜像在默认分支和非默认分支上有不同的名称时,你可以使用 CS_DEFAULT_BRANCH_IMAGE 变量来指示该镜像在默认分支上的名称是什么。GitLab 然后会正确确定在非默认分支上运行扫描时是否存在漏洞。

举个例子,假设如下:

  • 非默认分支发布镜像的命名约定为 $CI_REGISTRY_IMAGE/$CI_COMMIT_BRANCH:$CI_COMMIT_SHA
  • 默认分支发布镜像的命名约定为 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

在这个例子中,你可以使用以下 CI/CD 配置来确保漏洞不会重复:

include:
  - template: Jobs/Container-Scanning.gitlab-ci.yml

container_scanning:
  variables:
    CS_DEFAULT_BRANCH_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  before_script:
    - export CS_IMAGE="$CI_REGISTRY_IMAGE/$CI_COMMIT_BRANCH:$CI_COMMIT_SHA"
    - |
      if [ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]; then
        export CS_IMAGE="$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"
      fi

CS_DEFAULT_BRANCH_IMAGE 应该对给定的 CS_IMAGE 保持相同。如果它改变了,那么会创建一组重复的漏洞,这必须手动驳回。

在使用 Auto DevOps 时,CS_DEFAULT_BRANCH_IMAGE 会自动设置为 $CI_REGISTRY_IMAGE/$CI_DEFAULT_BRANCH:$CI_APPLICATION_TAG

使用自定义SSL CA证书颁发机构

你可以使用 ADDITIONAL_CA_CERT_BUNDLE CI/CD 变量来配置自定义SSL CA证书颁发机构,用于在从使用HTTPS的注册表获取Docker镜像时验证对端。ADDITIONAL_CA_CERT_BUNDLE 的值应包含 X.509 PEM公钥证书的文本表示形式。例如,要在 .gitlab-ci.yml 文件中配置此值,请使用以下内容:

container_scanning:
  variables:
    ADDITIONAL_CA_CERT_BUNDLE: |
        -----BEGIN CERTIFICATE-----
        MIIGqTCCBJGgAwIBAgIQI7AVxxVwg2kch4d56XNdDjANBgkqhkiG9w0BAQsFADCB
        ...
        jWgmPqF3vUbZE0EyScetPJquRFRKIesyJuBFMAs=
        -----END CERTIFICATE-----

ADDITIONAL_CA_CERT_BUNDLE 的值也可以作为 UI中的自定义变量 进行配置,既可以作为 file(需要证书路径),也可以作为变量(需要证书的文本表示)。

扫描多架构镜像

你可以使用 TRIVY_PLATFORM CI/CD 变量来配置容器扫描针对特定的操作系统和架构运行。例如,要在 .gitlab-ci.yml 文件中配置此值,请使用以下内容:

container_scanning:
  # 使用arm64 SaaS runner原生扫描此镜像
  tags: ["saas-linux-small-arm64"]
  variables:
    TRIVY_PLATFORM: "linux/arm64"

漏洞白名单

  • 层级:旗舰版
  • 提供:GitLab.com, GitLab 自托管, GitLab 专用

要允许特定漏洞,请遵循以下步骤:

  1. 通过遵循 覆盖容器扫描模板 中的说明,在你的 .gitlab-ci.yml 文件中设置 GIT_STRATEGY: fetch
  2. 在名为 vulnerability-allowlist.yml 的YAML文件中定义允许的漏洞。这必须使用 vulnerability-allowlist.yml 数据格式 中描述的格式。
  3. vulnerability-allowlist.yml 文件添加到项目Git仓库的根文件夹中。

vulnerability-allowlist.yml 数据格式

vulnerability-allowlist.yml 文件是一个YAML文件,用于指定允许存在的漏洞的CVE ID列表,因为这些漏洞是误报,或者不适用。

如果在 vulnerability-allowlist.yml 文件中找到匹配项,则会发生以下情况:

  • 当分析器生成 gl-container-scanning-report.json 文件时,该漏洞不会被包含
  • 流水线的Security标签页不会显示该漏洞。它未包含在JSON文件中,而该文件是Security标签页的真实数据来源。

示例 vulnerability-allowlist.yml 文件:

generalallowlist:
  CVE-2019-8696:
  CVE-2014-8166: cups
  CVE-2017-18248:
images:
  registry.gitlab.com/gitlab-org/security-products/dast/webgoat-8.0@sha256:
    CVE-2018-4180:
  your.private.registry:5000/centos:
    CVE-2015-1419: libxml2
    CVE-2015-1447:

此示例从 gl-container-scanning-report.json 中排除了:

  1. 所有CVE ID为 CVE-2019-8696CVE-2014-8166CVE-2017-18248 的漏洞。
  2. 在容器镜像 registry.gitlab.com/gitlab-org/security-products/dast/webgoat-8.0@sha256 中发现的CVE ID为 CVE-2018-4180 的所有漏洞。
  3. 在容器 your.private.registry:5000/centos 中发现的CVE ID为 CVE-2015-1419CVE-2015-1447 的所有漏洞。
文件格式
  • generalallowlist 块允许你全局指定CVE ID。所有具有匹配CVE ID的漏洞都会从扫描报告中排除。

  • images 块允许你独立地为每个容器镜像指定CVE ID。来自给定镜像且具有匹配CVE ID的所有漏洞都会从扫描报告中排除。镜像名称是从用于指定要扫描的Docker镜像的环境变量之一获取的,例如 $CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAGCS_IMAGE。此块中提供的镜像必须与此值匹配,并且不能包含标签值。例如,如果你使用 CS_IMAGE=alpine:3.7 指定要扫描的镜像,那么你会在 images 块中使用 alpine,但不能使用 alpine:3.7

你可以通过多种方式指定容器镜像:

  • 仅作为镜像名称(如 centos)。
  • 作为带有注册表主机名的完整镜像名称(如 your.private.registry:5000/centos)。
  • 作为带有注册表主机名和sha256标签的完整镜像名称(如 registry.gitlab.com/gitlab-org/security-products/dast/webgoat-8.0@sha256)。

CVE ID后的字符串(如前例中的 cupslibxml2)是一种可选的注释格式。它对漏洞的处理没有任何影响。你可以包含注释来描述漏洞。

容器扫描作业日志格式

你可以通过查看由容器扫描分析器在 container_scanning 作业详情中生成的日志,来验证扫描结果以及 vulnerability-allowlist.yml 文件的正确性。

日志包含一个以表格形式呈现的已发现漏洞列表,例如:

+------------+-------------------------+------------------------+-----------------------+------------------------------------------------------------------------+
|   状态     |      CVE 严重程度        |      包名              |    包版本             |                            CVE 描述                                     |
+------------+-------------------------+------------------------+-----------------------+------------------------------------------------------------------------+
| 已批准     |   高危 CVE-2019-3462     |          apt           |         1.4.8         | apt 版本 1.4.8 及更早版本的 HTTP 传输方法中对 302 重定向字段的清理不当,|
|            |                         |                        |                       | 可能导致中间人攻击者注入内容,进而可能在目标机器上执行远程代码。       |
+------------+-------------------------+------------------------+-----------------------+------------------------------------------------------------------------+
| 未批准     |  中危 CVE-2020-27350     |          apt           |         1.4.8         | APT 在解析 .deb 包时存在多个整数溢出和下溢问题,即 GHSL-2020-168 和    |
|            |                         |                        |                       | GHSL-2020-169,涉及文件 apt-pkg/contrib/extracttar.cc、apt-pkg/deb/   |
|            |                         |                        |                       | debfile.cc 以及 apt-pkg/contrib/arfile.cc。此问题影响以下版本:         |
|            |                         |                        |                       | apt 1.2.32ubuntu0(低于 1.2.32ubuntu0.2 的版本);1.6.12ubuntu0(低   |
|            |                         |                        |                       | 于 1.6.12ubuntu0.2 的版本);2.0.2ubuntu0(低于 2.0.2ubuntu0.2 的版   |
|            |                         |                        |                       | 本);2.1.10ubuntu0(低于 2.1.10ubuntu0.1 的版本)。                   |
+------------+-------------------------+------------------------+-----------------------+------------------------------------------------------------------------+
| 未批准     |  中危 CVE-2020-3810      |          apt           |         1.4.8         | APT 版本 2.1.2 之前的 ar/tar 实现中缺少输入验证,可能导致在处理特殊构   |
|            |                         |                        |                       | 建的 deb 文件时出现拒绝服务。                                          |
+------------+-------------------------+------------------------+-----------------------+------------------------------------------------------------------------+

当日志中的漏洞对应的 CVE ID 被添加到 vulnerability-allowlist.yml 文件中时,该漏洞会被标记为 已批准

在离线环境中运行容器扫描

  • 层级:免费、高级、终极
  • 提供:GitLab 自托管

对于在网络访问受限、受限制或间歇性访问外部资源的环境中运行的实例,需要对容器扫描作业进行一些调整才能成功运行。更多信息请参见离线环境

离线容器扫描的要求

要在离线环境中使用容器扫描,您需要:

  • 配置了 dockerkubernetes 执行器 的 GitLab Runner。
  • 配置一个包含容器扫描镜像副本的本地 Docker 容器注册表。您可以在各自的注册表中找到这些镜像:
GitLab 分析器 容器注册表
Container-Scanning Container-Scanning 容器注册表

GitLab Runner 有一个 默认 pull policyalways,这意味着即使有本地副本可用,Runner 也会尝试从 GitLab 容器注册表中拉取 Docker 镜像。在离线环境中,如果您希望仅使用本地可用的 Docker 镜像,可以将 GitLab Runner 的 pull_policy 设置为 if-not-present。但是,如果不是在离线环境中,我们建议将拉取策略设置为 always,因为这能让您的 CI/CD 流水线中使用更新的扫描器。

对自定义证书颁发机构的支持

对 Trivy 自定义证书颁发机构的支持是在版本 4.0.0 中引入的。

使 GitLab 容器扫描分析器镜像在您的 Docker 注册表中可用

对于容器扫描,请从 registry.gitlab.com 导入以下镜像到您的 本地 Docker 容器注册表

registry.gitlab.com/security-products/container-scanning:8
registry.gitlab.com/security-products/container-scanning/trivy:8

将 Docker 镜像导入本地离线 Docker 注册表的过程取决于 您的网络安全策略。请咨询您的 IT 人员,了解您可以使用的已接受且批准的流程,以便导入或临时访问外部资源。这些扫描器会 定期更新,您可能能够自行进行偶尔的更新。

有关更多信息,请参阅 如何使用流水线更新镜像的具体步骤

有关以文件形式保存和传输 Docker 镜像的详细信息,请参阅 Docker 文档中的 docker savedocker loaddocker exportdocker import

设置容器扫描 CI/CD 变量以使用本地容器扫描分析器

此处描述的方法适用于您 .gitlab-ci.yml 文件中定义的 container_scanning 作业。这些方法不适用于由机器人管理且不使用 .gitlab-ci.yml 文件的 Registry 容器扫描功能。若要在离线环境中配置自动 Registry 容器扫描,请在 GitLab UI 中 定义 CS_ANALYZER_IMAGE 变量

  1. 在您的 .gitlab-ci.yml 文件中 覆盖容器扫描模板,以引用托管在本地 Docker 容器注册表上的 Docker 镜像:

    include:
      - template: Jobs/Container-Scanning.gitlab-ci.yml
    
    container_scanning:
      image: $CI_REGISTRY/namespace/container-scanning
  2. 如果您的本地 Docker 容器注册表通过 HTTPS 安全运行,但您使用了自签名证书,则必须在 .gitlab-ci.ymlcontainer_scanning 部分中设置 CS_DOCKER_INSECURE: "true"

通过管道自动化容器扫描漏洞数据库更新

我们建议你设置一个计划管道,以按预设时间表获取最新的漏洞数据库。通过管道自动化此过程意味着你不必每次都手动执行。你可以使用以下 .gitlab-ci.yml 示例作为模板:

variables:
  SOURCE_IMAGE: registry.gitlab.com/security-products/container-scanning:8
  TARGET_IMAGE: $CI_REGISTRY/namespace/container-scanning

image: docker:latest

update-scanner-image:
  services:
    - docker:dind
  script:
    - docker pull $SOURCE_IMAGE
    - docker tag $SOURCE_IMAGE $TARGET_IMAGE
    - echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY --username $CI_REGISTRY_USER --password-stdin
    - docker push $TARGET_IMAGE

上述模板适用于本地安装运行的 GitLab Docker 注册表。但是,如果你使用非 GitLab Docker 注册表,你必须修改 $CI_REGISTRY 值以及 docker login 凭证,使其匹配你的本地注册表详情。

扫描外部私有注册表中的镜像

若要扫描外部私有注册表中的镜像,你必须配置访问凭证,以便容器扫描分析器在尝试访问待扫描镜像前完成身份验证。

如果你使用 GitLab Container RegistryCS_REGISTRY_USERCS_REGISTRY_PASSWORD 配置变量会自动设置,你可跳过此配置。

此示例展示了扫描私人 Google Container Registry 中镜像所需的配置:

include:
  - template: Jobs/Container-Scanning.gitlab-ci.yml

container_scanning:
  variables:
    CS_REGISTRY_USER: _json_key
    CS_REGISTRY_PASSWORD: "$GCP_CREDENTIALS"
    CS_IMAGE: "gcr.io/path-to-you-registry/image:tag"

在你提交此配置前,添加 CI/CD 变量用于 GCP_CREDENTIALS(包含 JSON 密钥),具体请参考 Google Cloud Platform Container Registry 文档。另外:

  • 变量的值可能不符合 Mask variable 选项的掩码要求,因此该值可能会暴露在作业日志中。
  • 如果你选择 Protect variable 选项,扫描可能不会在不受保护的功能分支上运行。
  • 如果未选中这些选项,考虑创建仅读权限的凭证并定期轮换。

当启用 FIPS 模式时,不支持扫描外部私有注册表中的镜像。

创建和使用 Trivy Java 数据库镜像

当使用 trivy 扫描器且遇到待扫描容器镜像中的 jar 文件时,trivy 会下载额外的 trivy-java-db 漏洞数据库。默认情况下,trivy-java-db 数据库作为 OCI 工件托管于 ghcr.io/aquasecurity/trivy-java-db:1。如果此注册表不可访问或返回 TOOMANYREQUESTS,一种解决方案是将 trivy-java-db 镜像到更易访问的容器注册表中:

mirror trivy java db:
  image:
    name: ghcr.io/oras-project/oras:v1.1.0
    entrypoint: [""]
  script:
    - oras login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - oras pull ghcr.io/aquasecurity/trivy-java-db:1
    - oras push $CI_REGISTRY_IMAGE:1 --config /dev/null:application/vnd.aquasec.trivy.config.v1+json javadb.tar.gz:application/vnd.aquasec.trivy.javadb.layer.v1.tar+gzip

漏洞数据库并非常规 Docker 镜像,因此无法通过 docker pull 拉取。如果在 GitLab UI 中访问该镜像,会出现错误。

如果容器注册表是 gitlab.example.com/trivy-java-db-mirror,则容器扫描作业应按如下方式配置。不要在末尾添加标签 :1,它由 trivy 自动添加:

include:
  - template: Jobs/Container-Scanning.gitlab-ci.yml

container_scanning:
  variables:
    CS_TRIVY_JAVA_DB: gitlab.example.com/trivy-java-db-mirror

扫描归档格式

Container Scanning 支持 .tar.tar.gz 归档格式的镜像。 此类镜像可通过例如 docker savedocker buildx build 创建。

若要扫描归档文件,请将环境变量 CS_IMAGE 设置为 archive://path/to/archive 格式:

  • archive:// 方案前缀指定分析器要扫描归档文件。
  • path/to/archive 指定要扫描的归档文件的路径,无论是绝对路径还是相对路径。

Container Scanning 支持遵循 Docker Image Specification 的 tar 镜像文件。 不支持 OCI tarball。 有关受支持格式的更多信息,请参阅 Trivy tar 文件支持

构建受支持的 tar 文件

Container Scanning 使用 tar 文件的元数据来确定镜像名称。 构建 tar 镜像文件时,请确保镜像已标记:


# 拉取或构建带有名称和标签的镜像
docker pull image:latest

# 或者
docker build . -t image:latest

# 然后使用 docker save 导出为 tar
docker save image:latest -o image-latest.tar

# 或者使用 buildx build 构建带标签的镜像
docker buildx create --name container --driver=docker-container
docker buildx build -t image:latest --builder=container -o type=docker,dest=- . > image-latest.tar

# 使用 podman
podman build -t image:latest .
podman save -o image-latest.tar image:latest

镜像名称

Container Scanning 通过先评估归档文件的 manifest.json 并使用 RepoTags 中的第一项来确定镜像名称。 如果未找到,则使用 index.json 获取 io.containerd.image.name 注解。如果仍未找到,则改用归档文件名。

扫描之前作业中构建的归档文件

若要扫描 CI/CD 作业中构建的归档文件,必须将从构建作业传递到容器扫描作业的归档工件。 使用 artifacts:pathsdependencies 关键字从一个作业向后续作业传递工件:

build_job:
  script:
    - docker build . -t image:latest
    - docker save image:latest -o image-latest.tar
  artifacts:
    paths:
      - "image-latest.tar"

container_scanning:
  variables:
    CS_IMAGE: "archive://image-latest.tar"
  dependencies:
    - build_job

扫描项目仓库中的归档文件

若要扫描项目中发现的归档文件,请确保您的 Git 策略 允许访问您的仓库。 在 container_scanning 作业中将 GIT_STRATEGY 关键字设置为 clonefetch,因为默认情况下它被设置为 none

container_scanning:
  variables:
    GIT_STRATEGY: fetch

运行独立的容器扫描工具

无需在 CI 作业上下文中运行即可针对 Docker 容器运行 GitLab 容器扫描工具。 若要直接扫描镜像,请按照以下步骤操作:

  1. 运行 Docker DesktopDocker Machine

  2. 运行分析器的 Docker 镜像,将您要分析的镜像和标签通过 CI_APPLICATION_REPOSITORYCI_APPLICATION_TAG 变量传入:

    docker run \
      --interactive --rm \
      --volume "$PWD":/tmp/app \
      -e CI_PROJECT_DIR=/tmp/app \
      -e CI_APPLICATION_REPOSITORY=registry.gitlab.com/gitlab-org/security-products/dast/webgoat-8.0@sha256 \
      -e CI_APPLICATION_TAG=bc09fe2e0721dfaeee79364115aeedf2174cce0947b9ae5fe7c33312ee019a4e \
      registry.gitlab.com/security-products/container-scanning

结果存储在 gl-container-scanning-report.json 中。

报告的JSON格式

容器扫描工具会生成JSON格式的报告,这些报告通过CI配置文件中的artifacts:reports关键字被GitLab Runner识别。

CI作业完成后,Runner会将这些报告上传到GitLab,之后可在CI作业工件中查看。在GitLab Ultimate中,这些报告可以在对应的pipeline中查看,并成为vulnerability report的一部分。

这些报告必须遵循security report schemas中定义的格式。请参阅:

CycloneDX 软件物料清单(Software Bill of Materials)

除了JSON报告文件Container Scanning工具还会为扫描的镜像输出CycloneDX软件物料清单(SBOM)。这个CycloneDX SBOM名为gl-sbom-report.cdx.json,与JSON报告文件保存在同一目录下。此功能仅在使用Trivy分析器时支持。

该报告可在依赖项列表中查看。

你可以像下载其他作业工件一样下载CycloneDX SBOMs the same way as other job artifacts

CycloneDX报告中包含的许可证信息

容器扫描可以在CycloneDX报告中包含许可证信息。此功能默认禁用以保持向后兼容性。

若要在容器扫描结果中启用许可证扫描:

  • 在你的.gitlab-ci.yml文件中设置CS_INCLUDE_LICENSES变量:
container_scanning:
  variables:
    CS_INCLUDE_LICENSES: "true"
  • 启用此功能后,生成的CycloneDX报告将包含容器镜像中检测到的组件的许可证信息。

  • 你可以在依赖项列表页面或作为可下载的CycloneDX作业工件的一部分查看此许可证信息。

需要注意的是,仅支持SPDX许可证。不过,不符合SPDX规范的许可证仍会被纳入,且不会出现面向用户的错误。

已停止支持的操作系统检测

容器扫描包括检测和报告你的容器镜像是否使用了已达到生命终点(EOL)的操作系统的能力。已达到EOL的操作系统不再接收安全更新,使其容易受到新发现的安全问题的影响。

EOL检测功能使用Trivy来识别其各自发行版不再支持的操作系统。当检测到EOL操作系统时,它会在你的容器扫描报告中与其他安全检测结果一起被报告为漏洞。

若要启用EOL检测,将CS_REPORT_OS_EOL设置为"true"

容器注册表扫描

  • 层级:旗舰版
  • 提供方式:GitLab.com、GitLab 自托管、GitLab 专用

当带有 latest 标签的容器镜像被推送时,安全策略机器人会在新管道中对默认分支自动触发容器扫描作业。

与常规容器扫描不同,扫描结果不包含安全报告。相反,容器注册表扫描依赖于持续漏洞扫描来检查扫描检测到的组件。

当识别出安全发现时,GitLab 会将这些发现填充到漏洞报告中。漏洞可以在漏洞报告页面的容器注册表漏洞标签下查看。

容器注册表扫描仅在新的建议发布到GitLab 建议数据库时才会填充漏洞报告。支持用所有现有建议数据而非仅新检测到的数据填充漏洞报告的功能,已在史诗任务 11219 中提出。

先决条件

  • 您必须至少拥有项目的 Maintainer 角色才能启用容器注册表扫描。
  • 所使用的项目不能为空。如果您仅将空项目用于存储容器镜像,此功能将无法按预期运行。作为解决方法,请确保项目中包含默认分支上的初始提交。
  • 默认情况下,每个项目每天最多进行 50 次扫描。
  • 您必须配置容器注册表通知

启用容器注册表扫描

若要为 GitLab 容器注册表启用容器扫描:

  1. 在左侧边栏,选择搜索或前往并找到您的项目。
  2. 选择安全 > 安全配置
  3. 向下滚动至容器注册表扫描部分,开启开关。

在离线或气隙环境中使用

要在离线或气隙环境中使用容器注册表扫描,您必须使用容器扫描分析器镜像的本地副本。由于该功能由 GitLab 安全策略机器人管理,因此无法通过编辑 .gitlab-ci.yml 文件来配置分析器镜像。

相反,您必须在 GitLab UI 中设置 CS_ANALYZER_IMAGE CI/CD 变量以覆盖默认扫描器镜像。动态创建的扫描作业会继承 UI 中定义的变量。您可以在项目、组或实例级别设置该变量。

若要配置自定义扫描器镜像:

  1. 在左侧边栏,选择搜索或前往并找到您的项目或组。
  2. 选择设置 > CI/CD
  3. 展开变量部分。
  4. 选择添加变量并填写详细信息:
    • 键:CS_ANALYZER_IMAGE
    • 值:您镜像的容器扫描镜像的完整 URL。例如,my.local.registry:5000/analyzers/container-scanning:7
  5. 选择添加变量

现在,GitLab 安全策略机器人在触发扫描时会使用指定的镜像。

漏洞数据库

所有分析器镜像都会每日更新(查看详情)。

这些镜像使用来自上游公告数据库的数据:

  • AlmaLinux 安全公告
  • Amazon Linux 安全中心
  • Arch Linux 安全追踪器
  • SUSE CVRF
  • CWE 公告
  • Debian 安全漏洞跟踪器
  • GitHub 安全公告
  • Go 漏洞数据库
  • CBL-Mariner 漏洞数据
  • NVD
  • OSV
  • Red Hat OVAL v2
  • Red Hat 安全数据 API
  • Photon 安全公告
  • Rocky Linux 更新信息
  • Ubuntu CVE 跟踪器(仅包含2021年中及之后的数据源)

除上述扫描器提供的来源外,GitLab 维护以下漏洞数据库:

在 GitLab Ultimate 层级中,GitLab 公告数据库 的数据会被合并进来,以增强外部来源的数据。在 GitLab Premium 和 Free 层级中,GitLab 公告数据库(开源版) 的数据会被合并进来,以增强外部来源的数据。此增强功能目前仅适用于 Trivy 扫描器的分析器镜像。

其他分析器的数据库更新信息可在 维护表 中找到。

漏洞解决方案(自动修复)

  • 层级:Ultimate
  • 提供:GitLab.com、GitLab 自托管、GitLab 专用

部分漏洞可通过应用 GitLab 自动生成的解决方案进行修复。

要启用修复支持,扫描工具必须能访问由 CS_DOCKERFILE_PATH CI/CD 变量指定的 Dockerfile。为确保扫描工具有权访问该文件,需按本文档 覆盖容器扫描模板 部分的说明,在 .gitlab-ci.yml 文件中设置 GIT_STRATEGY: fetch

阅读更多关于 漏洞解决方案 的内容。

故障排除

docker: Error response from daemon: failed to copy xattrs

当运行器使用 docker 执行器且使用 NFS 时(例如 /var/lib/docker 位于 NFS 挂载上),容器扫描可能因类似以下错误而失败:

docker: Error response from daemon: failed to copy xattrs: failed to set xattr "security.selinux" on /path/to/file: operation not supported.

这是 Docker 中的一个 bug 导致的结果,现已 修复。为避免此错误,请确保运行器使用的 Docker 版本为 18.09.03 或更高。更多信息,请参阅 问题 #10241

收到警告消息 gl-container-scanning-report.json: no matching files

有关此问题的信息,请参见 通用应用程序安全故障排除部分

扫描 AWS ECR 中的镜像时出现 unexpected status code 401 Unauthorized: Not Authorized

当未配置 AWS 区域且扫描器无法获取授权令牌时,可能发生此情况。将 SECURE_LOG_LEVEL 设为 debug 时,会看到类似以下日志消息:

[35mDEBUG[0m failed to get authorization token: MissingRegion: could not find region configuration

要解决此问题,请在 CI/CD 变量中添加 AWS_DEFAULT_REGION

variables:
  AWS_DEFAULT_REGION: <AWS_REGION_FOR_ECR>

unable to open a file: open /home/gitlab/.cache/trivy/ee/db/metadata.json: no such file or directory

压缩后的 Trivy 数据库存储在容器的 /tmp 文件夹中,并在运行时解压至 /home/gitlab/.cache/trivy/{ee|ce}/db。若运行器配置中对 /tmp 目录进行了卷挂载,则可能出现此错误。

要解决此问题,不要绑定整个 /tmp 文件夹,而是绑定 /tmp 中的特定文件或文件夹(例如 /tmp/myfile.txt)。

解决 context deadline exceeded 错误

此错误表示发生了超时。要解决此问题,请在 container_scanning 作业中添加 TRIVY_TIMEOUT 环境变量,并设置足够长的时间。

变更

容器扫描分析器的变更可在项目的更新日志中找到。

容器扫描 v6.x:过时的漏洞数据库错误

使用带有 registry.gitlab.com/security-products/container-scanning/grype:6registry.gitlab.com/security-products/container-scanning/grype:6-fips 分析器镜像的容器扫描可能会因过时漏洞数据库错误而失败,例如:

1 error occurred:
* the vulnerability database was built 6 days ago (max allowed age is 5 days)

当上述其中一个容器扫描镜像被复制到用户的仓库且未更新到该镜像(镜像每天重建)时,会发生这种情况。