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

使用 Sigstore 进行无密钥签名和验证

  • Tier: 免费版、高级版、旗舰版
  • Offering: GitLab.com

Sigstore 项目提供了一个名为 Cosign 的 CLI 工具,可用于对使用 GitLab CI/CD 构建的容器镜像进行无密钥签名。无密钥签名有很多优势,包括无需管理、保护和轮换私钥。Cosign 请求一个临时密钥对用于签名,将其记录在证书透明日志中,然后丢弃该密钥。密钥是通过从 GitLab 服务器获取的令牌生成的,该令牌使用运行管道的用户 OIDC 身份。此令牌包含唯一声明,证明令牌是由 CI/CD 管道生成的。要了解更多信息,请参阅 Cosign 关于无密钥签名的 文档

有关 GitLab OIDC 声明与 Fulcio 证书扩展之间映射的详细信息,请参阅 将 OIDC 令牌声明映射到 Fulcio OID 的 GitLab 列。

先决条件:

  • 您必须使用 GitLab.com。
  • 您项目的 CI/CD 配置必须位于项目中。

使用 Cosign 签名或验证容器镜像和构建产物

您可以使用 Cosign 来签名和验证容器镜像和构建产物。

先决条件:

  • 您必须使用 >= 2.0.1 版本的 Cosign。

已知问题

  • CI/CD 配置文件中的 id_tokens 部分必须位于正在构建和签名的项目中。不支持 AutoDevOps、从其他仓库包含的 CI 文件和子管道。移除此限制的工作正在 epic 11637 中跟踪。

最佳实践

  • 在同一个作业中构建和签名镜像/产物,以防止在签名之前被篡改。
  • 签名容器镜像时,签名的摘要(不可变)而不是标签。

GitLab ID tokens 可被 Cosign 用于 无密钥签名。令牌必须将 sigstore 设置为 aud 声明。当令牌设置在 SIGSTORE_ID_TOKEN 环境变量中时,Cosign 可以自动使用它。

要了解如何安装 Cosign,请参阅 Cosign 安装文档

签名

容器镜像

Cosign.gitlab-ci.yml 模板可用于在 GitLab CI 中构建和签名容器镜像。签名会自动存储在与镜像相同的容器仓库中。

include:
- template: Cosign.gitlab-ci.yml

要了解有关签名的更多信息,请参阅 Cosign 签名容器文档

构建产物

以下示例演示如何在 GitLab CI 中签名构建产物。您应该保存 cosign sign-blob 生成的 cosign.bundle 文件,该文件用于签名验证。

要了解有关签名的更多信息,请参阅 Cosign 签名 Blob 文档

build_and_sign_artifact:
  stage: build
  image: alpine:latest
  variables:
    COSIGN_YES: "true"
  id_tokens:
    SIGSTORE_ID_TOKEN:
      aud: sigstore
  before_script:
    - apk add --update cosign
  script:
    - echo "This is a build artifact" > artifact.txt
    - cosign sign-blob artifact.txt --bundle cosign.bundle
  artifacts:
    paths:
      - artifact.txt
      - cosign.bundle

验证

命令行参数

名称
--certificate-identity Fulcio 签名的证书的 SAN。可以使用镜像/产物签名项目中的以下信息构建:GitLab 实例 URL + 项目路径 + // + CI 配置路径 + @ + ref 路径。
--certificate-oidc-issuer 签名镜像/产物的 GitLab 实例 URL。例如,https://gitlab.com
--bundle cosign sign-blob 生成的 bundle 文件。仅用于验证构建产物。

要了解有关验证签名镜像/产物的更多信息,请参阅 Cosign 验证文档

容器镜像

以下示例演示如何在 GitLab CI 中验证签名的容器镜像。使用前面描述的 命令行参数

verify_image:
  image: alpine:3.20
  stage: verify
  before_script:
    - apk add --update cosign docker
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  script:
    - cosign verify "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" --certificate-identity "https://gitlab.com/my-group/my-project//path/to/.gitlab-ci.yml@refs/heads/main" --certificate-oidc-issuer "https://gitlab.com"

其他详细信息

  • 项目路径和 .gitlab-ci.yml 路径之间的双反斜杠不是错误,是验证成功所必需的。当使用单斜杠时,典型错误是 Error: none of the expected identities matched what was in the certificate, got subjects,后跟签名的 URL,其中项目路径和 .gitlab-ci.yml 路径之间有两个斜杠。
  • 如果验证与签名在同一管道中进行,则可以使用此路径:"${CI_PROJECT_URL}//.gitlab-ci.yml@refs/heads/${CI_COMMIT_REF_NAME}"

构建产物

以下示例演示如何在 GitLab CI 中验证签名的构建产物。验证产物需要产物本身和 cosign sign-blob 生成的 cosign.bundle 文件。使用前面描述的 命令行参数

