【云原生 | Kubernetes 系列】K8s 实战 管理 Secret 详解


前言

在这里插入图片描述

Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。 这样的信息可能会被放在 Pod 规约中或者镜像中。 用户可以创建 Secret,同时系统也创建了一些 Secret。


一、使用 kubectl 管理 Secret

1.1、创建 Secret

一个 Secret 可以包含 Pod 访问数据库所需的用户凭证。 例如,由用户名和密码组成的数据库连接字符串。 你可以在本地计算机上,将用户名存储在文件 ./username.txt 中,将密码存储在文件 ./password.txt 中。

echo -n 'admin' > ./username.txt
echo -n '1f2d1e2e67df' > ./password.txt

在这些命令中,-n 标志确保生成的文件在文本末尾不包含额外的换行符。 这一点很重要,因为当 kubectl 读取文件并将内容编码为 base64 字符串时,多余的换行符也会被编码。

kubectl create secret 命令将这些文件打包成一个 Secret 并在 API 服务器上创建对象。

$ kubectl create secret generic db-user-pass \
  --from-file=./username.txt \
  --from-file=./password.txt

输出类似于:

secret/db-user-pass created

默认密钥名称是文件名。 可以使用 --from-file=[key=]source 来设置密钥名称。

例如:

$ kubectl create secret generic db-user-pass \
  --from-file=username=./username.txt \
  --from-file=password=./password.txt

不需要对文件中包含的密码字符串中的特殊字符进行转义。

还可以使用 --from-literal=<key>=<value> 标签提供 Secret 数据。 可以多次使用此标签,提供多个键值对。
需要注意,特殊字符(例如:$,\,*,= 和 !)由你的 shell 解释执行,而且需要转义。

在大多数 shell 中,转义密码最简便的方法是用单引号括起来。 比如,如果你的密码是 S!B\*d$zDsb=, 可以像下面一样执行命令:

$ kubectl create secret generic db-user-pass \
  --from-literal=username=devuser \
  --from-literal=password='S!B\*d$zDsb='

1.2、验证 Secret

检查 secret 是否已创建:

$ kubectl get secrets

输出类似于:

NAME                  TYPE                                  DATA      AGE
db-user-pass          Opaque                                2         51s

你可以查看 Secret 的描述:

$ kubectl describe secrets/db-user-pass

输出类似于:

Name:            db-user-pass
Namespace:       default
Labels:          <none>
Annotations:     <none>

Type:            Opaque

Data
====
password:    12 bytes
username:    5 bytes

kubectl getkubectl describe 命令默认不显示 Secret 的内容。 这是为了防止 Secret 被意外暴露或存储在终端日志中。

1.3、解码 Secret

要查看创建的 Secret 的内容,运行以下命令:

$ kubectl get secret db-user-pass -o jsonpath='{
    
    .data}'

这里会输出你的账号和密码,我就不贴了。

现在你可以解码 password 的数据:

# 这是一个用于文档说明的示例。
# 如果你这样做,数据 'MWYyZDFlMmU2N2Rm' 可以存储在你的 shell 历史中。
# 可以进入你电脑的人可以找到那个记住的命令并可以在你不知情的情况下 base-64 解码这个 Secret。
# 通常最好将这些步骤结合起来,如页面后面所示。
echo 'MWYyZDFlMmU2N2Rm' | base64 --decode

输出类似于:

1f2d1e2e67df

为了避免在 shell 历史记录中存储 Secret 的编码值,可以执行如下命令:

$ kubectl get secret db-user-pass -o jsonpath='{
    
    .data.password}' | base64 --decode

输出应与上述类似。

1.4、清理

删除创建的 Secret:

$ kubectl delete secret db-user-pass

二、使用配置文件管理 Secret

2.1、创建 Secret

你可以先用 JSON 或 YAML 格式在一个清单文件中定义 Secret 对象,然后创建该对象。 Secret 资源包含 2 个键值对:data 和 stringData。 data 字段用来存储 base64 编码的任意数据。 提供 stringData 字段是为了方便,它允许 Secret 使用未编码的字符串。 data 和 stringData 的键必须由字母、数字、-、_ 或 . 组成。

我来使用 data 字段在 Secret 中存储两个字符串:

  1. 将这些字符串转换为 base64:
echo -n 'admin' | base64
echo -n '1f2d1e2e67df' | base64

输出类似于:

YWRtaW4=
MWYyZDFlMmU2N2Rm
  1. 创建清单:
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm

Secret 对象的名称必须是有效的 DNS 子域名。

  1. 使用 kubectl apply 创建 Secret:
$ kubectl apply -f ./secret.yaml

输出类似于:

secret/mysecret created

2.2、创建 Secret 时提供未编码的数据

对于某些场景,你可能希望使用 stringData 字段。 这个字段可以将一个非 base64 编码的字符串直接放入 Secret 中, 当创建或更新该 Secret 时,此字段将被编码。

上述用例的实际场景可能是这样:当你部署应用时,使用 Secret 存储配置文件, 你希望在部署过程中,填入部分内容到该配置文件。

