从纵深防御的角度构建密钥防泄漏方案

权当抛砖引玉,毕竟我不是专职的SRE/DevOps,我的工作方向还是以Information Security为主,大家多包涵。 前言:部分概念科普 Helm?Helm3 VS Helm2? Helm是什么? Helm 是 Kubernetes 的一个包管理工具,类似于 Linux 下的 apt 或

权当抛砖引玉,毕竟我不是专职的SRE/DevOps,我的工作方向还是以Information Security为主,大家多包涵。

前言:部分概念科普

Helm?Helm3 VS Helm2?

Helm是什么?

Helm 是 Kubernetes 的一个包管理工具,类似于 Linux 下的 apt 或 yum。它被设计用于帮助开发者和运维团队打包、配置和部署应用程序及其依赖到 Kubernetes 集群中。

不过,虽然 Helm 和 apt、yum 在概念上类似,都是包管理器,但 Helm 是专门为 Kubernetes 设计的。它用于管理 Kubernetes 的应用程序 - Helm 的 "包" 被称为 "charts"。Helm chart 是一个预配置的包含了一组 Kubernetes 资源定义的文件集合,这些资源定义了运行某个应用程序或服务所需的一切。

Helm 客户端可以安装在任何可以访问 Kubernetes 集群的机器上,关键是 Helm 客户端和 Kubernetes 集群能够进行通信才行。

因此,为了让 Helm 能够操作 Kubernetes 集群,需要在远程操作 Kubernetes 集群的机器上有一个配置好的 kubeconfig 文件,这个文件包含了集群的访问信息和证书等。

Helm3 VS Helm2?

看问题的视角不同,选择也会不同。运维团队一般会更倾向"无必要不更新",但我从安全的视角看,还是选择Helm3更好。

实际上, Helm 3 是对 Helm 2 的一次重大更新,带来了许多改进和新功能,例如:

  1. Tiller 的移除

  • Helm 2 使用了一个名为 Tiller 的服务端组件,该组件运行在 Kubernetes 集群内,用于管理 Helm charts 的安装。这引入了额外的复杂度和安全暴露面风险,因为 Tiller 需要很多权限来操作 Kubernetes 资源。

  • Helm 3 移除了 Tiller,转而直接与 Kubernetes API 交互,简化了架构并增强了安全性。

  1. 改进的安全和权限模型

  • 由于 Helm 3 移除了 Tiller,因此就不需要太复杂的权限模型了,现在它只依赖于用户的 Kubernetes 凭据来执行操作,这减少了权限过大的风险。

  1. 改进的升级和回滚策略

  • Helm 3 引入了更加可靠的升级和回滚机制,使得部署更加稳定。

  1. Release 名称现在是作用域限定的

  • 在 Helm 2 中,release 名称是在整个集群范围内唯一的。

  • Helm 3 中,release 名称是在namespace范围内唯一的,这意味着我可以在不同的命名空间中使用相同的 release 名称。

  1. 改进的依赖管理

  • Helm 3 改进了对 chart 依赖的处理,依赖现在可以存储在 chart 的 Chart.yaml 文件中,而不是单独的 requirements.yaml 文件。

  1. API 版本的更新

  • Helm 3 支持最新的 Kubernetes API 版本,而 Helm 2 可能不支持较新版本的 Kubernetes。

所以哪一个版本更好?

从安全角度看, Helm 3 明显比 Helm 2 更好,因为它提供了更简单的架构、更高的安全性、以及更好的用户体验。但是,从运维团队的角度看,现在大家都在维护一个已经存在且仍在使用 Helm 2 的系统,贸然切换到 Helm 3 一定是充满风险的,无论是运维团队还是安全团队,大家都不喜欢风险并试图使用BCM等方案来极力避免风险。因此除非是"非升不可的情况"下,没人想去动基础设施。

所以我建议,如果是全新项目,选 Helm 3 更好,Helm 3 的设计考虑了 Helm 2 的反馈和学习经验,如果是老项目,评估清楚在升级就好。

Kubernetes - K8s

这里篇幅有限,我就不多说讲K8s了,只说两种和本文关系密切的资源对象:

ConfigMap

ConfigMap 是用来存储非敏感数据的键值对。它可以用来存储应用程序配置数据,比如配置文件内容、命令行参数、环境变量等。使用 ConfigMap 可以将应用程序的配置与镜像内容分离开来,从而提高应用程序的可移植性和灵活性。ConfigMap 在 Pod 的启动时被引用,并提供给 Pod 中的应用程序使用。

例如,对于配置数据库的连接信息时,可以把数据库的URL端口号等非敏感信息配置在ConfigMap中,然后在 Pod 配置中引用这个 ConfigMap,以设置应用程序连接数据库的环境变量。

Secret

Secret 用于存储敏感信息,如密码、OAuth 令牌、SSH 密钥等。 Secret 也是KV对的形式存储数据,但它们是加密存储的,只有存在相应权限的 Pod 才能访问 Secret 中的信息。Kubernetes 也提供了将 Secret 数据挂载到 Pod 的文件系统中或通过环境变量传递给 Pod 中应用程序的能力。

