目前为止,我们还没有真正讨论过前端要连接的Redis服务。在任何实际应用中,我们都需要确保服务间的连接安全。一方面是为了确保用户及其数据的安全,另一方面是为了防止出现诸如将开发环境的前端连接到生产数据库之类的错误。
Redis数据库使用简单的密码认证模式。将密码存储在应用程序源代码或容器镜像的文件中可能是比较方便的,但是这两种做法都不太明智。首先你将机密数据(例如密码)泄漏到了无须考虑访问控制的环境中。如果将密码放入源代码,那么你就需要为源代码和所有机密数据设置相同的访问权限,这很可能是不合适的。能够访问源代码的用户很可能要比真正需要访问Redis的用户多得多。同样,能够访问容器镜像的人也不一定需要有生产数据库的访问权限。
除了访问控制之外,参数化是避免将机密数据绑定到源代码或镜像的另一个原因。你可能想在各种环境(例如,开发、金丝雀和生产)中使用相同的源代码和镜像。如果将机密数据紧密地绑定在源代码或镜像中,那么每种环境都需要不同的镜像(或代码)。
在1.5节了解了ConfigMap之后,你可能会立即想到将密码保存为配置并作为特定于应用程序的配置注入应用程序。你也会自然而然地认为,配置与应用的分离和机密与应用的分离是同一个概念,但事实上,机密本身就是一个重要的概念。你很可能希望以与配置不同的方式来处理访问控制、处理和机密更新。更为重要的是,你希望开发者用不同的思维方式看待机密与配置的访问。因此,Kubernetes提供了内置的Secret资源来管理机密数据。
你可以使用如下命令为示例程序中的Redis数据库创建密码,并将其存储在Secret中:
显然,你会想要使用其他的内容而非随机数作为密码。此外,你可能更希望使用一个机密/密钥管理服务,不管是来自云服务商(如Microsoft Azure Key Vault),还是来自开源项目(如HashiCorp的Vault)。当你使用密钥管理服务时,它们通常都与Kubernetes的Secret有着更紧密的集成。
默认情况下,Secret中的数据是未加密的。如果你要对机密数据进行加密存储,则需要与密钥提供程序进行集成以获得密钥,Kubernetes将使用该密钥来加密集群中的所有机密。请注意,尽管这样可以保护密钥不会受到
etcd
数据库被直接攻击的影响,但是仍然需要确保Kubernetes API服务器的访问安全。
在Kubernetes中将Redis的密码作为机密存储后,你需要在部署到Kubernetes时将该机密绑定到正在运行的应用程序。为此,你可以使用Kubernetes的Volume。Volume实际上是一个文件或目录,它可以挂载到用户指定位置正在运行的容器中。对于机密来说,可以将Volume创建为基于内存的tmpfs文件系统并将其挂载到容器中。这样可以确保即使机器遭到物理泄漏(在云环境中不太可能,但在数据中心中可能会发生),攻击者也很难获得机密数据。
你需要在Deployment的YAML中添加两个新的配置来绑定secret volume。首先你需要在Pod中配置
volume
字段:
其次,你需要在容器的配置中设置
volumeMounts
字段来挂载Pod中配置的Volume:
上述配置将该secret volume挂载到容器的
redis-passwd
目录以供客户端的代码访问。完整的Deployment如下所示:
至此,我们已经为客户端应用配置了一个用于Redis服务身份认证的Secret。为Redis本身配置密码也需要类似的操作。将Secret挂载到Redis的Pod中,让Pod可以从文件中加载密码。