在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

加密配置的关键组件:

  1. kind: EncryptionConfiguration:声明资源类型。
  2. resources:指定应加密的 API 资源。
  3. providers:定义加密机制。常见的提供程序包括 aescbcaesgcm 以及 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 对象之间的差距。

  1. 存储: 实际密钥仅存在于外部保险库中。
  2. 同步/注入: 操作器监视自定义资源(如 ExternalSecret),并从保险库获取数据。
  3. 创建: 操作器随后在本地创建一个标准的 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 挂载,还是来自外部保险库的动态凭据。最佳设置是限制谁可以读取密钥、密钥存储在哪里以及暴露后保持有用时间长短的设置。