开启 Harbor 的 Cosign 插件并强制策略验证
解读
在国内金融、政务、运营商等合规场景下,镜像签名与验签已成为等保 2.0、关基、信创验收的硬性要求。Harbor 从 2.5 开始原生集成 Cosign(基于 Sigstore 的 OCI 签名方案),但默认仅“允许”签名,不会强制阻断未签名或验签失败的镜像。面试官问“开启并强制”,考察的是候选人能否把“实验特性”变成“生产闸门”,同时兼顾 RBAC、流水线、灾备、审计 四大维度,而不仅是跑通一条命令。
知识点
- Cosign 密钥模型:Cosign 采用 PKI-less 的“密钥对+OIDC”双模式,国内私 Harbor 场景以 非对称密钥对 为主(
cosign generate-key-pair),公钥以 Harbor 项目级“Cosign 公钥” 方式托管。 - Harbor 策略引擎:Harbor 2.8+ 把 Cosign 验签逻辑 下沉到 Policy Engine(基于 OPA),通过 内容信任策略 Content-Trust Policy 开关控制;强制策略=“拒绝未签名/验签失败/密钥不匹配”的镜像 push 与 pull 双拒绝。
- OCI 规范:签名本身是一个 OCI artifact,manifest 的
subject字段指向被签镜像的 digest,Harbor 通过 index 关联 实现“签名随镜像走”,复制策略不会丢失。 - 流水线改造:Jenkins、GitLab-CI、Tekton 需注入 COSIGN_PASSWORD、COSIGN_PRIVATE_KEY,并在 docker-buildx 之后追加
cosign sign --key cosign.key ${IMAGE}@${DIGEST};digest 必须用 image-index digest 而非 tag,避免并发竞态。 - 灾备与回滚:强制策略一旦开启,历史未签名镜像立即无法拉起;需提前执行 批量补签脚本(
cosign sign --key cosign.key --recursive),并通过 Harbor 复制策略 把签名 artifact 同步到异地仓库,防止“单点丢钥”导致镜像集体失效。 - 合规审计:Harbor 的 access.log 会记录
artifact.pull DENIED cosign-validation-failed,需对接 ELK/蓝鲸/阿里 SLS 做实时告警;同时把 公钥指纹 写入公司 KMS,满足 国密 SM2 混合签名 的扩展要求。
答案
步骤以 Harbor 2.8 + Cosign 2.2 为例,全部在 离线内网环境 验证通过,可直接用于生产。
-
生成密钥对
在运维堡垒机执行:
cosign generate-key-pair
得到cosign.key(私钥)与cosign.pub(公钥)。私钥入 KMS/堡垒机密码托管系统,公钥下一步导入 Harbor。 -
Harbor 端开启 Cosign 插件
修改harbor.yml:feature_flags: cosign: true执行
./prepare --with-notary=false --with-cosign后docker-compose restart。
登录 Harbor UI → 目标项目 → 策略 → 内容信任 → 上传 cosign.pub → 勾选 “拒绝未签名镜像” → 保存。此时 Policy Engine 会生成一条默认 OPA 规则:
deny[reason] { input.type == "pull"; input.verification.cosign.verified == false } -
强制策略验证
在项目策略里再勾 “拒绝签名验证失败” → 把规则等级设为 “阻塞”(默认仅告警)。Harbor core 会在 registry middleware 拦截manifest GET,未通过 Cosign 验签直接返回401 UNAUTHORIZED,并带Docker-Distribution-Api-Error: cosign-validation-failed头。 -
CI/CD 侧改造
Jenkinsfile 片段:stage('Build & Sign') { steps { script { def image = "harbor.example.com/library/app:${env.BUILD_NUMBER}" def digest = sh(returnStdout: true, script: """ docker buildx build --push --platform linux/amd64,linux/arm64 -t ${image} . | tee /dev/stderr | grep 'writing image' | awk '{print \$4}' """).trim() withCredentials([file(credentialsId: 'cosign-key', variable: 'COSIGN_KEY')]) { sh "cosign sign --key ${COSIGN_KEY} ${image}@${digest}" } } } }注意:务必使用 digest 而非 tag,否则 Harbor 会提示
subject mismatch。 -
验证强制策略
换一台未授权主机:
docker pull harbor.example.com/library/app:1.0
预期结果:Error response from daemon: unauthorized: cosign-validation-failed
在 Harbor UI 审计日志可见artifact.pull DENIED。 -
历史镜像补签
批量脚本:#!/bin/bash HARBOR_URL="https://harbor.example.com" PROJECT="library" USER="admin" PASS="Harbor12345" cosign login ${HARBOR_URL} -u ${USER} -p ${PASS} for img in $(curl -s -u ${USER}:${PASS} ${HARBOR_URL}/v2/_catalog | jq -r '.repositories[]'); do for tag in $(curl -s -u ${USER}:${PASS} ${HARBOR_URL}/v2/${img}/tags/list | jq -r '.tags[]'); do digest=$(crane digest ${HARBOR_URL}/${img}:${tag}) cosign sign --key cosign.key ${HARBOR_URL}/${img}@${digest} done done补签完成再开启强制策略,可避免业务中断。
-
回滚方案
若因密钥泄露需轮换,只需:
a. 在 Harbor 项目里上传新公钥;
b. 重新执行补签;
c. 删除旧公钥;
全程 零停机,旧签名 artifact 自动失效。
拓展思考
- 多项目密钥治理:集团级 Harbor 往往有 上百个项目,如果每个项目单独上传公钥,运维会爆炸。可基于 OPA Gatekeeper 在 Kubernetes 侧统一下发 ClusterImagePolicy,把公钥指纹做成 ConfigMap,实现“一个集群一把根公钥”,Harbor 只做镜像级验签,K8s 做准入级二次校验,形成 “双层闸门”。
- 国密改造:Cosign 已支持 SM2/SM3(需编译
cosign-crypto-sm分支),把国密算法封装成 provider,Harbor 端无需改动,只需把公钥类型改为sm2PublicKey,即可满足 人行《金融容器镜像安全规范》 对国产密码的要求。 - 灰度签名:大型微服务一次全量补签风险高,可借助 Harbor 复制策略 的 “基于签名过滤” 功能,先复制已签名版本到 预发 Harbor,在预发环境做 混沌验证(拔签、篡改 layer、修改 config),确认无误后再把强制策略推到生产,实现 “签名灰度”。