阶段二 · 密钥与供应链安全

Secret 管理

一句话总结

K8s 原生 Secret 只是 base64 编码, 不是加密, 任何有权限的人或被攻破的 Pod 都能直接读取明文.
生产环境的 Secret 管理需要外部加密存储(Vault)+ 自动同步(External Secrets Operator)+ 最小权限访问控制.

K8s Secret 的局限

K8s 06 篇配置管理中讲过 Secret 基础. 从安全视角看, 原生 Secret 有严重局限:

局限 风险
base64 ≠ 加密 kubectl get secret -o yaml 直接看到明文
etcd 默认不加密 拿到 etcd 备份 = 拿到所有 Secret
RBAC 粒度不够 能读 Secret 就能读 Namespace 下所有 Secret
无审计轮换 Secret 创建后永远不变, 密钥泄露后无感知
存在 Git 仓库 YAML 提交到 Git = 密钥永远留在历史记录中

绝不要把 Secret YAML 提交到 Git

即使 .gitignore 排除了, 如果曾经 commit 过一次, 密钥永远在 git history 中. 攻击者 clone 仓库 + git log --all -p 就能找到所有历史密钥.

etcd 静态加密

最低要求: 开启 etcd 的静态加密(Encryption at Rest), 确保 Secret 在磁盘上是密文:

# EncryptionConfiguration
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {} # fallback: 未加密的旧数据仍可读

局限: 这只保护 etcd 磁盘上的数据. 通过 API 访问(kubectl get secret)仍然返回明文, RBAC 是唯一的防线.

HashiCorp Vault

Vault 是企业级 Secret 管理的事实标准. 核心能力:

能力 K8s Secret Vault
加密存储 需要额外配置 etcd 加密 内置 AES-256 加密
访问控制 RBAC(Namespace 粒度) 细粒度 Policy(按 path/操作)
审计日志 K8s audit log(有限) 完整的读写审计
自动轮换 不支持 Dynamic Secrets(自动生成临时凭证)
租约管理 Secret 有 TTL, 过期自动撤销
多后端 只有 K8s etcd 数据库密码, 云凭证, PKI 证书等

Vault + K8s 认证

Pod 使用自己的 ServiceAccount Token 向 Vault 认证, 获取授权的 Secret:

sequenceDiagram
participant POD as Pod
participant VA as Vault Agent
participant VAULT as Vault Server
participant KA as K8s API

POD->>VA: 需要数据库密码
VA->>VAULT: 认证(SA Token)
VAULT->>KA: 验证 SA Token 有效性
KA-->>VAULT: Token 有效, 属于 order-service SA
VAULT-->>VA: 返回 DB 密码(TTL=1h)
VA-->>POD: 注入密码到文件/环境变量
Note over VA: 到期前自动续租/轮换

Dynamic Secrets

Vault 最强大的能力, 不是存储静态密码, 而是按需生成临时凭证:

  • 数据库: 每个 Pod 获得唯一的短期数据库用户名/密码(TTL=1h), 过期自动删除
  • AWS: 按需生成临时 IAM 凭证, 过期自动撤销
  • PKI: 按需签发短期 TLS 证书

好处: 没有共享密码. 每个 Pod 有自己的凭证, 泄露只影响一个实例, 且会自动过期.

External Secrets Operator(ESO)

ESO 自动将外部 Secret 存储(Vault / AWS Secrets Manager / GCP Secret Manager)同步为 K8s Secret, 让应用代码不需要感知 Vault:

# ExternalSecret: 从 Vault 同步到 K8s Secret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
spec:
refreshInterval: 1h # 每小时同步一次
secretStoreRef:
name: vault-store
kind: ClusterSecretStore
target:
name: db-credentials # 生成的 K8s Secret 名称
data:
- secretKey: username
remoteRef:
key: secret/data/production/database
property: username
- secretKey: password
remoteRef:
key: secret/data/production/database
property: password

ESO 的价值

应用代码仍然通过标准的 K8s Secret(环境变量/文件挂载)读取密钥, 零改造. 密钥的真实来源是 Vault, ESO 负责同步.

这让我们获得 Vault 的安全能力(加密, 审计, 轮换), 同时保持 K8s 原生的使用方式.

Sealed Secrets

解决"Secret YAML 不能提交到 Git"的问题. Sealed Secrets 将 Secret 加密后可以安全地提交到 Git:

开发者本地:
kubectl create secret ... --dry-run -o yaml | kubeseal → SealedSecret YAML(加密的)
→ 提交到 Git(安全! 只有集群内的 Controller 能解密)

集群内:
Sealed Secrets Controller 监听 SealedSecret → 解密 → 生成真实的 K8s Secret
# 加密 Secret
$ kubectl create secret generic db-creds \
--from-literal=password=mysecret \
--dry-run=client -o yaml | \
kubeseal --format yaml > sealed-secret.yaml

# sealed-secret.yaml 可以安全提交到 Git
$ git add sealed-secret.yaml && git commit -m "add sealed db credentials"

方案对比与选型

方案 适用场景 复杂度
K8s Secret + etcd 加密 最低要求, 小团队起步
Sealed Secrets GitOps 流程, 需要 Secret 入 Git
ESO + 云 Secret Manager 云原生环境, 已有 AWS/GCP
ESO + Vault 多云/混合云, 需要高级能力
Vault Agent Sidecar 需要 Dynamic Secrets / 短期凭证

渐进路径

起步: K8s Secret + etcd 加密 + Sealed Secrets(满足 GitOps).
进阶: ESO + 云 Secret Manager 或 Vault(统一管理 + 审计).
高阶: Vault Dynamic Secrets(每个 Pod 唯一临时凭证).

快速回顾

  • K8s Secret 不是加密: base64 编码 + etcd 默认明文存储
  • etcd 加密是最低要求(EncryptionConfiguration)
  • Vault: 加密存储 + 细粒度策略 + 审计 + Dynamic Secrets + 自动轮换
  • ESO: 将 Vault/云密钥管理器同步为 K8s Secret, 应用零改造
  • Sealed Secrets: 解决 Secret 入 Git 的问题
  • 永远不要把 Secret YAML 提交到 Git(用 Sealed Secrets 或 ESO 替代)

动手练习

  1. 检查 etcd 加密状态: 检查集群是否开启了 etcd 加密, kubectl get secret -n kube-system -o yaml 看数据是否是密文
  2. Sealed Secrets 实践: 安装 Sealed Secrets Controller, 用 kubeseal 加密一个 Secret 并提交到 Git, 验证 Controller 自动解密生成真实 Secret
  3. Vault 集成: 用 Docker Compose 部署 Vault dev server, 配置 K8s auth backend, 从 Pod 内使用 SA Token 获取 Vault 中的密钥
  4. ESO 同步: 安装 External Secrets Operator, 创建 ExternalSecret 从 Vault 同步密钥到 K8s Secret