教程:使用构建治理数据注释容器镜像
注释提供了关于构建过程的有价值的元数据。这些信息用于审计和可追溯性。在安全事件中,详细的来源数据可以显著加快调查和补救过程。
本教程描述了如何设置极狐GitLab流水线来自动化构建、签名和使用 Cosign 注释容器镜像的过程。您可以配置您的 .gitlab-ci.yml 文件来构建、推送和签署 Docker 镜像,并将其推送到极狐GitLab容器仓库。
要注释容器镜像:
当您将所有步骤结合起来时,您的 .gitlab-ci.yml 应该类似于本教程结尾提供的示例配置。
在您开始之前
您必须具备:
- 安装了 Cosign v2.0 或更高版本。
- 对于极狐GitLab私有化部署,极狐GitLab容器仓库配置了元数据库以显示签名。
设置镜像和服务镜像
在 .gitlab-ci.yml 文件中,使用 docker:latest 镜像并启用 Docker-in-Docker 服务以允许 Docker 命令在 CI/CD 作业中运行。
yamlbuild_and_sign: stage: build image: docker:latest services: - docker:dind # Enable Docker-in-Docker service to allow Docker commands inside the container
定义 CI/CD 变量
使用极狐GitLab CI/CD 预定义变量定义镜像标签和 URI 的变量。
yamlvariables: IMAGE_TAG: $CI_COMMIT_SHORT_SHA # Use the commit short SHA as the image tag IMAGE_URI: $CI_REGISTRY_IMAGE:$IMAGE_TAG # Construct the full image URI with the registry, project path, and tag COSIGN_YES: "true" # Automatically confirm actions in Cosign without user interaction FF_SCRIPT_SECTIONS: "true" # Enables GitLab's CI script sections for better multi-line script output
准备 OIDC 令牌
设置一个 OIDC 令牌用于使用 Cosign 的无密钥签名。
yamlid_tokens: SIGSTORE_ID_TOKEN: aud: sigstore # Provide an OIDC token for keyless signing with Cosign
准备容器
在 .gitlab-ci.yml 文件的 before_script 部分:
- 安装 Cosign 和 jq(用于 JSON 处理):apk add --no-cache cosign jq
- 启用使用 CI/CD 作业令牌登录极狐GitLab容器仓库:docker login -u "gitlab-ci-token" -p "$CI_JOB_TOKEN" "$CI_REGISTRY"
流水线首先设置必要的环境。
构建和推送镜像
在 .gitlab-ci.yml 文件的 script 部分,输入以下命令以构建 Docker 镜像并将其推送到极狐GitLab容器仓库。
yaml- docker build --pull -t "$IMAGE_URI" . - docker push "$IMAGE_URI"
此命令使用当前目录的 Dockerfile 创建镜像,并将其推送到仓库。
使用 Cosign 签署镜像
在构建并将镜像推送到极狐GitLab容器仓库后,使用 Cosign 签署它。
在 .gitlab-ci.yml 文件的 script 部分,输入以下命令:
yaml1- IMAGE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE_URI") 2- | 3 cosign sign "$IMAGE_DIGEST" \ 4 --annotations "com.gitlab.ci.user.name=$GITLAB_USER_NAME" \ 5 --annotations "com.gitlab.ci.pipeline.id=$CI_PIPELINE_ID" \ 6 # Additional annotations removed for readability 7 --annotations "tag=$IMAGE_TAG"
此步骤检索镜像摘要。然后使用 Cosign 签署镜像,并添加多个注释。
验证签名和注释
签署镜像后,验证签名和添加的注释是至关重要的。
在 .gitlab-ci.yml 文件中,使用 cosign verify 命令包含一个验证步骤:
yaml1- | 2 cosign verify \ 3 --annotations "tag=$IMAGE_TAG" \ 4 --certificate-identity "$CI_PROJECT_URL//.gitlab-ci.yml@refs/heads/$CI_COMMIT_REF_NAME" \ 5 --certificate-oidc-issuer "$CI_SERVER_URL" \ 6 "$IMAGE_URI" | jq .
验证步骤确保附加到镜像的来源数据是正确的,并且没有被篡改。cosign verify 命令验证签名并检查注释。输出显示您在签名过程中添加到镜像的所有注释。
在输出中,您可以看到之前添加的所有注释,包括:
- 极狐GitLab用户名
- 流水线 ID 和 URL
- 作业 ID 和 URL
- 提交 SHA 和参考名称
- 项目路径
- 镜像来源和修订
通过验证这些注释,您可以确保镜像的来源数据是完整的,并且与您根据构建过程期望的相匹配。
示例 .gitlab-ci.yml 配置
当您遵循上述所有步骤时,您的 .gitlab-ci.yml 应该类似于:
yaml1stages: 2 - build 3 4build_and_sign: 5 stage: build 6 image: docker:latest 7 services: 8 - docker:dind # Enable Docker-in-Docker service to allow Docker commands inside the container 9 variables: 10 IMAGE_TAG: $CI_COMMIT_SHORT_SHA # Use the commit short SHA as the image tag 11 IMAGE_URI: $CI_REGISTRY_IMAGE:$IMAGE_TAG # Construct the full image URI with the registry, project path, and tag 12 COSIGN_YES: "true" # Automatically confirm actions in Cosign without user interaction 13 FF_SCRIPT_SECTIONS: "true" # Enables GitLab's CI script sections for better multi-line script output 14 id_tokens: 15 SIGSTORE_ID_TOKEN: 16 aud: sigstore # Provide an OIDC token for keyless signing with Cosign 17 before_script: 18 - apk add --no-cache cosign jq # Install Cosign (mandatory) and jq (optional) 19 - docker login -u "gitlab-ci-token" -p "$CI_JOB_TOKEN" "$CI_REGISTRY" # Log in to the Docker registry using GitLab CI token 20 script: 21 # Build the Docker image using the specified tag and push it to the registry 22 - docker build --pull -t "$IMAGE_URI" . 23 - docker push "$IMAGE_URI" 24 25 # Retrieve the digest of the pushed image to use in the signing step 26 - IMAGE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE_URI") 27 28 # Sign the image using Cosign with annotations that provide metadata about the build and tag annotation to allow verifying 29 # the tag->digest mapping (https://github.com/sigstore/cosign?tab=readme-ov-file#tag-signing) 30 - | 31 cosign sign "$IMAGE_DIGEST" \ 32 --annotations "com.gitlab.ci.user.name=$GITLAB_USER_NAME" \ 33 --annotations "com.gitlab.ci.pipeline.id=$CI_PIPELINE_ID" \ 34 --annotations "com.gitlab.ci.pipeline.url=$CI_PIPELINE_URL" \ 35 --annotations "com.gitlab.ci.job.id=$CI_JOB_ID" \ 36 --annotations "com.gitlab.ci.job.url=$CI_JOB_URL" \ 37 --annotations "com.gitlab.ci.commit.sha=$CI_COMMIT_SHA" \ 38 --annotations "com.gitlab.ci.commit.ref.name=$CI_COMMIT_REF_NAME" \ 39 --annotations "com.gitlab.ci.project.path=$CI_PROJECT_PATH" \ 40 --annotations "org.opencontainers.image.source=$CI_PROJECT_URL" \ 41 --annotations "org.opencontainers.image.revision=$CI_COMMIT_SHA" \ 42 --annotations "tag=$IMAGE_TAG" 43 44 # Verify the image signature using Cosign to ensure it matches the expected annotations and certificate identity 45 - | 46 cosign verify \ 47 --annotations "tag=$IMAGE_TAG" \ 48 --certificate-identity "$CI_PROJECT_URL//.gitlab-ci.yml@refs/heads/$CI_COMMIT_REF_NAME" \ 49 --certificate-oidc-issuer "$CI_SERVER_URL" \ 50 "$IMAGE_URI" | jq . # Use jq to format the verification output for easier readability