DevOps全链路实战 | 第 19 天:供应链安全闭环:Trivy 扫描 + cosign 签名 + Kyverno 验签

第 19/19 天 — 系列收官篇。今天我们将打通 DevOps 全链路的最后一公里:从镜像漏洞扫描、签名验签到准入控制,构建完整的供应链安全闭环。

引言:为什么供应链安全至关重要

K8s

在前 18 天的实战中,我们搭建了从代码提交到灰度发布的完整 DevOps 管道。然而,如果一条流水线只关注”能不能跑通”,却忽略了”跑的东西安不安全”,那就如同一条高速运转的流水线没有质检环节——速度越快,风险越大。

近年来,软件供应链攻击事件频发:攻击者通过污染开源依赖、篡改镜像仓库等方式,将恶意代码植入生产环境。SolarWinds 事件、Log4j 漏洞都给业界敲响了警钟。Kubernetes 生态中,容器镜像是最核心的交付物,保障镜像安全就是保障整个交付管道的安全。

今天我们将围绕三个关键工具构建供应链安全闭环:

  • Trivy:全能型漏洞扫描器,扫描镜像、文件系统、IaC 配置
  • cosign:基于 Sigstore 项目的容器镜像签名工具
  • Kyverno:Kubernetes 原生的策略引擎,用于准入控制

三者协同形成”扫描 → 签名 → 验签准入”的完整闭环。

一、核心概念:供应链安全的三大防线

1.1 漏洞扫描(Trivy)

Trivy 是 Aqua Security 开源的安全扫描工具,支持扫描容器镜像、文件系统、Git 仓库、Kubernetes 资源等。它的核心能力包括:

  • OS 包漏洞:扫描 Alpine、Debian、Ubuntu 等基础镜像中的已知漏洞
  • 语言依赖漏洞:扫描 package-lock.json、requirements.txt、go.mod 等
  • IaC 配置扫描:检测 Terraform、Kubernetes YAML 中的配置风险
  • 密钥泄露检测:扫描代码中的硬编码凭证

1.2 镜像签名(cosign)

cosign 是 Sigstore 项目的一部分,用于对容器镜像进行密码学签名。它支持:

  • 密钥对签名:使用 ED25519 或 RSA 密钥对签名
  • Keyless 签名:基于 OIDC 的无密钥签名(Fulcio + Rekor)
  • 透明日志:签名记录存入 Rekor 透明日志,可审计不可篡改

1.3 准入控制(Kyverno)

Kyverno 是专为 Kubernetes 设计的策略引擎,使用 YAML 定义策略,无需学习新的策略语言。它可以在 Admission Controller 阶段拦截不合规的部署请求。

二、Trivy 漏洞扫描部署与集成

2.1 安装 Trivy

在 GitLab Runner 所在的 CI 环境中安装 Trivy:

💻 代码示例

# 下载并安装 Trivy

wget https://github.com/aquasecurity/trivy/releases/download/v0.50.0/trivy_0.50.0_Linux-64bit.tar.gz

tar zxvf trivy_0.50.0_Linux-64bit.tar.gz

mv trivy /usr/local/bin/

 

# 验证安装

trivy –version

2.2 GitLab CI 集成 Trivy 扫描

将 Trivy 扫描集成到第 6 天搭建的 GitLab CI 流水线中,在 Kaniko 构建镜像之后立即扫描:

💻 代码示例

# .gitlab-ci.yml 片段

stages:

– build

– scan

– sign

– deploy

 

trivy-scan:

stage: scan

image: aquasec/trivy:latest

variables:

TRIVY_EXIT_CODE: "1"

TRIVY_SEVERITY: "CRITICAL,HIGH"

script:

# 扫描构建产物镜像(Harbor 中的镜像)

– trivy image –severity CRITICAL,HIGH –exit-code 1

–format json –output trivy-report.json

$HARBOR_REGISTRY/myapp:$CI_COMMIT_SHORT_SHA

# 生成 HTML 报告

– trivy image –format template

–template "@contrib/html.tpl"

–output trivy-report.html

$HARBOR_REGISTRY/myapp:$CI_COMMIT_SHORT_SHA

artifacts:

paths:

– trivy-report.json

– trivy-report.html

expire_in: 30 days

rules:

– if: $CI_PIPELINE_SOURCE == "merge_request_event"

上述配置中,TRIVY_EXIT_CODE: "1" 表示当发现 CRITICAL 或 HIGH 级别漏洞时,CI 任务失败,阻止后续部署。这确保了带严重漏洞的镜像不会被推送到生产环境。

2.3 基础镜像的预扫描

除了扫描业务镜像,我们还应该在流水线入口扫描 Dockerfile 引用的基础镜像,做到尽早发现问题:

💻 代码示例

# 扫描基础镜像 python:3.12-slim

trivy image –severity CRITICAL,HIGH python:3.12-slim

 

# 忽略特定 CVE(经过评估确认可接受的风险)

cat > .trivyignore << 'EOF'

CVE-2024-XXXXX

CVE-2024-YYYYY

EOF

 

# 使用忽略文件扫描

trivy image –ignorefile .trivyignore –severity CRITICAL,HIGH myapp:latest

三、cosign 镜像签名

3.1 生成签名密钥

在安全的密钥管理系统(如 GitLab CI Variables 或 HashiCorp Vault)中存储密钥。首先生成密钥对:

💻 代码示例

# 生成 cosign 密钥对(会提示设置密码)

cosign generate-key-pair

 

# 输出文件:

# cosign.pub – 公钥(用于验签,可公开)

# cosign.key – 私钥(用于签名,必须保密)

将私钥内容存入 GitLab CI 变量 COSIGN_PRIVATE_KEY,密码存入 COSIGN_PASSWORD。公钥 cosign.pub 提交到代码仓库,供 Kyverno 验签使用。

3.2 GitLab CI 中签名镜像

在 Trivy 扫描通过后,对镜像进行签名:

💻 代码示例

# .gitlab-ci.yml 片段

cosign-sign:

stage: sign

image: gcr.io/projectsigstore/cosign:v2.2.3

variables:

COSIGN_EXPERIMENTAL: "true"

script:

# 登录 Harbor

– cosign login -u $HARBOR_USER -p $HARBOR_PASS $HARBOR_REGISTRY

# 对镜像进行签名

– cosign sign –key env://COSIGN_PRIVATE_KEY

$HARBOR_REGISTRY/myapp:$CI_COMMIT_SHORT_SHA

# 验证签名是否成功

– cosign verify –key cosign.pub

$HARBOR_REGISTRY/myapp:$CI_COMMIT_SHORT_SHA

rules:

– if: $CI_COMMIT_BRANCH == "main"

环境变量 COSIGN_PRIVATE_KEY 和 COSIGN_PASSWORD 通过 GitLab CI/CD Settings → CI/CD Variables 配置,确保密钥不会泄露到代码中。签名操作将签名元数据推送到镜像的 OCI Manifest 中,可通过 cosign verify 验证。

3.3 Keyless 签名模式(进阶)

对于更高安全要求的场景,可以使用 Keyless 模式,无需管理私钥:

💻 代码示例

# Keyless 签名(基于 OIDC 令牌,需集成 GitLab OIDC)

export COSIGN_EXPERIMENTAL=1

 

# 使用 OIDC 令牌签名

cosign sign –identity-token $CI_JOB_JWT_V2

$HARBOR_REGISTRY/myapp:$CI_COMMIT_SHORT_SHA

 

# 验证签名(按 Issuer 和 Subject 过滤)

cosign verify

–certificate-identity "https://gitlab.com/myorg/myapp//.gitlab-ci.yml@refs/heads/main"

–certificate-oidc-issuer "https://gitlab.com"

$HARBOR_REGISTRY/myapp:$CI_COMMIT_SHORT_SHA

Keyless 模式利用 Sigstore 的 Fulcio 证书颁发和 Rekor 透明日志,签名者身份与 OIDC 令牌绑定,审计性更强。

四、Kyverno 验签准入控制

4.1 安装 Kyverno

在 K8s 集群中安装 Kyverno,使用 Helm 部署:

💻 代码示例

# 添加 Kyverno Helm 仓库

helm repo add kyverno https://kyverno.github.io/kyverno/

