在Kubernetes集群中管理机密和敏感数据的最佳实践
通过RBAC、etcd加密、更安全的挂载方式、外部密钥存储、CSI驱动和轮换策略来保护Kubernetes Secrets。
在Kubernetes集群中管理机密和敏感数据的最佳实践
Kubernetes Secrets 虽然方便,但仅仅因为对象名为 Secret 并不意味着它自动安全。如果您的 RBAC 过于宽泛或 etcd 未加密,泄露的令牌可能会暴露整个集群中的数据库密码、API 密钥和私有证书。
将 Kubernetes Secrets 作为一层防护,然后根据风险程度添加加密、访问控制、更安全的注入模式以及外部密钥存储。
理解 Kubernetes Secrets:默认机制
Kubernetes 引入了专门用于保存敏感信息的 Secret 对象。虽然它很有用,但了解其局限性和默认安全行为至关重要。
默认行为与注意事项
默认情况下,Kubernetes Secrets 在 etcd(集群所有配置数据的后端存储)中不会加密存储。它们仅经过 Base64 编码,这实际上并不提供加密。任何有权访问 etcd 数据存储的人(例如集群管理员、被攻破的节点)都可以轻松解码这些值。
警告: 在未应用加密措施的情况下,切勿仅依赖默认的 Kubernetes Secret 对象来处理高度敏感的数据。
Base64 编码与加密的区别
一个常见的误解是 Base64 编码能提供安全性。Base64 是一种编码方案,而非加密方案。它很容易被逆转:
# 解码 Kubernetes Secret 值的示例
echo 'c3VwZXItc2VjcmV0Cg==' | base64 -d
# 输出: super-secret
第一层:保护静态 Secrets(etcd 加密)
保护 Secrets 最基础的步骤是确保它们在存储层(etcd)上被加密。即使底层数据库被直接访问,这也能保护数据。
启用静态加密
静态加密通过 Kubernetes API 服务器使用 EncryptionConfiguration 对象进行配置。该配置指定应使用哪些提供程序来加密存储在 etcd 中的各种数据类型,包括 secrets。
加密配置的关键组件:
kind: EncryptionConfiguration:声明资源类型。resources:指定应加密的 API 资源。providers:定义加密机制。常见的提供程序包括aescbc、aesgcm以及 KMS 提供程序(如 AWS KMS 或 GCP KMS)。
最佳实践: 当平台支持时,使用 KMS 提供程序。如果使用本地密钥,请仔细管理密钥轮换,并在现有数据被重新加密之前保留旧密钥。
第二层:保护传输中和使用中的 Secrets
虽然 etcd 加密解决了“静态”问题,但 Secrets 在被挂载到 Pod 中时仍会被 Kubelet 解密。我们必须控制这些 Secrets 如何以及在何处出现。
策略 1:卷挂载 Secrets
将 Secret 数据注入容器的标准方法是将其作为卷挂载(通常会在容器的文件系统中生成一个文件)。
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
containers:
- name: my-container
image: nginx
volumeMounts:
- name: secret-volume
mountPath: "/etc/config/db"
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: my-sensitive-secret
安全考虑: 挂载的 Secret 卷通常在 Linux 节点上由 tmpfs 支持,但值仍然对容器进程以及任何具有足够节点或 Pod 访问权限的人可见。使用 readOnly: true,避免将环境或配置文件转储到日志中,并限制对生产 Pod 的 shell 访问。
策略 2:环境变量(不推荐用于高敏感性数据)
虽然方便,但通常不推荐使用从 Secrets 获取的环境变量来存储高价值机密。环境变量容易通过以下方式泄露:
- 配置不当的应用程序生成的容器日志。
- 从容器内部或其他特权容器读取
/proc/1/environ。 - 容器检查工具。
如果必须使用环境变量,请仅用于低敏感性的配置数据。
第三层:使用外部密钥存储进行高级管理
最安全的模式是将敏感数据完全保留在 Kubernetes 控制平面(etcd)之外,并使用专门的工具在运行时动态检索。
使用外部密钥操作器
外部密钥操作器桥接了存储在专用保险库(如 HashiCorp Vault、AWS Secrets Manager、Azure Key Vault)中的安全密钥与本机 Kubernetes Secret 对象之间的差距。
- 存储: 实际密钥仅存在于外部保险库中。
- 同步/注入: 操作器监视自定义资源(如
ExternalSecret),并从保险库获取数据。 - 创建: 操作器随后在本地创建一个标准的 Kubernetes
Secret对象,然后可以将其挂载到 Pod 中。
好处: 数据源保留在集群外部,从而改进了轮换和审计能力。然而,同步的 Kubernetes Secret 仍然存在于集群中,因此您仍然需要 RBAC、etcd 加密和命名空间隔离。
使用 Secrets Store CSI 驱动
对于需要直接、临时访问且无需在 etcd 中本地存储密钥的应用程序,Secrets Store CSI 驱动是更优选择。
- 该驱动利用提供程序(例如 Vault 提供程序、Azure 提供程序)。
- 它将密钥直接从外部存储挂载到 Pod 的文件系统中作为临时卷,从而完全避免将密钥数据写入 etcd。
这通过完全从 etcd 数据库中消除密钥,提供了最高级别的安全性。
密钥管理的操作最佳实践
除了技术存储机制之外,操作卫生对于维护安全态势至关重要。
1. 最小权限原则 (PoLP)
确保与 Pod 关联的服务帐户仅具有读取其所需特定 Secret 的权限,而没有其他权限。使用基于角色的访问控制 (RBAC) 来严格限定权限范围。
2. 频繁轮换密钥
为所有凭据实施自动轮换计划。长期存在的密钥会增加被攻破的机会窗口。与外部保险库集成的工具通常会自动处理此轮换。
3. 审计和监控访问
配置审计日志以跟踪谁读取或修改了 Secret 对象。与外部保险库(如 Vault Agents 或 CSI 驱动)集成的工具也应记录对外部存储的访问尝试。
4. 切勿将密钥提交到 Git
这是一条基本规则。切勿将原始甚至 Base64 编码的密钥存储在 Git 仓库中,即使是私有仓库也不行。使用 git-secrets 等工具或配置管理模板工具(如 Helm 或 Kustomize)结合外部密钥注入机制来管理部署清单。
使用 Kustomize 的示例(外部引用):
使用模板时,您可以在清单文件中使用占位符,并依赖构建步骤或 CI/CD 管道在将 YAML 应用到集群之前,从保险库安全地检索实际密钥值并注入。
管理策略比较
| 策略 | 安全级别 | etcd 暴露? | 复杂度 | 最适合 |
|---|---|---|---|---|
| 默认 K8s Secret(无 etcd 加密) | 非常低 | 是(明文) | 低 | 仅临时测试 |
| 带 etcd 加密的 K8s Secret | 中等 | 是(加密) | 中等 | 通用配置数据 |
| 外部密钥操作器 | 高 | 是(操作器管理的 Secret) | 高 | 标准化密钥管理 |
| Secrets Store CSI 驱动 | 最高 | 否(直接挂载) | 高 | 高度敏感的凭据和令牌 |
从启用 etcd 加密和收紧 RBAC 开始。然后决定每个工作负载是使用同步的 Secrets、直接的 CSI 挂载,还是来自外部保险库的动态凭据。最佳设置是限制谁可以读取密钥、密钥存储在哪里以及暴露后保持有用时间长短的设置。