私有镜像仓库的凭证一旦泄露,风险不只在当前运行的容器:攻击者可能借此读取凭证有权访问的镜像,而下一次扩容、节点替换或工作负载重建也可能因凭证失效而拉取失败。Kubernetes 可以通过命名空间内的 Secret 和 imagePullSecrets 为镜像拉取提供认证,但这只是凭证治理的一部分,还需要限制访问、验证轮换结果并准备回滚。

以下流程适合使用 Kubernetes Secret 保存仓库拉取凭证的集群。开始前应确认变更授权、仓库凭证的签发和撤销方式,以及集群是否已有云厂商凭证组件或其他自动化管理机制。本文中的名称均为示例,操作前请替换,并在非生产环境验证。
准备:盘点引用和影响范围
一次轮换需要同时覆盖仓库端和集群端。先记录仓库地址、凭证所属账号、可访问的仓库或项目、到期时间,以及哪些命名空间和工作负载依赖它。仓库账号尽量只授予所需镜像的拉取权限,不使用管理员账号。
检查前确认集群上下文和命名空间:
kubectl config current-context
kubectl get namespaces以 app-prod 命名空间为例,列出 Secret 的名称和类型,以及 ServiceAccount、Pod 使用的引用:
kubectl -n app-prod get secrets \
-o custom-columns=NAME:.metadata.name,TYPE:.type
kubectl -n app-prod get serviceaccounts \
-o custom-columns=NAME:.metadata.name,PULL_SECRETS:.imagePullSecrets[*].name
kubectl -n app-prod get pods \
-o custom-columns=NAME:.metadata.name,SA:.spec.serviceAccountName,PULL_SECRETS:.spec.imagePullSecrets[*].name
kubectl -n app-prod get deployments \
-o custom-columns=NAME:.metadata.name,SA:.spec.template.spec.serviceAccountName,PULL_SECRETS:.spec.template.spec.imagePullSecrets[*].name还应检查 StatefulSet、DaemonSet、Job、CronJob 和直接创建的 Pod;有多个命名空间时逐一检查。这些命令需要相应资源的读取权限,权限不足时应由授权管理员执行,而不是临时扩大普通账号权限。
不要为了盘点而导出 Secret 内容。 避免对 Secret 使用包含数据的 -o yaml、-o json,也不要把解码后的凭证写入工单、终端录屏或 CI 日志。上面的 Secret 清单仍需读取 Secret 资源;格式化输出只减少终端展示,并不缩小 API 权限。
理解命名空间和引用边界
imagePullSecrets 引用的是 Pod 所在命名空间中的 Secret,不能直接引用其他命名空间的同名对象。多个命名空间需要使用同一仓库时,应分别在各自命名空间中配置 Secret,并按各自工作负载核对;不要以为在一个命名空间更新 Secret 就会自动更新其他命名空间。
ServiceAccount 可以为使用它的新 Pod 提供默认的 imagePullSecrets。如果 Pod 模板已经显式配置了该字段,不应假设它会与 ServiceAccount 上的列表自动合并;应以新建 Pod 的实际配置为准。修改 ServiceAccount 也不会追溯改写已有 Pod 的配置,因此轮换时必须检查控制器模板和新建 Pod。
实施:收敛 Secret 和工作负载权限
使用专用 ServiceAccount
下面的配置将专用 ServiceAccount 与同命名空间的拉取 Secret 关联:
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-runtime
namespace: app-prod
automountServiceAccountToken: false
imagePullSecrets:
- name: registry-pull-v2automountServiceAccountToken: false 适用于应用不需要通过自动挂载的令牌访问 Kubernetes API 的场景;它不等同于关闭镜像拉取认证。若应用确实需要访问 API,应另行评估令牌和权限配置。
Deployment 的 Pod 模板可引用该 ServiceAccount:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
namespace: app-prod
spec:
replicas: 2
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
serviceAccountName: app-runtime
containers:
- name: app
image: registry.example.com/team/app:release如果必须让工作负载显式指定凭证,可在 template.spec 中配置:
serviceAccountName: app-runtime
imagePullSecrets:
- name: registry-pull-v2这种做法便于逐个工作负载控制,但也意味着轮换时必须更新所有显式引用。无论采用哪种方式,都不要把仓库密码写入镜像、应用源码、Deployment 清单或普通环境变量。
最小化权限,不只检查 get secrets
限制谁能读取、列出和监听 Secret,也要限制谁能创建或修改 Pod、工作负载和 ServiceAccount。能够在命名空间内创建 Pod 的主体,可能通过挂载 Secret 等方式间接取得该命名空间中的敏感数据;因此,仅撤销直接读取 Secret 的权限并不足以构成完整隔离。
用授权主体检查实际权限,例如:
kubectl auth can-i get secrets -n app-prod
kubectl auth can-i list secrets -n app-prod
kubectl auth can-i watch secrets -n app-prod
kubectl auth can-i create pods -n app-prod
kubectl auth can-i patch deployments.apps -n app-prod
kubectl auth can-i patch serviceaccounts -n app-prod这些命令默认检查当前身份;需要检查其他身份时,应由有权模拟该身份的管理员执行。重点是让应用运行身份、部署系统和凭证维护人员各自只拥有工作所需权限。若多个团队可以互相创建工作负载或读取 Secret,应重新评估命名空间和租户边界。
Secret 的值也需要存储保护。确认集群是否对 API 数据存储启用适当的静态加密、备份访问控制和密钥管理;Base64 编码本身不是加密。
轮换:先新建、再验证、后撤销
常规到期轮换可以保留短暂的旧凭证回退窗口;如果凭证已确认泄露,应优先按事件响应要求限制或撤销旧凭证,即使这会缩短回滚窗口。不要为了方便回滚而继续使用已遭入侵的账号。
| 阶段 | 操作 | 完成依据 |
|---|---|---|
| 准备 | 创建仅有必要拉取权限的新仓库凭证;保留旧配置的非敏感引用记录 | 明确受影响命名空间、工作负载和负责人 |
| 分发 | 在每个目标命名空间创建新名称的 Secret,例如 registry-pull-v2 | 名称、类型和目标命名空间正确 |
| 切换 | 更新对应 ServiceAccount 或工作负载模板 | 新建 Pod 的实际引用指向预期 Secret |
| 验证 | 用真实私有镜像进行受控拉取,并观察仓库和集群事件 | 确认新凭证确实被使用且具备所需权限 |
| 收尾 | 完成观察后撤销旧凭证,移除旧引用和 Secret | 仓库端撤销确认,集群内无预期外旧引用 |
新 Secret 应通过组织批准的密钥管理或部署流程创建,使用 Kubernetes 支持的仓库凭证 Secret 类型。避免将密码直接放入命令行参数、shell 历史、版本库或 CI 明文日志;也不要把包含凭证的完整 Docker 配置文件随意分发给运维人员。
建议使用新名称而不是直接覆盖旧 Secret:这样更容易识别哪些 Pod 使用了新引用,也更便于在旧凭证仍安全有效时回退。切换前记录工作负载当前版本、镜像引用、副本状态和变更方式;若由 GitOps 或其他控制器管理,应同步修改其期望状态,避免人工修改被覆盖。
验证:证明新凭证完成了拉取
仅看到 Pod 运行成功并不一定能证明新凭证有效:节点可能已有镜像缓存,也可能存在其他可用认证来源。应在受控环境使用能够区分新旧凭证的仓库审计记录,并结合集群镜像拉取策略、节点缓存和其他凭证机制判断。必要时选择未缓存的测试镜像或受控测试节点,避免对生产仓库和节点造成意外负载。
可以先创建一个测试 Pod,显式使用新 Secret,隔离 ServiceAccount 继承问题:
apiVersion: v1
kind: Pod
metadata:
name: registry-pull-check
namespace: app-prod
spec:
restartPolicy: Never
imagePullSecrets:
- name: registry-pull-v2
containers:
- name: check
image: registry.example.com/team/pull-test:release
imagePullPolicy: Always使用已获准的私有测试镜像替换示例镜像。Always 有助于触发镜像拉取检查,但仍应结合实际节点、运行时和仓库日志确认认证来源,不能单凭该字段断言使用了新凭证。测试完成后删除测试 Pod。
kubectl -n app-prod apply -f registry-pull-check.yaml
kubectl -n app-prod describe pod registry-pull-check
kubectl -n app-prod get events --sort-by=.metadata.creationTimestamp验证显式 Secret 成功后,再用实际 ServiceAccount 创建测试 Pod,或通过受控方式更新少量工作负载副本,检查新 Pod 的 serviceAccountName 和 imagePullSecrets 是否符合预期。生产环境应分批进行,并观察可用副本数、调度和应用健康状态。
区分认证失败与其他拉取故障
ErrImagePull 和 ImagePullBackOff 表示拉取遇到问题或正在退避,不自动等于密码错误。优先查看 Pod 事件和仓库侧记录:
FailedToRetrieveImagePullSecret:检查 Secret 是否位于 Pod 的命名空间、名称是否拼写正确,以及实际 Pod 引用是否与预期一致。- 认证或授权失败:核对仓库地址、凭证有效期、账号权限和目标镜像路径;注意区分认证成功但无权访问目标仓库。
- 网络、DNS、TLS 或仓库不可用:检查节点到仓库的连接、证书信任和仓库服务状态,不要反复轮换凭证掩盖故障。
- 镜像不存在或引用错误:核对镜像名称、标签或摘要,以及仓库中的实际内容。
Kubernetes 官方文档也建议在拉取失败时检查 Pod 事件,特别是无法取得拉取 Secret 的提示,参见拉取私有仓库镜像。
失败回滚:恢复引用,也恢复可用能力
回滚前先判断故障范围:是测试 Pod、单个命名空间,还是多个工作负载;同时确认旧凭证是否仍有效且安全。不要立即删除健康的旧 Pod,尤其是在新副本无法启动时。
- 暂停扩大变更。 停止继续切换其他命名空间或副本,保留事件、变更记录和仓库认证日志。
- 恢复旧引用。 如果修改的是工作负载模板,恢复原有
imagePullSecrets或原有模板版本;如果修改的是 ServiceAccount,恢复其旧引用,并确保后续新建 Pod 实际获得该引用。 - 通过受控重建验证。 已创建 Pod 的引用不会因 ServiceAccount 更新而自动改变。根据工作负载的可用性要求,逐步创建或替换 Pod,确认旧配置能够拉取并恢复服务。
- 处理不安全的旧凭证。 若旧凭证已泄露或被撤销,不应将其重新启用作为常规回滚;应使用事先准备的独立应急凭证,或修复新凭证后重新切换。
- 同步声明式配置。 回滚 GitOps 或部署系统中的期望状态,防止控制器再次应用失败配置。
对于 Deployment,可以在确认修订历史及其包含的变更后,考虑使用 kubectl rollout undo 恢复工作负载模板;它不会自动撤销独立的 ServiceAccount 或 Secret 修改,也不能恢复仓库端已经撤销的凭证。回滚后仍需检查实际 Pod、服务健康和仓库访问记录。
审计与平台差异
审计记录应能回答:谁在何时修改了哪个 Secret 的元数据、ServiceAccount 或工作负载引用,以及随后发生了哪些仓库认证和拉取失败。 将 Kubernetes 审计事件与仓库认证日志、部署记录和告警关联,并限制日志访问、设置保留期限。
审计策略需要特别注意 Secret 数据:不要为了排查而把 Secret 请求或响应内容广泛写入审计日志。实际可记录的细节取决于集群审计配置、日志后端和仓库能力,变更前应与安全和平台团队确认。
云平台的自动凭证组件也可能改变操作方式。例如,阿里云文档说明,特定免密组件会管理 ServiceAccount 的拉取凭证,而在工作负载模板中手动配置 imagePullSecrets 可能使该组件失效;使用自定义 ServiceAccount 时也需要调整组件配置。采用此类方案时,应先核对对应组件的官方说明,不要直接套用静态 Secret 的切换步骤。
最后复盘旧凭证是否已撤销、旧 Secret 和引用是否已清理、所有目标命名空间是否完成验证,以及应急凭证和负责人是否明确。imagePullSecrets 解决的是镜像拉取认证问题:即使认证成功,也不能证明镜像来源可信或不存在漏洞;镜像签名验证、漏洞扫描和供应链策略仍需独立实施。
- it2021
- it2021.com
- Kubernetes
- test
- 安全运维
- 漏洞扫描
- 访问控制





广东 深圳 1F
节点缓存这坑确实容易忽略
广东 深圳 2F
轮换前先确认仓库审计能区分账号
重庆 重庆 3F
旧凭证泄露时还得提前备好应急方案
4F
多命名空间逐个核对挺考验细心