HashiCorp 发布了 Vault Kubernetes Key Management 公测版。这是一个兼容 Kubernetes KMS v2 的插件,让 API Server 把信封加密操作委托给 Vault Enterprise。变化的核心不是“再加一层加密”,而是把保护 etcd 数据的密钥加密密钥(KEK)移出 Kubernetes 集群,放进一个能够独立授权、审计和运维的信任域。
信封加密解决的是密钥边界问题
Kubernetes Secret、ConfigMap 等 API 对象最终存储在 etcd 中。只依赖磁盘加密时,攻击者一旦同时获得节点和磁盘访问能力,保护效果就会明显下降。API Server 的静态加密配置可以改善这一点,但如果 AES 密钥仍保存在控制平面节点上的配置文件中,密文和主密钥依旧处于相近的管理边界。
接入外部 KMS 后,数据写入路径大致变成:
- API Server 为对象生成或使用数据加密密钥(DEK)。
- DEK 加密 Secret 等资源的内容。
- KMS v2 插件请求 Vault 使用 KEK 保护 DEK。
- etcd 保存加密后的对象以及被包装的 DEK,而不是 Vault 中的 KEK。
因此,仅拿到 etcd 快照通常不足以解密数据。攻击者还需要跨越 Vault 的认证、授权和审计边界。与此同时,Vault 也进入了 Kubernetes 控制面的关键写入路径,其可用性和延迟必须按基础设施依赖来管理。
KMS v2 带来的工程含义
KMS v2 是 API Server 与密钥管理插件之间的接口。Vault 插件通常通过控制平面节点上的 Unix Domain Socket 向 API Server 提供该接口,再由插件与 Vault Enterprise 通信。这种分层让 Kubernetes 不需要直接持有 Vault 的高权限凭据,也便于分别治理集群管理员和密钥管理员。
公测状态意味着团队应重点验证以下行为:
- Vault 或插件短暂不可用时,API 对象的读取与写入分别会怎样失败。
- 多个 API Server 是否连接到独立、健康且配置一致的插件实例。
- 插件重启、Vault 主节点切换和网络抖动对请求延迟的影响。
- KEK 轮换后,旧数据能否读取,新写入是否使用新密钥。
- 审计日志能否关联 Kubernetes 请求、插件调用和 Vault 操作。
需要注意,KMS 主要保护静态数据。已经通过 RBAC 获得 Secret 读取权限的主体,仍可通过 Kubernetes API 得到解密后的内容。它不能替代最小权限、工作负载身份、审计和 Secret 生命周期管理。
可以这样搭建验证环境
下面是一个可改造的 KMS v2 加密配置。这里明确假设:控制平面支持 KMS v2;Vault Enterprise 和公测插件已按对应版本文档完成配置;插件监听 /var/run/kms-plugins/vault.sock。实际插件参数、镜像和认证方式应以所使用的公测版本为准。
将以下内容保存为 /etc/kubernetes/encryption-config.yaml:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- kms:
apiVersion: v2
name: vault-kms
endpoint: unix:///var/run/kms-plugins/vault.sock
timeout: 3s
- identity: {}
identity 放在末尾有两个作用:已有明文对象仍然可以读取,而新的 Secret 会优先经由 Vault KMS 加密。迁移完成后是否保留该回退项,需要结合恢复方案和安全要求决定。
API Server 还要加载配置文件,并能访问插件 socket。以静态 Pod 管理的控制平面为例,可以这样检查所需参数;不要直接批量修改生产节点:
sudo grep -nE 'encryption-provider-config|kms-plugins' \
/etc/kubernetes/manifests/kube-apiserver.yaml
对应的 kube-apiserver 参数和挂载关系应类似:
spec:
containers:
- name: kube-apiserver
command:
- kube-apiserver
- --encryption-provider-config=/etc/kubernetes/encryption-config.yaml
volumeMounts:
- name: encryption-config
mountPath: /etc/kubernetes/encryption-config.yaml
readOnly: true
- name: kms-socket
mountPath: /var/run/kms-plugins
volumes:
- name: encryption-config
hostPath:
path: /etc/kubernetes/encryption-config.yaml
type: File
- name: kms-socket
hostPath:
path: /var/run/kms-plugins
type: Directory
这只是需要合并到现有静态 Pod 清单中的片段,不能覆盖完整的 kube-apiserver.yaml。还应限制加密配置文件和 socket 目录的权限,并确保每个控制平面节点使用一致的 provider 名称与配置。
配置生效后,可以创建测试 Secret:
kubectl create namespace kms-check
kubectl -n kms-check create secret generic database \
--from-literal=username=app \
--from-literal=password='change-me-before-production'
kubectl -n kms-check get secret database -o yaml
最后一条命令会通过 API Server 返回可用的 Kubernetes 对象,因此不能证明 etcd 中存放的是密文。真正的验证应读取 etcd 原始记录。下面的命令需要在测试控制平面上执行,并按环境调整证书路径和 endpoint:
export ETCDCTL_API=3
sudo -E etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
get /registry/secrets/kms-check/database --print-value-only | strings
输出中不应出现 change-me-before-production。同时检查 Vault 和插件审计记录,确认该写入确实触发了预期的密钥操作。
已有 Secret 不会因为添加 provider 自动重写。经过备份和测试后,可以通过 API 重写目标资源,让其使用列表中的第一个 provider:
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
这条命令会更新整个集群的 Secret,可能触发控制器行为并增加 API Server、etcd 和 Vault 的负载。生产环境应按命名空间分批执行,避开高峰期,并记录失败对象以便重试。
上线前把故障路径走一遍
公测功能更适合先进入隔离的非生产集群。验收不应只检查“能创建 Secret”,还要主动停止插件、切断 Vault 网络、执行 Vault 高可用切换并轮换 KEK,观察 API Server 错误率、延迟和恢复过程。
上线评审至少应覆盖:
- Vault、插件和 API Server 的版本兼容矩阵已经固定。
- 每个控制平面节点都有独立且受监控的插件实例。
- Vault 策略只授予插件所需的最小密钥操作权限。
- etcd 快照恢复与 Vault 备份恢复经过联合演练。
- KEK 轮换、provider 更名和配置回滚都有书面步骤。
- 迁移前后都抽样检查了 etcd 原始数据,而不只使用
kubectl验证。
Vault Kubernetes Key Management 的价值,在于建立独立于集群的密钥控制面和审计边界。代价则是更多运行组件、更严格的可用性要求,以及必须联合设计的备份恢复流程。对于已经运行 Vault Enterprise、并需要强化 Kubernetes 静态数据隔离的团队,这个公测版值得验证,但不应在缺少故障演练和恢复证据时直接承担生产核心负载。