使用 Mozilla SOPS 来加密 Kubernetes 集群中的敏感信息

Kubernetes 已经成为运行容器工作负载的事实标准,在很多大型企业的数字开放平台也处于中心地位。然而,和 Kubernetes 相关的工作非常有挑战性,这其中之一就是如何处理工作负载正常运行所需要的一些敏感信息。这些敏感信息包括但不限于密码,API 密钥,令牌等等。

任何不小心的敏感信息泄漏将对这种大型企业的声誉以及收入带来严重威胁,所以必须使用一种安全的方式来存储这些数据。关于这个问题有许多不同的解决方案,本文将分享如何使用 Mozilla SOPS 来存储敏感数据的方案,这个方案不需要太多的修改和适配。


Kubernetes 中的敏感信息长什么样?

对于 Kubernetes 的新手,可以快速看一下如下截图,了解敏感信息在 Kubernetes 中是怎样定义的:

image.png 一个典型的 Kubernetes 集群中的敏感数据

如上图所示,这是 Kubernetes 中敏感信息的默认类型,所有信息都以键值对的形式保存在一个 YAML 文件中, data 区域的值必须使用 base64 编码。这个文件一旦创建出来,你就可以使用以下命令将敏感数据部署到你的命名空间中:

shell kubectl apply -f mysecret.yml

现在我们知道敏感数据长什么样了,如果我们希望保持它们的安全,就需要回答两个问题:

  • 我要将这个 YAML 文件放置在哪里?以什么方式保存?
  • 当敏感信息被部署到命名空间中后,如何放置泄漏?

使用 Mozilla SOPS 存储敏感信息


Mozilla SOPS 是一个加密文件编辑器,支持 YAML、JSON、ENV、INI 以及二进制文件,也支持各种不同的加密提供商诸如 AWS KMS、GCP KMS、Azure Key Vault、Hashicorp Vault 以及 PGP。保存敏感数据可以有很多选项,但是对于 Kubernetes 来说,SOPS 尤其适合,主要有以下这些原因:

  • 易于使用:你只需要解密、编辑、然后加密即可,不需要学习新的工具,也不需要使用 Restful API 和第三方服务打交道而导致的学习曲线陡峭。
  • 可以将代码和敏感数据放在一起:将敏感信息加密可以让你将它们随代码一起提交到版本管理系统(如 git)中,相比其他方案,这将大大简化持续集成/持续部署流程。
  • 跟踪变化特别简单:和上一个优点相关:将敏感信息提交到版本管理系统中,跟踪变化就非常简单了。而且还可以看出是谁做了什么改变。
  • 不需要额外的基础设施支持:其他方案比如 Hashicorp 就需要额外的工具链,甚至需要为其部署额外的存储设施(Consul、DynamoDB 等等)。这些额外的工具增加了架构中的复杂性,但是并没有为你的产品带来额外的价值。
  • 没有扩展问题:再一次和前一个优点相关,由于不需要额外的基础设施,也就不需要为其做额外的运维和扩展工作,对某些大项目来说这些工作可能是很大的一个问题。


接下来让我们看一下如何使用它来加密敏感数据。


使用 SOPS 来加解密

SOPS 的官方文档中已经有一个使用 PGP 密钥的基本用法,但是其强大之处在于 **.sops.yaml **文件,所有的魔法都在这个文件里。来看一下它长什么样:

image.png .sops.yaml 的样例文件

.sops.yaml 文件包含了对代码仓库中的文件进行加解密的所有规则。以上面的文件为例,对于加解密有两个不同的规则。这些规则的优先级是从上到下的,第一个出现的规则被优先应用。详细地说:

  • 第一个是说所有匹配正则表达式的文件将使用 AWS KMS 进行加解密。结合 SOPS 和 AWS KMS 的主要优势在于你可以给 SOPS 在不同的区域提供多个不同的密钥,从而避免了加解密过程中的单点故障。
  • 第二个是说文件将使用给定的 PGP 密钥进行加解密。对于不匹配前一个规则中的文件,这个规则将被应用。

一旦你写好了你的 .sops.yaml 文件,就可以用如下命令进行加密:

shell sops -e -p <yourkeyhere>

这会产生类似如下的输出:

image.png 使用 SOPS 加密的结果示意图

正如你所看到的,文件中所有相关数据都已经被加密。SOPS 并不会加密键,所以你不必关心具体的值,就能很容易看到什么值被修改了。

SOPS 也支持密钥轮换,假设你的密钥泄漏了,那么你可以将它们从 .sops.yaml 文件中移除,然后重新加密,这很简单,只需要:

shell sops -r -i --rm-pgp <yourkeyhere> filename

如果需要更高级的用法和示例,可以参考 SOPS 的文档。

好,现在敏感数据已经被安全地存储在版本管理系统中了,但还有一个问题待解决:如何保证敏感数据在集群中的安全?

在集群中加密敏感数据: RBAC

敏感数据已经安全地保存在版本管理系统中了,是时候保证只让授权过的用户访问它们了。

通常,在集群中我们使用命名空间隔离不同项目,并且默认授予在这些命名空间中的所有权限。这是一个很糟糕的实践,得不惜一切代价摒弃这种做法。幸运的是 Kubernetes 提供了一个非常强大的角色系统可供使用。

先创建一个新的角色:

yaml

apiVersion rbac.authorization.k8s.io/v1 kind Role metadata namespace your_namespace name read-only-role rules

  • apiGroups [] resources [pods, configmaps, services, pods/log] verbs [get, watch, list]

这是一个很基本的角色,它允许所有人在你的命名空间 your_namespace 中执行如下几个操作:

  • 查询/列出/观察 pod, configmap 和 services
  • 从 pod 中查询日志


现在该绑定这个角色了,这需要一个 rolebinding,正如其名,它将角色绑定到一个主题上。主题可以是用户、组或者服务账号。可以使用如下示例将角色绑定到一个用户:

yaml apiVersion rbac.authorization.k8s.io/v1 kind RoleBinding metadata name read-only namespace your_namespace subjects

  • kind User name Jeff # Name is case sensitive, so be careful with that! apiGroup rbac.authorization.k8s.io roleRef kind Role name read-only-role apiGroup rbac.authorization.k8s.io

一旦应用,就算凭据被泄漏(最好不要),恶意攻击者将只能做前面列出的仅有的几个操作,不会对基础设施造成威胁。


总结


SOPS 是加密的强大工具,但是必须记住仍然需要应用更多的和集群相关的策略(比如本文建议的一个)才能是你的秘密信息真的被保密。

以上是某大型企业的生产实践,欢迎留言分享你在 Kubernetes 集群中处理敏感信息的策略。