helm repo update

 

# 安装 Kyverno(命名空间 kyverno)

helm install kyverno kyverno/kyverno

–namespace kyverno

–create-namespace

–set admissionController.replicas=3

–set backgroundController.replicas=2

 

# 验证安装

kubectl get pods -n kyverno

4.2 定义验签策略

创建 ClusterPolicy,要求所有来自 Harbor 的镜像必须经过 cosign 签名才能部署:

💻 代码示例

# require-signed-images.yaml

apiVersion: kyverno.io/v1

kind: ClusterPolicy

metadata:

name: require-cosign-signature

annotations:

policies.kyverno.io/title: Require Cosign Signature

policies.kyverno.io/category: Supply Chain Security

policies.kyverno.io/severity: high

spec:

validationFailureAction: Enforce

rules:

– name: verify-cosign-signature

match:

any:

– resources:

kinds:

– Pod

verifyImages:

– imageReferences:

– "harbor.stellardata.top/*"

attestors:

– entries:

– keys:

publicKeys: |

—–BEGIN PUBLIC KEY—–

<cosign.pub 内容,去掉注释行>

—–END PUBLIC KEY—–

# 签名验证失败时拒绝部署

failureAction: Fail

# 验证通过后将镜像替换为签名摘要版本

mutateDigest: true

应用策略:

💻 代码示例

kubectl apply -f require-signed-images.yaml

 

# 查看策略状态

kubectl get clusterpolicy require-cosign-signature

4.3 测试策略效果

用未签名镜像测试,应被拒绝:

💻 代码示例

# 推送一个未签名镜像到 Harbor

docker pull nginx:alpine

docker tag nginx:alpine harbor.stellardata.top/library/nginx-unsigned:alpine

docker push harbor.stellardata.top/library/nginx-unsigned:alpine

 

# 尝试部署未签名镜像(应被拒绝)

cat << 'EOF' | kubectl apply -f –

apiVersion: v1

kind: Pod

metadata:

name: test-unsigned

namespace: default

spec:

containers:

– name: nginx

image: harbor.stellardata.top/library/nginx-unsigned:alpine

EOF

 

# 输出错误:

# Error from server: admission webhook "validate.kyverno.svc" denied the request:

# resource Pod/default/test-unsigned was blocked due to the following policies:

# require-cosign-signature:

# verify-cosign-signature: image verification failed

使用已签名镜像测试,应成功部署:

💻 代码示例

# 对镜像签名后重新部署

cosign sign –key cosign.key harbor.stellardata.top/library/nginx-unsigned:alpine

 

# 再次尝试部署(应成功)

cat << 'EOF' | kubectl apply -f –

apiVersion: v1

kind: Pod

metadata:

name: test-signed

namespace: default

spec:

containers:

– name: nginx

image: harbor.stellardata.top/library/nginx-unsigned:alpine

EOF

 

# 验证 Pod 运行

kubectl get pod test-signed

五、常见问题与排查

Q1:Trivy 扫描超时或数据库下载失败?

Trivy 首次运行需下载漏洞数据库(约 200MB),在内网环境可能超时。解决方案:

💻 代码示例

# 预置数据库到内网镜像仓库

trivy image –download-db-only –db-repository harbor.stellardata.top/security/trivy-db

 

# 指定内网数据库镜像

export TRIVY_DB_REPOSITORY=harbor.stellardata.top/security/trivy-db

trivy image myapp:latest

Q2:cosign 签名在 CI 中报权限错误?

确保 CI 变量 COSIGN_PASSWORD 正确设置,并且私钥内容未经过多行转义损坏。建议使用 base64 编码存储私钥,在 CI 中解码:

💻 代码示例

# 编码存储

base64 -w 0 cosign.key # 结果存入 CI 变量 COSIGN_PRIVATE_KEY_B64

 

# CI 脚本中解码

echo "$COSIGN_PRIVATE_KEY_B64" | base64 -d > /tmp/cosign.key

cosign sign –key /tmp/cosign.key $IMAGE

Q3:Kyverno 策略导致 Argo CD 同步失败?