由于 Secret 中存储的数据是敏感的,所以 Kubernetes 提供了额外的保护措施来避免这些数据被泄露。例如,它不会被记录在日志中,且在 etcd 中以加密形式存储。

还是以数据库连接信息为例,假设使用用户名和密码连接数据库的方式,就需要把用户名和密码加密存储在 Secret 中,然后我们在 Kubernetes 资源配置中同时引用 Secret 和 ConfigMap,才能构造出完整的数据库连接字符串,但同时保证了敏感信息的安全。

ConfigMap vs. Secret

用途:ConfigMap 用于存储非敏感配置信息,而 Secret 用于存储敏感信息。

安全性:Secret 通过加密来提高存储敏感信息的安全性,而 ConfigMap 中的数据则以明文形式存储,没有额外的加密处理。

使用场景:当需要在 Pod 中注入配置信息时使用 ConfigMap;当需要在 Pod 中安全地注入敏感信息时,使用 Secret。

阶段性结论

在实践中,同时使用 ConfigMap 和 Secret 来管理配置信息和敏感数据,才能让应用配置更灵活的同时,也能保护敏感信息的安全性。

使用Secret就足够安全了吗

答案:并不!

etcd中的Secret数据加密

从 Kubernetes 1.7 版本开始,为了提高安全性,Kubernetes 支持对存储在 etcd 中的 Secret 数据进行加密。即使攻击者获得了对 etcd 数据的物理访问权限,没有解密密钥,他们也无法读取 Secret 的内容。

如何启用Secret数据加密?

我大概描述下在 Kubernetes 集群中启用 Secrets 的加密流程:

  • 配置加密提供者:在 Kubernetes API 服务器的启动配置中添加加密provider配置。通一般做法是修改 API 服务器的启动参数、配置文件来实现的,但具体取决于 Kubernetes 集群的部署情况。

  • 选择加密算法:Kubernetes 支持多种加密算法,如 aescbc、aesgcm、aesctr 等,根据实际情况选择算法即可。

通过这种方式能做到,虽然 Secret 数据在 etcd 中是加密存储的,但当它们被读取并提供给授权的 Pod 使用时,Kubernetes 会自动对这些数据进行解密,这层加密在应用程序角度看是透明化的,应用程序可以像使用未加密数据一样使用这些解密后的敏感信息。

开启Secret数据加密就够了吗?

实际上,开启 Secret 数据加密虽然是提升 Kubernetes 环境安全性的重要步骤,但还不够安全了。这里的安全仅仅是指密钥防泄漏,篇幅受限,本文就先不谈确保 Kubernetes 集群的全面安全,有空再说。

我还需要讲一下纵深防御这个概念。

从纵深防御的角度构建密钥防泄漏方案

1. 使用 Helm 管理 Kubernetes 应用

首先,使用 Helm 来管理 Kubernetes 应用,Helm 允许在部署时通过外部配置来注入密钥,而不是将密钥硬编码在应用配置中。这样做的好处是可以避免将敏感信息(如数据库密码)直接存储在代码库中。

最佳实践:创建 Helm charts 时,使用 values.yaml 文件来定义那些需要在部署时提供的配置项,但避免直接在其中填写敏感信息。敏感信息可以在部署时通过命令行参数或 CI/CD 系统中的环境变量安全地提供给 Helm。

2. Kubernetes Secrets 存储敏感信息

将敏感信息(如密码、密钥)存储在 Kubernetes Secrets 中。这样做的好处是 Kubernetes 提供了对 Secrets 的基本加密支持,可以减少敏感信息以明文形式存储的风险。

最佳实践:在 Kubernetes 中启用 Secrets 的加密功能,确保 Secrets 在 etcd 中以加密形式存储,而不是明文形式存储。

3. 配置和使用 Role-Based Access Control (RBAC)

通过配置 RBAC,限制对 Secrets 的访问。

最佳实践:为每个需要访问 Secrets 的服务账户创建角色和角色绑定,严格按照最小权限原则授予权限。

4. 密钥管理和轮换

使用外部密钥管理系统(如 HashiCorp Vault、AWS KMS )管理长期密钥和进行密钥轮换。这些系统提供了比 Kubernetes Secrets 更高级的密钥管理功能,包括自动密钥轮换和审计日志。

最佳实践:定期(我习惯是90天轮换)轮换用于加密 Kubernetes Secrets 的密钥,以及应用使用的所有外部服务密钥。使用密钥管理系统来自动化这个过程。

5. 审计和监控

对密钥访问和使用进行审计和监控,包括对密钥访问请求的日志记录和对异常访问模式的警报。

最佳实践:利用 Kubernetes 审计日志功能以及密钥管理系统提供的审计能力,跟踪对密钥的所有访问和操作。配置监控系统,以便在检测到异常访问模式时发出警报。