verify_artifact:
  stage: verify
  image: alpine:latest
  before_script:
    - apk add --update cosign
  script:
    - cosign verify-blob artifact.txt --bundle cosign.bundle --certificate-identity "https://gitlab.com/my-group/my-project//path/to/.gitlab-ci.yml@refs/heads/main" --certificate-oidc-issuer "https://gitlab.com"

其他详细信息

  • 项目路径和 .gitlab-ci.yml 路径之间的双反斜杠不是错误,是验证成功所必需的。当使用单斜杠时,典型错误是 Error: none of the expected identities matched what was in the certificate, got subjects,后跟签名的 URL,其中项目路径和 .gitlab-ci.yml 路径之间有两个斜杠。
  • 如果验证与签名在同一管道中进行,则可以使用此路径:"${CI_PROJECT_URL}//.gitlab-ci.yml@refs/heads/${CI_COMMIT_REF_NAME}"

使用 Sigstore 和 npm 生成无密钥来源证明

您可以使用 Sigstore 和 npm,结合 GitLab CI/CD,在不增加密钥管理开销的情况下对构建产物进行数字签名。

关于 npm 来源证明

npm CLI 允许包维护者为用户提供来源证明声明。使用 npm CLI 来源证明生成允许用户信任和验证他们正在下载和使用的包来自您和构建它的构建系统。

有关如何发布 npm 包的更多信息,请参阅 GitLab npm 包仓库

Sigstore

Sigstore 是一组工具,包管理器和安全专家可以使用它们来保护其软件供应链免受攻击。它将 Fulcio、Cosign 和 Rekor 等免费使用的开源技术结合在一起,处理数字签名、验证和来源检查,使分发和使用开源软件更加安全。

相关主题

在 GitLab CI/CD 中生成来源证明

既然 Sigstore 如前所述支持 GitLab OIDC,您可以将 npm 来源证明与 GitLab CI/CD 和 Sigstore 结合使用,在 GitLab CI/CD 管道中为您的 npm 包生成和签名来源证明。

先决条件

  1. 将您的 GitLab ID token aud 设置为 sigstore
  2. 添加 --provenance 标志以让 npm 发布。

要添加到 .gitlab-ci.yml 文件中的示例内容:

build:
  image: node:latest
  id_tokens:
    SIGSTORE_ID_TOKEN:
      aud: sigstore
  script:
    - npm publish --provenance --access public

npm GitLab 模板也提供此功能,示例在 模板文档 中。

验证 npm 来源证明

npm CLI 还为最终用户提供验证包来源证明的功能。

npm audit signatures
audited 1 package in 0s
1 package has a verified registry signature

检查来源证明元数据

Rekor 透明日志存储了每个使用来源证明发布的证书和声明。例如,这是 以下示例的条目

npm 生成的来源证明示例:

_type: https://in-toto.io/Statement/v0.1
subject:
  - name: pkg:npm/%40strongjz/strongcoin@0.0.13
    digest:
      sha512: >-
        924a134a0fd4fe6a7c87b4687bf0ac898b9153218ce9ad75798cc27ab2cddbeff77541f3847049bd5e3dfd74cea0a83754e7686852f34b185c3621d3932bc3c8
