2. Kubernetes Secrets 基础:Secret 资源类型、创建方式、存储机制

Kubernetes Secret 是集群内存储敏感数据的原生资源对象,专为密码、API 令牌、SSH 密钥、TLS 证书等场景设计。与 ConfigMap 不同,Secret 在数据编码、访问控制和存储机制上均采用更严格的安全策略。理解 Secret 的基础模型是构建自动化轮换准入策略的前提。

2.1 Secret 资源类型与数据结构

Secret 的核心数据结构包含 data 和 stringData 两个字段,前者要求 value 经过 Base64 编码,后者允许明文写入并在 API 层自动编码。Secret 的 type 字段决定了其语义和校验规则。

类型 用途 数据键约定 自动轮换支持
Opaque 通用键值对,任意敏感数据 无约束 需自定义控制器
kubernetes.io/service-account- ServiceAccount 令牌 , ca.crt, namespace 由 TokenRequest API 自动轮换
kubernetes.io/dockercfg Docker 镜像仓库认证 .dockercfg 需手动或外部工具
kubernetes.io/dockerconfigjson Docker 镜像仓库认证(推荐) .dockerconfigjson 需手动或外部工具
kubernetes.io/basic-auth HTTP 基本认证凭据 username, password 需自定义控制器
kubernetes.io/ssh-auth SSH 私钥 ssh-privatekey 需自定义控制器
kubernetes.io/tls TLS 证书与私钥 tls.crt, tls.key cert-manager 等外部工具
bootstrap.kubernetes.io/ 集群引导令牌 -id, -secret 由 kubeadm 管理
最佳实践: 在自动化轮换场景中,优先使用 kubernetes.io/tls 和 kubernetes.io/dockerconfigjson 类型,因为它们具有明确的键约束和成熟的生态工具支持。避免在 Opaque 类型中混合存储多种敏感数据,这会增加准入策略的复杂度。

2.2 Secret 创建方式

Kubernetes 提供四种创建 Secret 的途径,每种方式在自动化轮换场景中的适用性不同:

  1. kubectl 命令式创建:kubectl create secret generic 或 kubectl create secret tls,适合手动操作和快速验证。
  2. YAML 声明式创建:通过 kubectl apply -f 提交 Secret 清单,适合 GitOps 工作流。
  3. Kubernetes API 直接创建:通过 REST API POST 到 /api/v1/namespaces/{ns}/secrets,适合控制器和自动化工具。
  4. 控制器/Operator 自动创建:如 cert-manager 自动生成 TLS Secret,TokenRequest API 自动生成 ServiceAccount 令牌。
# 示例:kubectl 创建 Opaque Secret
kubectl create secret generic db-credentials \
  --from-literal=username=admin \
  --from-literal=password='S3cur3P@ss' \
  --namespace production

# 示例:YAML 声明式创建 TLS Secret
apiVersion: v1
kind: Secret
metadata:
  name: web-tls
  namespace: production
type: kubernetes.io/tls
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t...
  tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQ==
安全警告: YAML 清单中的 data 字段使用 Base64 编码,但 Base64 不是加密。将 Secret 清单提交到版本控制系统时,必须使用 sops、sealed-secrets 或 external-secrets 等工具进行加密。在自动化轮换准入策略中,应禁止直接提交明文 Base64 数据的 Secret 清单。

2.3 Secret 存储机制与 etcd 加密

Secret 在 Kubernetes 中的存储路径为 /registry/secrets/{namespace}/{name},底层存储引擎为 etcd。默认情况下,Secret 数据以 Base64 编码形式存储在 etcd 中,这意味着任何能够访问 etcd 数据的人都可以解码并读取敏感信息。

Secret 存储机制与 etcd 加密层级 kubectl / API Server / 控制器 创建 / 更新 / 读取 Secret 资源 API Server 处理层 Base64 编码 / 类型校验 / 准入控制 etcd 加密层(可选) AES-CBC / AES-GCM / 密钥管理服务 (KMS) etcd 持久化存储 /registry/secrets/{namespace}/{name} 未加密风险区 加密保护层

