铜墙铁壁 - 密钥管理的最佳实践
第一部分:回顾 Kubernetes Secret
的局限性
我们在之前的系列中已经接触过 K8s Secret
对象。它提供了一种将敏感数据与 Pod 定义分离的基础机制。但对于追求极致安全的生产环境,它存在几个显著的局限性:
- 默认仅编码非加密:
etcd
中存储的 Secret 数据默认只经过了 Base64 编码,这是一种可逆的编码方式,并非加密。任何人只要能访问到 etcd 的数据,就能轻易解码获取明文。除非你为 etcd 显式配置了静态加密,否则数据是“裸奔”的。 - 静态密钥 (Static Secrets): 存储在 Secret 中的值通常是静态的、长期有效的。一旦泄露,其有效期可能很长,直到被手动轮换。
- 轮换困难 (Rotation is Hard): 手动轮换一个被数十个应用使用的数据库密码,是一个充满风险和辛劳的过程,很容易出错或遗漏。
- 审计能力有限: 我们只能审计谁在 API 层面读取了
Secret
对象,但很难追踪一个密钥在被注入到 Pod 后,具体被哪个进程、在何时使用了。 - 权限“爆炸半径”较大: 通常,一个 ServiceAccount 被授予了读取某个命名空间下所有 Secret 的权限,这增加了不必要的风险。
第二部分:现代密钥管理的核心原则
为了克服这些局限性,现代的密钥管理系统遵循以下几个核心原则:
- 集中化 (Centralization): 将所有密钥都存储在一个统一的、高可用的、安全的“保险库”中进行管理。
- 强身份认证 (Strong Authentication): 对密钥的访问必须基于强认证的身份(无论是人类用户还是机器/应用),而不是依赖于共享的、长期有效的静态令牌。
- 动态密钥 (Dynamic Secrets): 这是最具革命性的思想。密钥应该被按需、动态地生成,并且拥有一个极短的生命周期 (TTL)。例如,应用需要连接数据库时,它不是去获取一个永久密码,而是向密钥管理器申请一个只在接下来 5 分钟内有效的临时用户名和密码。即使这个临时凭证泄露了,它很快也会失效。
- 全面审计 (Comprehensive Auditing): 对密钥管理器的每一次操作(认证、策略修改、密钥读取等)都必须有详细的、不可篡改的审计日志。
- 无处不加密 (Encryption Everywhere): 数据在传输中 (in-transit) 和静态存储时 (at-rest) 都必须被加密。
第三部分:HashiCorp Vault - 密钥管理的事实标准
HashiCorp Vault 是目前业界最流行、功能最强大的开源密钥管理工具,它完美地实现了上述所有原则。
Vault 的核心概念:
- 存储后端 (Storage Backends): Vault 本身不存储数据,它负责加密数据,然后将加密后的数据块存放在一个后端存储系统中(如 Consul, etcd, 或者云存储 S3, GCS 等)。
- 认证方法 (Auth Methods): 定义了客户端(人或机器)如何向 Vault 证明自己的身份。Vault 支持多种认证方法,如 Token, LDAP, GitHub, AppRole 等。对于 Kubernetes,最重要的是
kubernetes
认证方法,它允许 Pod 使用自己的 ServiceAccount Token 来向 Vault 认证。 - 密钥引擎 (Secrets Engines): Vault 的“插件”,负责管理不同类型的密钥。
KV
(Key-Value): 最基础的,用于存储静态的键值对密钥。Database
: 可以动态地为数据库生成有时效性的用户名和密码。PKI
: 可以作为一个证书颁发机构 (CA),动态地生成短期的 TLS 证书。AWS
,GCP
,Azure
: 可以动态地生成有时效性的云平台访问凭证。
- 策略 (Policies): 定义了经过认证的身份被允许做什么。它通过 HCL 语言编写,可以实现极其细粒度的访问控制(例如,“身份为
app-A
的服务,只允许读取路径为secret/data/app-A/db
的密钥”)。
第四部分:实践 - Vault 与 Kubernetes 的无缝集成
我们将探讨目前业界最推荐的、最安全的集成模式:使用 Vault Secrets Store CSI Driver。
工作流程:
- SRE/平台团队的一次性设置:
- 在 K8s 集群外部或内部,部署一个高可用的 Vault 集群。
- 在 Vault 中,开启并配置
kubernetes
认证方法,让 Vault 信任 K8s 集群的 ServiceAccount 签发机构。 - 在 Vault 中,创建一个角色 (Role),将一个 Vault 策略 (Policy) 绑定到 K8s 中的特定
ServiceAccount
和namespace
。 - 在 Vault 中,配置数据库密钥引擎,告诉 Vault 如何连接到你的数据库,以及如何创建和撤销临时用户。
- 在 K8s 集群中,安装 Vault Secrets Store CSI Driver 这个驱动程序。
- 开发者的应用部署流程 (GitOps):
现在,当开发者需要为他的应用配置数据库密码时,他不再需要申请或创建一个 K8s
Secret
。取而代之的是,他只需要在他的Deployment
YAML 中做如下修改:
# deployment-with-csi-volume.yaml
apiVersion: apps/v1
kind: Deployment
# ...
spec:
template:
metadata:
# ...
spec:
# Pod 必须使用被 Vault 角色绑定的 ServiceAccount
serviceAccountName: my-app-sa
containers:
- name: my-app
image: my-app:1.0
volumeMounts:
# 将由 CSI 驱动提供的密钥挂载到容器内的一个路径
- name: vault-db-credentials
mountPath: "/mnt/secrets"
readOnly: true
# 定义这个特殊的 Volume
volumes:
- name: vault-db-credentials
csi:
# 指定使用 Vault CSI 驱动
driver: secrets-store.csi.k8s.io
readOnly: true
# volumeAttributes 定义了如何从 Vault 获取密钥
volumeAttributes:
# Vault 中为此应用配置的角色名
roleName: "my-app-db-role"
# 要获取的密钥列表
objects: |
- objectName: "username.txt" # 将在 /mnt/secrets 中创建的文件名
secretPath: "database/creds/my-app-role" # 从 Vault 的这个路径获取动态密钥
secretKey: "username" # 获取动态凭证中的 username 字段
- objectName: "password.txt"
secretPath: "database/creds/my-app-role"
secretKey: "password"
这个 YAML 文件不包含任何敏感信息,可以安全地存入 Git。
运行时发生了什么?(魔法揭秘)
- 当这个 Pod 即将被调度到某个节点上时,
kubelet
看到它请求了一个secrets-store.csi.k8s.io
类型的 CSI 卷。 kubelet
通知该节点上的 Vault CSI Driver 准备这个卷。- CSI 驱动读取
volumeAttributes
,知道了需要扮演 Vault 中的my-app-db-role
角色。 - CSI 驱动从 Pod 的
ServiceAccount
中获取其 JWT Token。 - 它拿着这个 Token 去向 Vault 认证。Vault 验证 Token 的合法性,并确认这个 ServiceAccount 被授权扮演
my-app-db-role
角色。 - 认证成功后,CSI 驱动根据
secretPath
向 Vault 的数据库密钥引擎请求一个新的、动态的数据库凭证。 - Vault 连接到数据库,创建一个全新的、有时效性(例如,1小时后过期)的用户名和密码,并将其返回给 CSI 驱动。
- CSI 驱动将获取到的用户名和密码分别写入到两个临时文件中,并将这些文件所在的目录作为 Volume 挂载到应用容器的
/mnt/secrets
路径下。 - 你的应用程序启动后,只需从
/mnt/secrets/username.txt
和/mnt/secrets/password.txt
文件中读取数据库凭证即可。 - 自动轮换: 当凭证即将过期时,CSI 驱动可以自动地为应用获取新的凭证并更新挂载的文件。
SRE 视角的思考
- 动态密钥的革命: 从静态密钥到动态密钥的转变,是安全理念的一次巨大飞跃。它将“凭证泄露”这一事件的危害,从可能是永久性的,降低到了分钟或小时级别。
- 集中的策略与审计: 所有的访问控制策略和审计日志都集中在 Vault 中,极大地简化了安全管理和合规性工作。
- 赋能开发者的同时保障安全: 开发者无需关心密钥的存储和轮换,他们只需要在 YAML 中声明他们需要哪个“角色”的凭证即可。SRE 和安全团队则在 Vault 中集中定义和控制这些角色的权限,实现了完美的职责分离和安全赋能。
总结
今天,我们为我们的“云原生堡垒”安装了最先进的、由生物识别、动态口令和严格审计构成的“中央保险库系统”。我们深入探讨了现代密钥管理的原则,并学习了如何通过 HashiCorp Vault 和 Secrets Store CSI Driver 这一强大的组合,在 Kubernetes 中实现安全、自动化和动态的密钥管理。