6. 安全培训

多做培训和宣导,确保所有参与项目的人员都了解如何安全地处理密钥和敏感信息。

最佳实践:定期(我一般是做季度的培训,已经算很频繁了)举办安全培训和意识提升活动,教育团队成员识别潜在的安全威胁,并采取措施保护敏感信息不被泄露。

上述步骤实际上是可以构建起一套比较全面的密钥防泄漏方案,不仅限于技术层面的控制,还包括组织和流程的改进等。

思考

把存储在 Secret 中的密钥再加密一遍更好吗?

实际上不是的,为什么我想到了这个问题呢?我上家公司的运维团队在我没来的时候,并没有选择开启 Secrets 加密,而是选择自行实现加密算法来加密 Secrets 中的密码。实际上这是比较危险的行为,造成暴露面增加的主要原因是,自行实现的算法会暴露,而且解密这 Secrets 的密钥存储在环境变量里,实际上属于没有任何意义的做法。

实际上直接把 Secrets 中的敏感信息放到环境变量里注入是很靠谱的行为了,没必要为了加密这个环境变量在搞一个加密算法和密钥存储到环境变量里...这样加密一百次都是没意义的行为,属于典型外行行为

只使用 ConfigMap 和环境变量可行吗?

如果我只用ConfigMap和环境变量,并选择自己实现算法加密环境变量,那是不是就不需要用Secrets文件了呢?或者说这样的做法相比使用Secrets文件和数据加密相比,有什么劣势呢?

确实,如果想自己实现也行,但属实没有必要,劣势太明显了:

1. 额外复杂度:

自己实现加密算法就需要在应用程序中处理加密和解密的逻辑。这不仅增加了开发的复杂性,还可能引入新的安全漏洞,特别是如果应用程序的加解密逻辑出错的话,问题更严重。

2. 密钥管理问题:

自行处理加密还涉及到密钥管理的问题,首先需要安全存储用于加密和解密的密钥,而且还要考虑密钥的轮换和备份。如果管理不当的话,安全的暴露面就又多了一个...

3. 缺乏集中审计和监控:

Kubernetes Secrets 和内建的加密功能可以与集群的安全策略和审计日志紧密集成,提供对敏感数据访问的监控和记录。如果选择自己处理加解密,那就还需要额外工作来实现相同级别的安全审计和监控。

4. 不利于跨团队协作:

在团队或组织中,使用 Kubernetes 原生的 Secrets 管理敏感数据有助于统一配置管理方式,减少团队成员之间的理解差异。采用自定义加密方案可能会使新成员更难理解和维护。

所以说,虽然通过自定义加密算法和使用 ConfigMap 来管理敏感数据在技术上是可行的,但从安全性、可维护性和实施复杂性等多个方面考虑,这并非最佳实践。Kubernetes 的 Secrets 和内建的加密支持为敏感数据提供了一个更安全、更易于管理的解决方案,我们又不是搞“信创”,属实没必要自己造轮子了。

Vault 是什么?为什么它经常和 K8s 安全一起出现?

HashiCorp Vault 是一个很著名的开源工具,专门用于安全存储和访问敏感数据,如密码、令牌、API 密钥和其他机密。在 Kubernetes 环境中,Vault 特别受欢迎,因为它提供了一种更灵活更安全的方式来管理跨多个服务和应用程序的 Secrets ,解决了许多原生 Kubernetes Secrets 系统的限制。

Vault 解决了 Kubernetes Secrets 的哪些限制?

  • 动态 Secret :Vault 可以生成动态 Secret ,可以为短期使用自动创建和撤销数据库账户等。相比之下,Kubernetes Secrets 主要用于存储静态秘密,如相对长期的 API 密钥。

  • Secret 撤销和细粒度访问控制:Vault 提供了 Secret 撤销的能力和细粒度的访问策略,可以非常精确地控制谁可以访问哪些 Secret ,以及在什么条件下访问。这实际上超出了 Kubernetes Secrets 自身设计的功能范畴。

  • Secret 租期和自动轮换:Vault 中的 Secret 可以配置租期,并在到期时自动轮换,这有助于确保使用的秘密总是最新和最安全的。Kubernetes Secrets 一般需要手动更新,没有内建的自动轮换机制。

使用 AWS KMS 还是需要 Vault 吗?

还是看需求,我上家公司就用的是AWS KMS,但没有使用 Vault 。

如果需求主要是在 AWS 环境中简单地管理加密密钥,并且这些密钥主要用于 AWS 服务,那么 AWS KMS 其实是足够的。

如果需要更复杂的秘密管理功能,如动态秘密、跨云环境或本地环境的秘密管理,或者对秘密访问的更细粒度控制,那么 Vault 可能是更好的选择。

实际上,Vault 与 AWS KMS 集成起来是很优秀的方案,使用 KMS 作为加密密钥的存储后端,结合两者的优势。上家公司没用只是因为人太少,工作干不完而已...

Comment