etcd 加密是保护 Secret 静态存储安全的关键机制。Kubernetes 支持三种加密配置方式:

加密方式 加密算法 密钥管理 性能影响 轮换支持
identity 无加密 不适用 无 不适用
aescbc AES-CBC 本地密钥文件 低 手动密钥轮换
secretbox XChaCha20-Poly1305 本地密钥文件 低 手动密钥轮换
kms 由 KMS 插件决定 外部 KMS(AWS KMS / GCP KMS / Azure Key Vault / HashiCorp Vault) 中(网络延迟) 自动密钥轮换(依赖 KMS)
自动化轮换关键洞察: 在控制平面驱动 Secret 轮换的架构中,etcd 加密层(尤其是 KMS 方式)决定了轮换策略的边界。如果使用 aescbc 或 secretbox,轮换 Secret 数据时需要同时更新 etcd 加密密钥,这增加了轮换操作的原子性要求。推荐在生产集群中启用 kms 加密,将密钥生命周期管理外置,使准入控制器可以专注于 Secret 数据本身的轮换逻辑。

2.4 Secret 的存储大小限制与性能考量

Secret 数据存储在 etcd 中,而 etcd 对单个键值对的大小有限制。Kubernetes 官方建议单个 Secret 的 最大数据量为 1 MB(包括 metadata 和 data 字段)。超过此限制会导致 API Server 拒绝请求。

在自动化轮换场景中,需要关注以下性能指标:

  • API Server 吞吐量:大规模集群中频繁轮换大量 Secret 可能对 API Server 造成压力,建议使用 --max-requests-inflight 和 --max-mutating-requests-inflight 参数进行限流。
  • etcd 写入延迟:每次 Secret 更新都会触发 etcd 写入,轮换频率过高可能导致 etcd 集群写入放大。
  • 控制器冲突:多个控制器同时轮换同一 Secret 可能引发更新冲突,需使用 resourceVersion 乐观锁机制。
# 查看 Secret 大小(单位:字节)
kubectl get secret my-secret -n my-namespace -o json | jq '.data | map_values(length)'

# 示例输出
{
  "password": 24,
  "username": 8
}
轮换策略建议: 对于大型 Secret(接近 1 MB),建议拆分为多个小型 Secret,或使用 external-secrets 等工具将数据存储在外部系统,仅将引用指针存储在 Kubernetes 中。这可以显著降低轮换操作的延迟和失败概率。

2.5 Secret 与 Pod 的绑定机制

Secret 被 Pod 使用时,通过以下两种方式绑定:

  • 环境变量注入:Pod 启动时将 Secret 键值对注入为环境变量。这种方式在 Secret 更新后,Pod 需要重启才能获取新值。
  • Volume 挂载:将 Secret 挂载为 tmpfs 卷,每个键对应一个文件。Kubelet 会定期(默认 60 秒)同步 Secret 更新到挂载点,但 Pod 内运行的进程需要自行检测文件变化。
Secret 与 Pod 绑定方式对比 环境变量注入 Pod 启动时注入 Secret 值 env: DB_PASSWORD=**** Secret 更新后 Pod 必须重启才能获取新值 轮换影响:高 需要滚动更新或原地重启 Volume 挂载 Secret 挂载为 tmpfs 卷 /etc/secrets/password Kubelet 定期同步(默认 60s) 文件内容自动更新 轮换影响:低 应用需监听文件变化或定期重读
轮换设计陷阱: 如果应用使用环境变量方式读取 Secret,即使准入控制器成功轮换了 Secret 数据,Pod 仍然持有旧值直到重启。在自动化轮换准入策略中,必须结合 kubectl rollout restart 或 原地升级 机制,确保 Pod 在 Secret 轮换后重新加载新值。Volume 挂载方式虽然支持自动同步,但应用代码必须正确处理文件变化事件,否则仍可能使用缓存中的旧值。