0
点赞
收藏
分享

微信扫一扫

铜墙铁壁 - 密钥管理的最佳实践

铜墙铁壁 - 密钥管理的最佳实践

第一部分:回顾 Kubernetes Secret 的局限性

我们在之前的系列中已经接触过 K8s Secret 对象。它提供了一种将敏感数据与 Pod 定义分离的基础机制。但对于追求极致安全的生产环境,它存在几个显著的局限性:

  1. 默认仅编码非加密: etcd 中存储的 Secret 数据默认只经过了 Base64 编码,这是一种可逆的编码方式,并非加密。任何人只要能访问到 etcd 的数据,就能轻易解码获取明文。除非你为 etcd 显式配置了静态加密,否则数据是“裸奔”的。
  2. 静态密钥 (Static Secrets): 存储在 Secret 中的值通常是静态的、长期有效的。一旦泄露,其有效期可能很长,直到被手动轮换。
  3. 轮换困难 (Rotation is Hard): 手动轮换一个被数十个应用使用的数据库密码,是一个充满风险和辛劳的过程,很容易出错或遗漏。
  4. 审计能力有限: 我们只能审计谁在 API 层面读取了 Secret 对象,但很难追踪一个密钥在被注入到 Pod 后,具体被哪个进程、在何时使用了。
  5. 权限“爆炸半径”较大: 通常,一个 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

工作流程:

  1. SRE/平台团队的一次性设置:
  • 在 K8s 集群外部或内部,部署一个高可用的 Vault 集群。
  • 在 Vault 中,开启并配置 kubernetes 认证方法,让 Vault 信任 K8s 集群的 ServiceAccount 签发机构。
  • 在 Vault 中,创建一个角色 (Role),将一个 Vault 策略 (Policy) 绑定到 K8s 中的特定 ServiceAccountnamespace
  • 在 Vault 中,配置数据库密钥引擎,告诉 Vault 如何连接到你的数据库,以及如何创建和撤销临时用户。
  • 在 K8s 集群中,安装 Vault Secrets Store CSI Driver 这个驱动程序。
  1. 开发者的应用部署流程 (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。

运行时发生了什么?(魔法揭秘)

  1. 当这个 Pod 即将被调度到某个节点上时,kubelet 看到它请求了一个 secrets-store.csi.k8s.io 类型的 CSI 卷。
  2. kubelet 通知该节点上的 Vault CSI Driver 准备这个卷。
  3. CSI 驱动读取 volumeAttributes,知道了需要扮演 Vault 中的 my-app-db-role 角色。
  4. CSI 驱动从 Pod 的 ServiceAccount 中获取其 JWT Token。
  5. 它拿着这个 Token 去向 Vault 认证。Vault 验证 Token 的合法性,并确认这个 ServiceAccount 被授权扮演 my-app-db-role 角色。
  6. 认证成功后,CSI 驱动根据 secretPath 向 Vault 的数据库密钥引擎请求一个新的、动态的数据库凭证。
  7. Vault 连接到数据库,创建一个全新的、有时效性(例如,1小时后过期)的用户名和密码,并将其返回给 CSI 驱动。
  8. CSI 驱动将获取到的用户名和密码分别写入到两个临时文件中,并将这些文件所在的目录作为 Volume 挂载到应用容器的 /mnt/secrets 路径下。
  9. 你的应用程序启动后,只需从 /mnt/secrets/username.txt/mnt/secrets/password.txt 文件中读取数据库凭证即可。
  10. 自动轮换: 当凭证即将过期时,CSI 驱动可以自动地为应用获取新的凭证并更新挂载的文件。

SRE 视角的思考

  • 动态密钥的革命: 从静态密钥到动态密钥的转变,是安全理念的一次巨大飞跃。它将“凭证泄露”这一事件的危害,从可能是永久性的,降低到了分钟或小时级别。
  • 集中的策略与审计: 所有的访问控制策略和审计日志都集中在 Vault 中,极大地简化了安全管理和合规性工作。
  • 赋能开发者的同时保障安全: 开发者无需关心密钥的存储和轮换,他们只需要在 YAML 中声明他们需要哪个“角色”的凭证即可。SRE 和安全团队则在 Vault 中集中定义和控制这些角色的权限,实现了完美的职责分离和安全赋能。

总结

今天,我们为我们的“云原生堡垒”安装了最先进的、由生物识别、动态口令和严格审计构成的“中央保险库系统”。我们深入探讨了现代密钥管理的原则,并学习了如何通过 HashiCorp Vault 和 Secrets Store CSI Driver 这一强大的组合,在 Kubernetes 中实现安全、自动化和动态的密钥管理。

举报

相关推荐

0 条评论