镜像扫描、SBOM、签名与准入 Hands-on
验证:未记录
- 适用版本
- 未记录
- 验证范围
- 尚未登记验证记录。
本文缩写(英文全称与中文含义)
| 缩写 | 英文全称/名称 | 中文含义 |
|---|---|---|
| API | Application Programming Interface | 应用程序编程接口 |
| AWS | Amazon Web Services | 亚马逊云服务 |
| CI | Continuous Integration | 持续集成 |
| CLI | Command-Line Interface | 命令行接口 |
| CVE | Common Vulnerabilities and Exposures | 通用漏洞披露标识体系 |
| DB | Database | 数据库 |
| KMS | Key Management Service | 密钥管理服务 |
| OCI | Open Container Initiative | 开放容器倡议及其镜像/运行时规范 |
| PEM | Privacy-Enhanced Mail | 常用于证书/密钥的文本封装格式 |
| SBOM | Software Bill Of Materials | 软件物料清单 |
场景:同一订单镜像经过扫描、签名、准入后晋级;不重新构建生产镜像。前置:Kyverno、私有 OCI registry、已批准的 Trivy/Cosign/crane CLI、短期 CI 凭据。镜像仓库支持签名相关 OCI 工件,控制器可认证访问它。
1. 固定镜像与漏洞库#
将本节作为 Bash 脚本运行,失败立即退出,禁止扫描失败后仍继续签名:
set -euo pipefail
export IMAGE_REPO='registry.example.com/orders/api'
export BUILD_TAG='REPLACE_IMMUTABLE_BUILD_TAG'
DIGEST=$(crane digest "$IMAGE_REPO:$BUILD_TAG")
export DIGEST
[[ "$DIGEST" =~ ^sha256:[0-9a-f]{64}$ ]]
export IMAGE="$IMAGE_REPO@$DIGEST"
trivy --version
cosign version
trivy image --format cyclonedx --output sbom.cdx.json "$IMAGE"
trivy image --severity HIGH,CRITICAL --exit-code 1 --format json --output vulnerabilities.json "$IMAGE"扫描失败阻断发布;例外必须有 CVE、影响评估、负责人、到期时间。不要用全局 ignore-unfixed 掩盖风险。记录扫描器/DB 更新时间;SBOM 不是“无漏洞”证明,多架构镜像需覆盖生产实际平台。
2. 用企业 KMS 签名并验证#
以 AWS KMS 为例,预先创建专用非对称签名 key,CI 只允许指定 key 的 Sign/GetPublicKey,节点不持有签名权限:
先确定透明日志服务与数据披露策略,再执行签名。 私有环境预先配置企业 Sigstore 服务或所选版本支持的离线方案;下列命令继承已批准的配置,不能在配置未知时直接使用公共默认服务。
export COSIGN_KEY='awskms:///REPLACE_KMS_KEY_ARN'
cosign public-key --key "$COSIGN_KEY" > cosign.pub
cosign sign --key "$COSIGN_KEY" "$IMAGE"
cosign verify --key cosign.pub "$IMAGE" > signature-verification.json
cosign attest --key "$COSIGN_KEY" --type cyclonedx --predicate sbom.cdx.json "$IMAGE"
cosign verify-attestation --key cosign.pub --type cyclonedx "$IMAGE" > sbom-verification.jsonCI 中签名步骤必须依赖扫描 job 成功;若跨 job,用受保护的同一 digest/扫描结果传递,不能在签名阶段重新解析可变 tag。公开 key 入平台 repo;签名私钥不能下载到 Git/流水线文件。
3. 配置准入验签#
下例使用 Kyverno ClusterPolicy verifyImages,适用于支持该 API 的已固定版本;新版本其他策略 API 不直接混用。保存 verify-orders.yaml,把 cosign.pub 的完整 PEM 替换到 publicKeys:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata: {name: verify-orders-images}
spec:
validationFailureAction: Enforce
background: false
webhookTimeoutSeconds: 30
rules:
- name: trusted-orders-image
match:
any:
- resources:
kinds: [Pod]
namespaces: [orders]
verifyImages:
- imageReferences: ['registry.example.com/orders/*']
required: true
mutateDigest: true
verifyDigest: true
attestors:
- entries:
- keys:
publicKeys: |-
REPLACE_WITH_COMPLETE_PEM_PUBLIC_KEY该规则只验证匹配仓库,不会拒绝其他仓库,因此同时建立仓库白名单。保存 allowed-registry.yaml:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata: {name: orders-allowed-images}
spec:
validationFailureAction: Enforce
background: true
rules:
- name: approved-repository
match:
any:
- resources:
kinds: [Pod]
namespaces: [orders]
validate:
message: 'orders 容器必须使用受信任仓库。'
foreach:
- list: 'request.object.spec.[containers, initContainers, ephemeralContainers][]'
pattern:
image: 'registry.example.com/orders/*'正式规则允许哪些 mesh/诊断镜像要逐项定义且同样验签;不能给任意 sidecar 开放整个仓库。为 Kyverno admission controller 配置只读 registry 凭据及 KMS/证书信任,参照所选版本 imagePullSecrets 配置;先在独立 namespace 验证,再覆盖业务。
kubectl apply --dry-run=server -f verify-orders.yaml -f allowed-registry.yaml
kubectl apply -f verify-orders.yaml -f allowed-registry.yaml
kubectl -n orders rollout restart deployment/orders-api
kubectl -n orders rollout status deployment/orders-api --timeout=5m4. 正反向验收与轮换#
在 故障篇的隔离 Deployment 副本测试:已签 digest 成功;同仓库未签 digest 被拒;非白名单仓库被拒;篡改镜像后的 digest 被拒;registry 不可达时观察 timeout/拒绝及告警,已有运行 Pod 不会自动退出。
SBOM 签名证明来源,若需强制漏洞门禁,还应添加受信扫描 attestation 校验及 freshness 约束;不能因为本篇只验镜像签名就宣称准入已验证漏洞结果。
轮换:准入先接受新旧公钥→CI 使用新 key→重新签名仍需运行的旧镜像→验收所有历史回滚镜像→移除旧信任。失败时恢复已签旧 digest;不删除全部验签策略恢复发布。