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 的途径,每种方式在自动化轮换场景中的适用性不同:
- kubectl 命令式创建:
kubectl create secret generic或kubectl create secret tls,适合手动操作和快速验证。 - YAML 声明式创建:通过
kubectl apply -f提交 Secret 清单,适合 GitOps 工作流。 - Kubernetes API 直接创建:通过 REST API POST 到
/api/v1/namespaces/{ns}/secrets,适合控制器和自动化工具。 - 控制器/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 数据的人都可以解码并读取敏感信息。
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,即使准入控制器成功轮换了 Secret 数据,Pod 仍然持有旧值直到重启。在自动化轮换准入策略中,必须结合
kubectl rollout restart 或 原地升级 机制,确保 Pod 在 Secret 轮换后重新加载新值。Volume 挂载方式虽然支持自动同步,但应用代码必须正确处理文件变化事件,否则仍可能使用缓存中的旧值。