适用版本层级:Free、Premium、Ultimate;适用部署:GitLab Self-Managed。
运行自管理 GitLab 时,不能使用公共 Sigstore 服务为 CI/CD 制品和容器镜像签名,因为该服务只信任 GitLab.com 的流水线。可以将自己的 Sigstore 基础设施——Fulcio、Rekor 和证书透明度日志——接入 GitLab 实例,通过 Cosign 签名和验证制品,无须依赖 GitLab.com 或互联网。
GitLab OpenID Connect(OIDC)提供程序负责证明身份;Cosign 在使用后丢弃签名密钥;Rekor 将每次签名事件记入透明日志。
Fulcio 签发的证书嵌入签名,其中包含建立签名的流水线信息,例如项目路径、提交 SHA、流水线来源、Runner 环境和任务 URL。
前提条件
- 有权配置 Sigstore 基础设施(Fulcio、Rekor)及 GitLab CI/CD Runner。
- 网络内运行自托管 Sigstore 栈,包括 Fulcio、Rekor 和证书透明度日志。证书透明度日志不可省略:Cosign 验证时会检查签名证书时间戳;未配置此日志的 Fulcio 签发的证书不能通过 Cosign 验证。部署说明见 Sigstore 透明日志安装指南(Rekor 和 Trillian 后端)及 Fulcio 仓库(Fulcio 和证书透明度日志)。
- Rekor 使用持久化签名密钥。
- 如果 GitLab 使用私有证书颁发机构签发的 HTTPS 证书,Fulcio 和 Runner 都必须信任该机构。将 CA 证书挂载到 Fulcio 容器,并用
SSL_CERT_FILE指向它;同时在每个 Runner 的操作系统信任存储中安装该 CA 证书。 - Runner 安装 Cosign v2.x 或更新版本。
- 在 Runner 的共享位置(例如
/etc/sigstore/)放置 Sigstore 栈的信任材料:Fulcio 根 CA 证书fulcio-root.pem、Rekor 透明日志公钥rekor-pub.pem、证书透明度日志公钥ctfe-pub.pem。
让 Fulcio 信任 GitLab 实例
配置 Fulcio,使其在无密钥签名时能验证 GitLab CI/CD 任务的 OIDC 令牌。Fulcio 将令牌声明映射为签名证书字段。配置文件需要同时包含 oidc-issuers 和 ci-issuer-metadata 两个部分。
第一步,获取精确的 OIDC issuer URL。将下面的示例域名替换为 GitLab 实例地址。Fulcio 要求精确匹配,协议以及末尾有无斜杠都影响结果。
curl --silent "https://gitlab.example.com/.well-known/openid-configuration" | jq --raw-output .issuer
第二步,创建 Fulcio OIDC 配置,为实例添加 oidc-issuers 条目。用上一步的输出替换 <gitlab_issuer_url>:
oidc-issuers:
<gitlab_issuer_url>:
issuer-url: <gitlab_issuer_url>
client-id: sigstore
type: ci-provider
ci-provider: gitlab-pipeline
contact: admin@example.com
description: "GitLab Self-Managed OIDC"
第三步,在同一个文件中加入 ci-issuer-metadata,复制 Fulcio 上游配置中的 GitLab 声明模板。使用与上一步相同的 issuer URL。各声明与证书字段的映射见 OIDC 声明到 Fulcio OID 映射表格的 GitLab 列。
ci-issuer-metadata:
gitlab-pipeline:
default-template-values:
url: "<gitlab_issuer_url>"
environment: ""
extension-templates:
build-signer-uri: "https://{{ .ci_config_ref_uri }}"
build-signer-digest: "ci_config_sha"
runner-environment: "runner_environment"
source-repository-uri: "{{ .url }}/{{ .project_path }}"
source-repository-digest: "sha"
source-repository-ref: >-
refs/{{if eq .ref_type "branch"}}heads/{{ else }}tags/{{end}}{{ .ref }}
source-repository-identifier: "project_id"
source-repository-owner-uri: "{{ .url }}/{{ .namespace_path }}"
source-repository-owner-identifier: "namespace_id"
build-config-uri: "https://{{ .ci_config_ref_uri }}"
build-config-digest: "ci_config_sha"
build-trigger: "pipeline_source"
run-invocation-uri: >-
{{ .url }}/{{ .project_path }}/-/jobs/{{ .job_id }}
source-repository-visibility-at-signing: "project_visibility"
deployment-environment: "environment"
subject-alternative-name-template: "https://{{ .ci_config_ref_uri }}"
这部分由 Sigstore 项目维护。应定期检查上游文件的变化,并同步自己的配置。
为制品和容器镜像签名
使用 id_tokens 为任务生成 OIDC 令牌。Cosign 将令牌发送给 Fulcio,由后者签发短期签名证书。
Cosign v3 使用签名配置文件指定 Sigstore 服务端点和信任材料。可以生成一次后分发给 Runner,也可以像下例一样在每次任务中生成。
sign-artifact:
stage: sign
id_tokens:
SIGSTORE_ID_TOKEN:
aud: sigstore
variables:
COSIGN_YES: "true"
script:
- cosign signing-config create
--fulcio="url=http://<sigstore-host>:5555,api-version=1,start-time=2024-01-01T00:00:00Z,operator=my-org"
--rekor="url=http://<sigstore-host>:3000,api-version=1,start-time=2024-01-01T00:00:00Z,operator=my-org"
--rekor-config="ANY"
--oidc-provider="url=https://gitlab.example.com,api-version=1,start-time=2024-01-01T00:00:00Z,operator=my-org"
--out signing-config.json
- cosign trusted-root create
--fulcio="url=http://<sigstore-host>:5555,certificate-chain=/etc/sigstore/fulcio-root.pem,start-time=2024-01-01T00:00:00Z"
--rekor="url=http://<sigstore-host>:3000,public-key=/etc/sigstore/rekor-pub.pem,start-time=2024-01-01T00:00:00Z"
--ctfe="url=http://<sigstore-host>:6962,public-key=/etc/sigstore/ctfe-pub.pem,start-time=2024-01-01T00:00:00Z"
--out trusted-root.json
- cosign sign-blob
--signing-config=signing-config.json
--trusted-root=trusted-root.json
--oidc-client-id=sigstore
--identity-token=$SIGSTORE_ID_TOKEN
--bundle=artifact.bundle
artifact.txt
start-time 表示该服务端点被视为有效的最早时间,其定义见 Sigstore protobuf 规范。实际配置时使用 Sigstore 栈的部署日期。
将 --oidc-client-id 中的 sigstore 替换为 Fulcio OIDC issuer 条目里设置的 client ID。--oidc-provider 必须使用注册在 Fulcio oidc-issuers 配置中的同一个 issuer URL。
为容器镜像签名
使用 cosign sign,将文件路径替换为镜像引用;签名配置相同。
容器镜像仓库必须通过可解析主机名的 HTTPS 地址访问。仓库在自己的外部 URL 上公布认证 realm。Cosign 会拒绝主机为私有或链路本地 IP 字面量的 realm。若 registry_external_url 直接使用 IP 地址,实例可以签署文件,但不能签署容器镜像。
Cosign v2.x 的配置
Cosign v2.x 使用 URL 参数和环境变量,替代 v3 的配置文件:
sign-artifact:
stage: sign
id_tokens:
SIGSTORE_ID_TOKEN:
aud: sigstore
variables:
COSIGN_YES: "true"
SIGSTORE_ROOT_FILE: /etc/sigstore/fulcio-root.pem
SIGSTORE_REKOR_PUBLIC_KEY: /etc/sigstore/rekor-pub.pem
SIGSTORE_CT_LOG_PUBLIC_KEY_FILE: /etc/sigstore/ctfe-pub.pem
script:
- cosign sign-blob
--fulcio-url=http://<sigstore-host>:5555
--rekor-url=http://<sigstore-host>:3000
--oidc-issuer=https://gitlab.example.com
--identity-token=$SIGSTORE_ID_TOKEN
--output-signature=artifact.sig
--output-certificate=artifact.crt
artifact.txt
容器镜像签名请使用前文的 Cosign v3 方式。
Cosign v2 写出的证书是经过 base64 编码的 PEM。在交给其他工具前应先解码。--oidc-issuer 也要使用 Fulcio oidc-issuers 中注册的同一个 issuer URL。
验证签名
验证 Cosign v3 bundle 时,使用信任材料及预期的签名者身份:
cosign verify-blob \
--trusted-root=trusted-root.json \
--bundle=artifact.bundle \
--certificate-oidc-issuer=https://gitlab.example.com \
--certificate-identity=https://gitlab.example.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main \
artifact.txt
--certificate-identity 指定签名证书中的 Subject Alternative Name,由 CI/CD 配置路径组成:
https://<CI_SERVER_HOST>/<CI_PROJECT_PATH>//.gitlab-ci.yml@<full ref>
这个路径模式有三个关键细节:
- 协议始终为
https://,因为 Fulcio 的subject-alternative-name-template固定如此,即使 GitLab 实例本身通过 HTTP 访问也不例外。 .gitlab-ci.yml前的双斜杠是正确的:前一个路径段是项目,其后的空路径段表示默认 CI/CD 配置位置。- 分支流水线的完整引用是
refs/heads/<branch>,标签流水线是refs/tags/<tag>。
验证 Cosign v2 签署的制品时,传入独立签名和证书:
cosign verify-blob \
--signature=artifact.sig \
--certificate=artifact.crt \
--certificate-oidc-issuer=https://gitlab.example.com \
--certificate-identity=https://gitlab.example.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main \
artifact.txt
相关文档
- 公共 Sigstore 与 GitLab.com 的签名示例
- CI/CD OIDC ID 令牌
- Sigstore 自定义组件
排查问题
自托管 Sigstore 签名可能遇到以下问题。
metadata not found for ci provider gitlab-pipeline
Fulcio 配置缺少 ci-issuer-metadata。加入前文配置 Fulcio章节给出的完整配置块。
ctfe public key not found for payload
Cosign 找不到证书透明度日志的公钥。Cosign v3 的 cosign trusted-root create 命令需包含 --ctfe;Cosign v2 需设置 SIGSTORE_CT_LOG_PUBLIC_KEY_FILE。
not enough verified log entries from transparency log
trusted-root.json 的 Rekor 公钥与运行中的 Rekor 密钥不再一致。内存签名器每次重启都会产生新密钥和空 Merkle 树。因此,重启会让信任材料失效,所有任务的签名都会失败,直到信任材料被重建。
从运行中的实例读取当前公钥,然后重新生成 trusted root:
curl --silent --fail "http://<sigstore-host>:3000/api/v1/log/publicKey" --output /etc/sigstore/rekor-pub.pem
cosign trusted-root create \
--fulcio="url=http://<sigstore-host>:5555,certificate-chain=/etc/sigstore/fulcio-root.pem,start-time=2024-01-01T00:00:00Z" \
--rekor="url=http://<sigstore-host>:3000,public-key=/etc/sigstore/rekor-pub.pem,start-time=2024-01-01T00:00:00Z" \
--ctfe="url=http://<sigstore-host>:6962,public-key=/etc/sigstore/ctfe-pub.pem,start-time=2024-01-01T00:00:00Z" \
--out trusted-root.json
将新生成的 trusted-root.json 分发给每个 Runner。要避免问题反复出现,应为 Rekor 配置持久化签名密钥和固定树标识符。
failed to verify signed certificate timestamp
Fulcio 未接入证书透明度日志时,证书缺少签名证书时间戳。此时签名本身可以成功,验证会失败。给 Fulcio 配置指向证书透明度日志的 --ct-log-url,并在创建 trusted root 时包含 --ctfe。
x509: certificate signed by unknown authority
Fulcio 无法验证 GitLab 实例的 TLS 证书。将私有 CA 证书挂载到 Fulcio 容器,并用 SSL_CERT_FILE 指向其路径。
即使 OIDC 提供程序初始化失败,Fulcio 的 /healthz 仍可能报告 SERVING。需要查看容器日志,确认提供程序确实已经加载。
来源:GitLab Inc.,Sign artifacts and container images with self-hosted Sigstore。Copyright (c) 2011-present GitLab Inc.。仓库许可证明确规定 doc/ 内容采用 CC BY-SA 4.0;本中文译稿同样按 CC BY-SA 4.0 提供。修改内容为中文翻译及标题组织,9 个原文代码/输出块逐字保留。Fulcio 声明模板的上游来源链接保留在正文。所有示例仅作静态核对,没有执行部署、签名、验证或网络命令。











暂无评论内容