如果你的应用程序使用以下配置文件:

apiUrl: "https://my.api.com/api/v1"
username: "<user>"
password: "<password>"

你可以使用以下定义将其存储在 Secret 中:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
stringData:
  config.yaml: |
    apiUrl: "https://my.api.com/api/v1"
    username: <user>
    password: <password>   

当你检索 Secret 数据时,此命令将返回编码的值,并不是你在 stringData 中提供的纯文本值。

运行以下命令:

$ kubectl get secret mysecret -o yaml

输出类似于:

apiVersion: v1
data:
  config.yaml: YXBpVXJsOiAiaHR0cHM6Ly9teS5hcGkuY29tL2FwaS92MSIKdXNlcm5hbWU6IHt7dXNlcm5hbWV9fQpwYXNzd29yZDoge3twYXNzd29yZH19
kind: Secret
metadata:
  creationTimestamp: 2018-11-15T20:40:59Z
  name: mysecret
  namespace: default
  resourceVersion: "7225"
  uid: c280ad2e-e916-11e8-98f2-025000000001
type:

2.3、同时指定 data 和 stringData

如果在 data 和 stringData 中设置了同一个字段,则使用来自 stringData 中的值。

可以定义以下 Secret:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
stringData:
  username: administrator

所创建的 Secret 对象如下:

apiVersion: v1
data:
  username: YWRtaW5pc3RyYXRvcg==
kind: Secret
metadata:
  creationTimestamp: 2018-11-15T20:46:46Z
  name: mysecret
  namespace: default
  resourceVersion: "7579"
  uid: 91460ecb-e917-11e8-98f2-025000000001
type: Opaque
YWRtaW5pc3RyYXRvcg== 解码成 administrator。

2.4、清理

删除你创建的 Secret:

$ kubectl delete secret mysecret

三、使用 Kustomize 管理 Secret

从 kubernetes v1.14 开始,kubectl 支持使用 Kustomize 管理对象。 Kustomize 提供了资源生成器(Generators)来创建 Secret 和 ConfigMap。 Kustomize 生成器应该在某个目录的 kustomization.yaml 文件中指定。 生成 Secret 后,你可以使用 kubectl apply 在 API 服务器上创建该 Secret。

3.1、创建 Kustomization 文件

你可以在 kustomization.yaml 中定义 secreteGenerator 字段,并在定义中引用其它本地文件生成 Secret。 例如:下面的 kustomization 文件 引用了 ./username.txt./password.txt 文件:

secretGenerator:
- name: db-user-pass
  files:
  - username.txt
  - password.txt

你也可以在 kustomization.yaml 文件中指定一些字面量定义 secretGenerator 字段。 例如:下面的 kustomization.yaml 文件中包含了 username 和 password 两个字面量:

secretGenerator:
- name: db-user-pass
  literals:
  - username=admin
  - password=1f2d1e2e67df

你也可以使用 .env 文件在 kustomization.yaml 中定义 secretGenerator。 例如:下面的 kustomization.yaml 文件从 .env.secret 文件获取数据。

secretGenerator:
- name: db-user-pass
  envs:
  - .env.secret

注意,上面两种情况,你都不需要使用 base64 编码。

3.2、创建 Secret

在包含 kustomization.yaml 文件的目录下使用 kubectl apply 命令创建 Secret。

$ kubectl apply -k .

输出类似于:

secret/db-user-pass-96mffmfh4k created

请注意,生成 Secret 时,Secret 的名称最终是由 name 字段和数据的哈希值拼接而成。 这将保证每次修改数据时生成一个新的 Secret。

3.3、检查创建的 Secret

你可以检查刚才创建的 Secret:

$ kubectl get secrets

输出类似于:

NAME                             TYPE                                  DATA      AGE
db-user-pass-96mffmfh4k          Opaque                                2         51s

你可以看到 Secret 的描述:

$ kubectl describe secrets/db-user-pass-96mffmfh4k

输出类似于:

Name:            db-user-pass-96mffmfh4k
Namespace:       default
Labels:          <none>
Annotations:     <none>

Type:            Opaque

Data
====
password.txt:    12 bytes
username.txt:    5 bytes

kubectl getkubectl describe 命令默认不显示 Secret 的内容。 这是为了防止 Secret 被意外暴露给旁观者或存储在终端日志中。

3.5、清理

删除你创建的 Secret:

$ kubectl delete secret db-user-pass-96mffmfh4k

总结

通过 API 创建的 Pod 时,不会检查应用的 secret 是否存在。一旦 Pod 被调度,kubelet 就会尝试获取该 secret 的值。如果获取不到该 secret,或者暂时无法与 API server 建立连接,kubelet 将会定期重试。Kubelet 将会报告关于 pod 的事件,并解释它无法启动的原因。一旦获取的 secret,kubelet将创建并装载一个包含它的卷。在安装所有pod的卷之前,都不会启动 pod 的容器。

猜你喜欢

转载自blog.csdn.net/u010755471/article/details/126508811