【Kubernetes从入门到精通】第57篇:Secret管理的最佳实践——原生Secret不加密?Vault/SealedSecrets来救场
上一篇【第56篇】NetworkPolicy安全实战——用零信任网络把微服务“关进笼子“下一篇【第58篇】Pod Security Standards——Pod安全的三条红线摘要第021篇我们聊过Secret——它是K8s存敏感信息密码、token、证书的机制。但当时埋了个雷Secret只是Base64编码不是加密。Base64一解码就是明文谁有etcd读权限谁就能看到所有密码。这就像你把钱放枕头底下然后跟小偷说我藏好了你看不见的——Base64就是那个枕头根本挡不住任何人。所以生产环境绝不能只用原生Secret裸奔。这篇文章讲清原生Secret的局限再对比三种主流生产方案Vault动态密钥之王、Sealed SecretsGitOps友好、External Secrets Operator对接云厂商最后给你选型建议。一、原生Secret的致命局限1.1 Base64不是加密【原生 Secret 的真相——皇帝的新衣】 你写的 apiVersion: v1 kind: Secret data: password: cGFzc3dvcmQxMjM ← Base64编码 任何人拿到etcd/Manifest都能 echo cGFzc3dvcmQxMjM | base64 -d → password123 ← 明文秒解 问题清单 1. etcd里存的是Base64(几乎明文) 2. Git里提交Secret Manifest 密码泄露 3. 所有有get secret权限的人都能看 4. 没有轮转机制(改密码要手动改所有引用) 5. 没有审计(谁读了secret不知道)要点K8s Secret的Base64纯粹是为了能在YAML里放二进制没有任何保密意义。唯一的正经防护是etcd静态加密encryption at rest但这只防物理拿到磁盘的场景挡不住有API权限的人。生产级密钥管理需要专门的工具。1.2 至少开启etcd加密如果暂时用不了外部工具至少把etcd的Secret加密存# 配置apiserver的加密配置# /etc/kubernetes/encryption-config.yamlapiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources:[secrets]providers: - aescbc: keys: - name: key1 secret:32字节base64密钥- identity:{}# 兜底(不加密)放最后# 启动时指定kube-apiserver --encryption-provider-config/etc/kubernetes/encryption-config.yaml二、方案1HashiCorp Vault——动态密钥之王2.1 Vault的定位【Vault 是什么——密钥界的银行金库】 Vault 提供 • 静态密钥存储(加密存密码/token/证书) • 动态密钥(临时生成、自动过期、自动吊销!) • 自动轮转 • 细粒度ACL 审计日志 • 多种secret引擎(数据库/SSH/PKI/K8s) 在K8s里的集成方式 ┌──────────────┐ 注入 ┌──────────────┐ │ Vault │ ──────────► │ Pod (通过 │ │ (金库) │ Sidecar │ vault-agent │ │ │ 或 CSI │ 或 Init) │ └──────────────┘ └──────────────┘2.2 Vault Agent Injector# 用Vault的Sidecar自动注入动态密钥apiVersion:v1kind:Podmetadata:name:app-with-vaultannotations:vault.hashicorp.com/agent-inject:truevault.hashicorp.com/role:my-appvault.hashicorp.com/agent-inject-secret-db:database/creds/my-appspec:containers:-name:appimage:my-app# 不用在Pod里写任何密码vault-agent自动把# 动态生成的DB凭据注入 /vault/secrets/dbVault优势说明动态密钥每次生成临时账号泄漏也无所谓自动过期自动轮转密码定期换减少泄露窗口完整审计谁、什么时候、读了什么全记录多引擎数据库/SSH/PKI/K8s统一管要点Vault最厉害的是动态密钥——它不是存一个静态密码而是按需向数据库申请一个临时账号用多久、过期自动吊销。即使这个临时凭据泄露它也很快失效。这对数据库凭证管理是降维打击。但Vault本身是个复杂系统需要专人运维。三、方案2Sealed Secrets——GitOps友好3.1 解决Secret不能提交Git的痛点【Sealed Secrets 的思路——加密后随便提交Git】 你本地有明文密码 │ ▼ kubeseal 用集群的公钥加密 │ ▼ 生成 SealedSecret (密文) → 可以安全提交Git │ ▼ 集群里的 SealedSecret Controller 用私钥解密 │ ▼ 还原成普通 Secret → Pod正常使用# 1. 用kubeseal加密(公钥来自集群)echo-nmy-password|kubectl create secret generic my-secret\--dry-runclient --from-filepassword/dev/stdin-ojson|\kubeseal--formatyamlsealed-secret.yaml# 2. sealed-secret.yaml 可以放心提交Git# 即使仓库公开没有集群私钥也解不开kubectl apply-fsealed-secret.yaml# 3. Controller自动解密成普通Secretkubectl get secret my-secret维度原生SecretSealed Secrets能提交Git吗❌ 明文泄露✅ 加密后可提交加密存储❌ Base64✅ 非对称加密GitOps友好❌✅动态轮转❌❌四、方案3External Secrets Operator——对接云厂商4.1 直接用云上的密钥管理【External Secrets Operator——K8s和云密钥管理的桥】 AWS Secrets Manager / GCP Secret Manager / Azure Key Vault │ │ (External Secrets Operator 同步) ▼ K8s 里的 Secret (自动同步、自动更新) │ ▼ Pod 像用普通Secret一样用apiVersion:external-secrets.io/v1beta1kind:ExternalSecretmetadata:name:db-passwordspec:refreshInterval:1h# 每小时同步一次secretStoreRef:name:aws-secretskind:ClusterSecretStoredata:-secretKey:passwordremoteRef:key:prod/db/password# AWS Secrets Manager里的key方案最佳场景复杂度动态密钥Vault自建、要动态密钥/轮转高✅Sealed SecretsGitOps、密钥要进Git低❌External Secrets已在用云厂商KMS中取决于云五、选型建议【怎么选——对号入座】 你已经在用 AWS/GCP/Azure 的密钥管理 → External Secrets Operator (直接桥接零额外运维) 你要做 GitOps密钥必须进Git → Sealed Secrets (最轻量) 你要动态密钥、自动轮转、完整审计 → HashiCorp Vault (功能最全但要养) 你啥都没有先过渡 → 至少开 etcd 静态加密 严格 RBAC 限制 get secret要点没有最好的方案只有最合适的。云上用户首选External Secrets不用养新系统GitOps用户选Sealed Secrets轻量、进Git安全对密钥安全有极致要求的金融/大厂选Vault动态密钥审计无敌但运维成本高。无论如何原生裸Secret只适合演示环境。本篇小结K8s原生Secret只是Base64等于明文etcd里谁有读权限谁就能看。生产必须升级至少开etcd静态加密更好的是上专业工具。三种主流方案各有所长——External Secrets桥接云厂商KMS零运维、Sealed Secrets让密钥安全进Git轻量GitOps、Vault提供动态密钥自动轮转审计功能最全但重。选哪个看你是不是云上、要不要进Git、要不要动态密钥。下篇讲Pod Security Standards——K8s给Pod安全划的三条红线。上一篇【第56篇】NetworkPolicy安全实战——用零信任网络把微服务“关进笼子“下一篇【第58篇】Pod Security Standards——Pod安全的三条红线