predicateType: https://slsa.dev/provenance/v0.2
predicate:
  buildType: https://github.com/npm/CLI/gitlab/v0alpha1
  builder:
    id: https://gitlab.com/strongjz/npm-provenance-example/-/runners/12270835
  invocation:
    configSource:
      uri: git+https://gitlab.com/strongjz/npm-provenance-example
      digest:
        sha1: 6e02e901e936bfac3d4691984dff8c505410cbc3
      entryPoint: deploy
    parameters:
      CI: 'true'
      CI_API_GRAPHQL_URL: https://gitlab.com/api/graphql
      CI_API_V4_URL: https://gitlab.com/api/v4
      CI_COMMIT_BEFORE_SHA: 7d3e913e5375f68700e0c34aa90b0be7843edf6c
      CI_COMMIT_BRANCH: main
      CI_COMMIT_REF_NAME: main
      CI_COMMIT_REF_PROTECTED: 'true'
      CI_COMMIT_REF_SLUG: main
      CI_COMMIT_SHA: 6e02e901e936bfac3d4691984dff8c505410cbc3
      CI_COMMIT_SHORT_SHA: 6e02e901
      CI_COMMIT_TIMESTAMP: '2023-05-19T10:17:12-04:00'
      CI_COMMIT_TITLE: trying to publish to gitlab reg
      CI_CONFIG_PATH: .gitlab-ci.yml
      CI_DEFAULT_BRANCH: main
      CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX: gitlab.com:443/strongjz/dependency_proxy/containers
      CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX: gitlab.com:443/strongjz/dependency_proxy/containers
      CI_DEPENDENCY_PROXY_SERVER: gitlab.com:443
      CI_DEPENDENCY_PROXY_USER: gitlab-ci-token
      CI_JOB_ID: '4316132595'
      CI_JOB_NAME: deploy
      CI_JOB_NAME_SLUG: deploy
      CI_JOB_STAGE: deploy
      CI_JOB_STARTED_AT: '2023-05-19T14:17:23Z'
      CI_JOB_URL: https://gitlab.com/strongjz/npm-provenance-example/-/jobs/4316132595
      CI_NODE_TOTAL: '1'
      CI_PAGES_DOMAIN: gitlab.io
      CI_PAGES_URL: https://strongjz.gitlab.io/npm-provenance-example
      CI_PIPELINE_CREATED_AT: '2023-05-19T14:17:21Z'
      CI_PIPELINE_ID: '872773336'
      CI_PIPELINE_IID: '40'
      CI_PIPELINE_SOURCE: push
      CI_PIPELINE_URL: https://gitlab.com/strongjz/npm-provenance-example/-/pipelines/872773336
      CI_PROJECT_CLASSIFICATION_LABEL: ''
      CI_PROJECT_DESCRIPTION: ''
      CI_PROJECT_ID: '45821955'
      CI_PROJECT_NAME: npm-provenance-example
      CI_PROJECT_NAMESPACE: strongjz
      CI_PROJECT_NAMESPACE_SLUG: strongjz
      CI_PROJECT_NAMESPACE_ID: '36018'
      CI_PROJECT_PATH: strongjz/npm-provenance-example
      CI_PROJECT_PATH_SLUG: strongjz-npm-provenance-example
      CI_PROJECT_REPOSITORY_LANGUAGES: javascript,dockerfile
      CI_PROJECT_ROOT_NAMESPACE: strongjz
      CI_PROJECT_TITLE: npm-provenance-example
      CI_PROJECT_URL: https://gitlab.com/strongjz/npm-provenance-example
      CI_PROJECT_VISIBILITY: public
      CI_REGISTRY: registry.gitlab.com
      CI_REGISTRY_IMAGE: registry.gitlab.com/strongjz/npm-provenance-example
      CI_REGISTRY_USER: gitlab-ci-token
      CI_RUNNER_DESCRIPTION: 3-blue.shared.runners-manager.gitlab.com/default
      CI_RUNNER_ID: '12270835'
      CI_RUNNER_TAGS: >-
        ["gce", "east-c", "linux", "ruby", "mysql", "postgres", "mongo",
        "git-annex", "shared", "docker", "saas-linux-small-amd64"]
      CI_SERVER_HOST: gitlab.com
      CI_SERVER_NAME: GitLab
      CI_SERVER_PORT: '443'
      CI_SERVER_PROTOCOL: https
      CI_SERVER_REVISION: 9d4873fd3c5
      CI_SERVER_SHELL_SSH_HOST: gitlab.com
      CI_SERVER_SHELL_SSH_PORT: '22'
      CI_SERVER_URL: https://gitlab.com
      CI_SERVER_VERSION: 16.1.0-pre
      CI_SERVER_VERSION_MAJOR: '16'
      CI_SERVER_VERSION_MINOR: '1'
      CI_SERVER_VERSION_PATCH: '0'
      CI_TEMPLATE_REGISTRY_HOST: registry.gitlab.com
      GITLAB_CI: 'true'
      GITLAB_FEATURES: >-
        elastic_search,ldap_group_sync,multiple_ldap_servers,seat_link,usage_quotas,zoekt_code_search,repository_size_limit,admin_audit_log,auditor_user,custom_file_templates,custom_project_templates,db_load_balancing,default_branch_protection_restriction_in_groups,extended_audit_events,external_authorization_service_api_management,geo,instance_level_scim,ldap_group_sync_filter,object_storage,pages_size_limit,project_aliases,password_complexity,enterprise_templates,git_abuse_rate_limit,required_ci_templates,runner_maintenance_note,runner_performance_insights,runner_upgrade_management,runner_jobs_statistics
      GITLAB_USER_ID: '31705'
      GITLAB_USER_LOGIN: strongjz
    environment:
      name: 3-blue.shared.runners-manager.gitlab.com/default
      architecture: linux/amd64
      server: https://gitlab.com
      project: strongjz/npm-provenance-example
      job:
        id: '4316132595'
      pipeline:
        id: '872773336'
        ref: .gitlab-ci.yml
  metadata:
    buildInvocationId: https://gitlab.com/strongjz/npm-provenance-example/-/jobs/4316132595
    completeness:
      parameters: true
      environment: true
      materials: false
    reproducible: false
  materials:
    - uri: git+https://gitlab.com/strongjz/npm-provenance-example
      digest:
        sha1: 6e02e901e936bfac3d4691984dff8c505410cbc3