6.5 Secret私密凭据

6.4节提到了Secret对象,Secret的主要作用是保管私密数据,比如密码、OAuth Tokens、SSH Keys等信息。将这些私密信息放在Secret对象中比直接放在Pod或Docker Image中更安全,也更便于使用和分发。

下面的例子用于创建一个Secret:

在上面的例子中,data域各子域的值必须为BASE64编码值,其中password域和username域BASE64编码前的值分别为value-1和value-2。

一旦Secret被创建,就可以通过下面三种方式使用它。

(1)创建Pod时,通过为Pod指定Service Account来自动使用该Secret。

(2)通过挂载该Secret到Pod来使用它。

(3)在Docker镜像下载时使用,通过指定Pod的spc.ImagePullSecrets来使用它。

第1种使用方式主要用在API Server鉴权方面,之前提到过。

下面的例子展示了第2种使用方式,即将一个Secret通过挂载的方式添加到Pod的Volume中:

其结果如图6.4所示。

图6.4 挂载Secret到Pod

第3种使用方式的应用流程如下。

(1)运行login命令,登录私有Registry:

输入用户名和密码,如果是第1次登录系统,则会创建新用户,相关信息被会写入~/.dockercfg文件中。

(2)用BASE64编码dockercfg的内容:

(3)将上一步命令的输出结果作为Secret的data.dockercfg域的内容,由此来创建一个Secret:

(4)在创建Pod时引用该Secret:

其结果如图6.5所示。

图6.5 imagePullSecret引用Secret

每个单独的Secret大小都不能超过1MB,Kubernetes不鼓励创建大的Secret,因为如果使用大的Secret,则将大量占用API Server和kubelet的内存。当然,创建许多小的Secret也能耗尽API Server和kubelet的内存。

在使用Mount方式挂载Secret时,Secret的data各个域的Key值将被设置为目录中的文件名,Value值被BASE64编码后存储在相应的文件中。在前面的例子中创建的Secret,被挂载到一个叫作mycontainer的容器中,在该容器中可通过相应的查询命令查看所生成的文件和文件中的内容,代码如下:

通过上面的例子可以得出如下结论:我们可以通过Secret保管其他系统的敏感信息(比如数据库的用户名和密码),并以Mount的方式将Secret挂载到Container中,然后通过访问目录中文件的方式获取该敏感信息。当Pod被API Server创建时,API Server不会校验该Pod引用的Secret是否存在。一旦这个Pod被调度,则kubelet将试着获取Secret的值。如果Secret不存在或暂时无法连接到API Server,则kubelet将按一定的时间间隔定期重试获取该Secret,并发送一个Event来解释Pod没有启动的原因。一旦Secret被Pod获取,则kubelet将创建并挂载包含Secret的Volume。只有所有Volume都挂载成功,Pod中的Container才会被启动。在kubelet启动Pod中的Container后,Container中与Secret相关的Volume将不会被改变,即使Secret本身被修改。为了使用更新后的Secret,必须删除旧Pod,并重新创建一个新Pod。

当Secret通过Volume方式被使用时,对Secret数据的任何修改都会引发Volume的同步更新,如果在一个业务系统中有大量Secret数据以Volume方式被使用,则可能带来性能问题。另外,Secret数据也可能被意外修改从而导致系统出现问题,为此,kubernetes 1.19版本默认开启了ImmutableEphemeralVolumes新特性,我们可以通过设置Secret的immutable属性为true创建一个不可变的Secret对象。