LabHub
学习 学习路径 课程

CKS — Kubernetes 安全专家

镜像固定与来源管控

在 LabHub 中继续学习

目标

建立一套标准配置:将进入集群的镜像固定到 Digest,将来源限制为允许列表,并在 ServiceAccount 层级处理私有 Registry 认证。

为什么重要

标签是可变指针。同一个 v1.2 标签可以推送不同镜像,因此昨天验证的镜像可能不同于今天运行的镜像。Digest 是内容哈希,从根本上消除了这一问题。发生事故时,能否立即回答“当前运行的究竟是什么”,会直接决定响应速度。

接下来是来源控制。允许的 Registry 列表会直接成为策略引擎的参数,imagePullSecrets 则是连接该 Registry 的凭据。与其在每个 Pod 中填写,不如附加到 ServiceAccount,让新工作负载自动继承,从而减少遗漏。

此环境无法访问互联网,因此不能真正拉取镜像,也无法安装 Kyverno 等策略引擎 CRD。所以策略清单以文件形式编写和评分,其他部分则按真实对象评分。

步骤

  1. 创建命名空间 cks-supply,并在其中创建 Pod pinned。镜像不使用标签,而固定到 Digest(registry.cks.local/shop/api@sha256: 后跟 64 位十六进制数)。imagePullPolicyIfNotPresent
  2. /root/cks-supply-chain/allowed-registries.txt 中逐行写入允许的 Registry prefix,严格按以下顺序写 4 行:registry.cks.local/harbor.cks.local/library/registry.k8s.io/ghcr.io/cks-lab/
  3. cks-supply 中创建类型为 kubernetes.io/dockerconfigjson 的 Secret harbor-pull。服务器为 harbor.cks.local,用户名为 robot$cks,密码为 cks-lab-token
  4. cks-supply 中创建 ServiceAccount deployer,并在其 imagePullSecrets 中加入 harbor-pull
  5. /root/cks-supply-chain/verify-images.yaml 中编写签名验证策略清单。apiVersion: kyverno.io/v1kind: ClusterPolicy,名称为 verify-image-signaturespec.validationFailureActionEnforce;唯一规则的 spec.rules[0].namecheck-signature,并通过 verifyImages[0].imageReferences[0]registry.cks.local/* 设为目标。
  6. cks-supply 中创建 Pod legacy-web(镜像 nginx:latest),复现未固定工作负载。然后在 /root/cks-supply-chain/find-unpinned.sh 中编写检测脚本,并将执行结果保存到 /root/cks-supply-chain/unpinned.txt。结果应列出 cks-supply 命名空间中容器镜像未固定到 @sha256: 的 Pod,格式为 cks-supply/<파드이름>,按字典序排序,每行一个。
  7. cks-supply 中创建 Deployment checkout。replicas 为 2,选择器和 Pod 标签为 app=checkoutserviceAccountNamedeployer,容器名称为 app;镜像以 registry.cks.local/ 开头并固定到 @sha256:imagePullPolicyIfNotPresent

参考

使用 Digest 而非标签固定镜像

创建命名空间 cks-supply,并在其中创建 Pod pinned。镜像不使用标签,而固定到 Digest(registry.cks.local/shop/api@sha256: 后跟 64 位十六进制数)。imagePullPolicyIfNotPresent

镜像引用格式为 <레지스트리>/<이름>@sha256:<64자리 16진수>。不要同时使用标签和 Digest,只保留 Digest。

允许的 Registry 列表

/root/cks-supply-chain/allowed-registries.txt 中逐行写入允许的 Registry prefix,严格按以下顺序写 4 行: registry.cks.local/harbor.cks.local/library/registry.k8s.io/ghcr.io/cks-lab/

该列表会原样传给策略引擎。使用 prefix 格式并保留末尾斜杠,避免相似名称的其他 Registry 通过。

Registry 认证 Secret

cks-supply 中创建类型为 kubernetes.io/dockerconfigjson 的 Secret harbor-pull。 服务器为 harbor.cks.local,用户名为 robot$cks,密码为 cks-lab-token

一行 kubectl create secret docker-registry 即可。类型名称是 kubernetes.io/dockerconfigjson,数据键为 .dockerconfigjson

为 ServiceAccount 添加 pull Secret

cks-supply 中创建 ServiceAccount deployer,并在其 imagePullSecrets 中加入 harbor-pull

加入 ServiceAccount 的 imagePullSecrets 后,所有使用该 SA 的 Pod 都会自动认证,比逐个 Pod 配置更可靠。

签名与 SBOM 验证策略清单

/root/cks-supply-chain/verify-images.yaml 中编写签名验证策略清单。 apiVersion: kyverno.io/v1kind: ClusterPolicy,名称为 verify-image-signaturespec.validationFailureActionEnforce;唯一规则(spec.rules[0].namecheck-signature)通过 verifyImages[0].imageReferences[0]registry.cks.local/* 设为目标。

此集群没有策略引擎 CRD,因此只编写文件。通过 imageReferences 选择目标 Registry,并在 attestors 中放置公钥。

检测未固定 Digest 的 Pod

cks-supply 中创建 Pod legacy-web(镜像 nginx:latest),复现未固定工作负载。 然后在 /root/cks-supply-chain/find-unpinned.sh 中编写检测脚本,并将执行结果保存到 /root/cks-supply-chain/unpinned.txt。结果应列出 cks-supply 命名空间中镜像未固定到 @sha256: 的容器所在 Pod,格式为 cks-supply/<파드이름>,按字典序排序,每行一个。

镜像字符串不含 @sha256: 即为未固定。可以使用 jq 的 containstest 过滤,同时不要遗漏 init 容器。

综合:具备固定、认证与来源控制的部署

cks-supply 中创建 Deployment checkout。replicas 为 2,选择器和 Pod 标签为 app=checkoutserviceAccountNamedeployer,容器名称为 app,镜像以 registry.cks.local/ 开头并固定到 @sha256:imagePullPolicyIfNotPresent

原样使用前面创建的 ServiceAccount 和允许列表中的第一个 prefix。将镜像固定到 Digest,并同时指定 imagePullPolicy。