Argo CD 部署的资源也需要通过 Kyverno 准入控制。如果镜像未签名,Argo CD 的同步会被拒绝。确保在 GitOps 仓库中只引用已签名的镜像(使用 immutable digest 而非 tag):

💻 代码示例

# GitOps 部署清单中使用摘要

image: harbor.stellardata.top/myapp@sha256:abc123…

六、全链路安全闭环回顾

至此,我们的供应链安全闭环已完整打通:

  1. 代码提交 → GitLab 触发 CI 流水线
  2. Kaniko 构建 → 镜像推送到 Harbor
  3. Trivy 扫描 → 发现 CRITICAL/HIGH 漏洞则流水线中止
  4. cosign 签名 → 扫描通过后对镜像签名
  5. GitOps 部署 → Argo CD 从 Git 仓库同步部署清单
  6. Kyverno 验签 → 准入控制验证镜像签名,未签名镜像拒绝部署
  7. Argo Rollouts 灰度 → 金丝雀渐进式发布到生产环境
  8. Prometheus 监控 → 实时观测应用健康状态
  9. Alertmanager 告警 → 异常自动通知运维团队

整个闭环确保了:没有经过安全扫描的镜像无法进入流水线后段;没有签名的镜像无法部署到 K8s 集群;已部署的应用处于持续监控之下。 这就是”安全左移”和”默认不信任”理念的落地实践。

七、总结

今天我们完成了 DevOps 全链路实战系列的收官之作,构建了从漏洞扫描到准入控制的供应链安全闭环:

  • Trivy 在 CI 阶段拦截带严重漏洞的镜像,实现安全左移
  • cosign 对通过扫描的镜像进行密码学签名,确保镜像不可篡改
  • Kyverno 在 K8s 准入控制层验证签名,未签名镜像无法部署

三者协同配合 GitLab CI、Harbor、Argo CD 形成了纵深防御体系,将安全嵌入到 DevOps 全链路的每一个环节,而非事后补救。

系列完结感言

从第 1 天的架构总览到今天的供应链安全,19 天的内容覆盖了 DevOps 工程师从零搭建生产级 CI/CD 管道所需的全部核心技能。希望这个系列能帮助大家在实际工作中少走弯路,真正落地 DevOps 实践。

下期预告

本系列已全部完结(共 19 天)。后续如果需要进一步深入某个主题,可以关注”(重制版)”系列,我们将以新技术版本和新环境背景重新梳理经典选题。感谢大家的陪伴!

系列大纲

  1. 全链路架构总览:从代码提交到灰度发布的完整管道设计
  2. K8s 集群与网络基础:kubeadm 离线部署与 Cilium 网络插件
  3. Harbor 私有镜像仓库部署与验证:Helm 安装与镜像推送
  4. GitLab CE 自托管部署:代码仓库与项目管理平台
  5. GitLab Runner 配置:K8s Executor 与 RBAC 权限设置
  6. GitLab CI 流水线搭建:.gitlab-ci.yml 与 Kaniko 无守护进程构建
  7. Harbor 镜像版本管理与 Tag 策略配置
  8. Argo CD 部署与 GitOps 配置仓库创建
  9. CI 与 CD 联动:从代码提交到部署的全自动闭环
  10. SonarQube 代码质量检查:SonarQube 部署与 GitLab CI 集成
  11. Prometheus 部署:kube-prometheus-stack 与 ServiceMonitor 指标采集
  12. Grafana 看板搭建:K8s 标准面板与自定义业务看板
  13. 告警规则与 Alertmanager:钉钉/邮件通知渠道配置
  14. Argo Rollouts 安装与基础概念:CRD 与 Rollout 资源定义
  15. 金丝雀发布实战:setWeight 流量分割与 pause 步骤
  16. AnalysisTemplate 指标分析与自动回滚机制
  17. 全链路端到端演示:代码提交→构建→代码检查→灰度→监控→告警完整流程
  18. 生产化加固要点:Harbor/GitLab/Argo CD/SonarQube 高可用方案
  19. 供应链安全闭环:Trivy 扫描 + cosign 签名 + Kyverno 验签(今天)
微信二维码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像 - 恒星
欢迎您留下宝贵的见解!
提交
头像 - 恒星

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容