0%

K8s-Secret概述

Kubernetes Secret 对象可以用来储存敏感信息,例如:密码、OAuth token、ssh 密钥等

一、Secret概述

概述

Kubernetes Secret 对象可以用来储存敏感信息,例如:密码、OAuth token、ssh 密钥等。如果不使用 Secret,此类信息可能被放置在 Pod 定义中或者容器镜像中。将此类敏感信息存储到 Secret 中,可以更好地:

  • 控制其使用
  • 降低信息泄露的风险

用户可以直接创建 Secret,Kubernetes 系统也会创建一些 Secret。

Secret有如下几种使用方式:

  • 作为 Pod 的数据卷挂载
  • 作为 Pod 的环境变量
  • kubelet 在抓取容器镜像时,作为 docker 镜像仓库的用户名密码

内建Secret

Service Account 将自动创建 Secret

Kubernetes 自动创建包含访问 Kubernetes APIServer 身份信息的 Secret,并自动修改 Pod 使其引用这类 Secret。

如果需要,可以禁用或者自定义自动创建并使用 Kubernetes APIServer 身份信息的特性。然而,如果期望安全地访问 Kubernetes APIServer,应该使用默认的 Secret 创建使用过程。

自建Secret

可以使用如下方式创建自己的 Secret:

  • 使用 kubectl 创建 Secret
  • 手动创建 Secret
  • 使用 Generator 创建 Secret

解码和编辑

Kubenetes 中,Secret 使用 base64 编码存储,您可以将其解码获得对应信息的原文,创建 Secret 之后,您也可以再次编辑Secret

二、创建Secret(使用kubectl)

假设某个 Pod 需要访问数据库。在您执行 kubectl 命令所在机器的当前目录,创建文件 ./username.txt 文件和 ./password.txt 暂存数据库的用户名和密码,后续我们根据这两个文件配置 kubernetes secrets。

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

在 Kubernetes APIServer 中创建 Secret 对象,并将这两个文件中的内容存储到该 Secret 对象中,执行命令,输出结果如下所示:

1
2
[root@k8s-master 0425]# kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt 
secret/db-user-pass created
  • 上述命令的执行效果与此命令执行效果相同: kubectl create secret generic db-user-pass –from-literal=username=admin –from-literal=password=1f2d1e2e67df

  • 如果密码中包含特殊字符需要转码(例如 $*\!),请使用 \ 进行转码。例如:实际密码为 S!B\*d$zDsb,kubectl 命令应该写成 kubectl create secret generic dev-db-secret –from-literal=username=devuser –from-literal=password=S\!B\\*d\$zDsb。如果通过文件创建(–from-file),则无需对文件中的密码进行转码。

    检查 Secret 的创建结果,输出信息如下所示:

1
2
3
4
5
[root@k8s-master 0425]# kubectl get secrets
NAME TYPE DATA AGE
db-user-pass Opaque 2 57s
default-token-xws5p kubernetes.io/service-account-token 3 28d
nginxsecret Opaque 2 15d

查看 Secret 详情,输出信息如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
[root@k8s-master 0425]# kubectl describe secrets db-user-pass
Name: db-user-pass
Namespace: default
Labels: <none>
Annotations: <none>

Type: Opaque

Data

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

默认情况下,kubectl getkubectl describe 命令都避免展示 Secret 的内容。这种做法可以避免密码被偷窥,或者被存储到终端的日志中

三、创建Secret(手动)

可以在 yaml 文件中定义好 Secret,然后通过 kubectl apply -f 命令创建。通过如下两种方式在 yaml 文件中定义 Secret:

  • data:使用 data 字段时,取值的内容必须是 base64 编码的
  • stringData:使用 stringData 时,更为方便,您可以直接将取值以明文的方式写在 yaml 文件中

在 yaml 中定义 data

  • 假设要保存 username=adminpassword=1f2d1e2e67df 到 Secret 中,要先将数据的值转化为 base64 编码,执行如下命令:
1
2
3
4
echo -n 'admin' | base64
YWRtaW4=
echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm

创建 secret.yaml 文件,内容如下所示:

1
2
3
4
5
6
7
8
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm

执行命令创建:

1
2
kubectl apply -f ./secret.yaml
secret "mysecret" created

在 yaml 中定义 stringData

假如并不想先将用户名和密码转换为 base64 编码之后再创建 Secret,则,可以通过定义 stringData 来达成,此时 stringData 中的取值部分将被 apiserver 自动进行 base64 编码之后再保存。

  • 创建文件 secret.yaml,内容如下所示:
1
2
3
4
5
6
7
8
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
stringData:
username: admin
password: 1f2d1e2e67df

执行命令

1
2
kubectl apply -f ./secret.yaml
secret "mysecret" created

执行命令 kubectl get -f ./secret.yaml -o yaml 输出结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
data:
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"mysecret","namespace":"default"},"stringData":{"password":"1f2d1e2e67df","username":"admin"},"type":"Opaque"}
creationTimestamp: "2019-09-23T14:16:56Z"
name: mysecret
namespace: default
resourceVersion: "10318365"
selfLink: /api/v1/namespaces/default/secrets/mysecret
uid: 24602031-e18d-467a-b7fe-0962af8ec8b8
type: Opaque

同时定义了 data 和 stringData

如果同时定义了 data 和 stringData,对于两个对象中key 重复的字段,最终将采纳 stringData 中的 value

创建文件 secret.yaml,该文件同时定义了 data 和 stringData,内容如下所示:

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
stringData:
username: administrator

执行命令

1
2
kubectl apply -f ./secret.yaml
secret "mysecret" created

执行命令 kubectl get -f ./secret.yaml -o yaml 输出结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@k8s-master 0425]# kubectl get -f  secret.yaml -o yaml
apiVersion: v1
data:
username: YWRtaW5pc3RyYXRvcg==
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","data":{"username":"YWRtaW4="},"kind":"Secret","metadata":{"annotations":{},"name":"mysecret","namespace":"default"},"stringData":{"username":"administrator"},"type":"Opaque"}
creationTimestamp: "2020-04-25T05:46:21Z"
name: mysecret
namespace: default
resourceVersion: "1544704"
selfLink: /api/v1/namespaces/default/secrets/mysecret
uid: 1b1d10a7-87e2-40a4-8101-693aad84eca2
type: Opaque

此处 YWRtaW5pc3RyYXRvcg== 解码后的值是 administrator

将配置文件存入 Secret

假设某个应用程序需要从一个配置文件中读取敏感信息,此时,可以将该文件的内容存入 Secret,再通过数据卷的形式挂载到容器。

例如,应用程序需要读取如下配置文件内容:

1
2
3
apiUrl: "https://my.api.com/api/v1"
username: user
password: password

可以使用下面的 secret.yaml 创建 Secret

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
stringData:
config.yaml: |-
apiUrl: "https://my.api.com/api/v1"
username: user
password: password

执行命令:

1
2
kubectl apply -f ./secret.yaml
secret "mysecret" created
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@k8s-master 0425]# kubectl get -f secret.yaml -o yaml
apiVersion: v1
data:
config.yaml: YXBpVXJsOiAiaHR0cHM6Ly9teS5hcGkuY29tL2FwaS92MSIKdXNlcm5hbWU6IHVzZXIKcGFzc3dvcmQ6IHBhc3N3b3Jk
username: ""
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"mysecret","namespace":"default"},"stringData":{"config.yaml":"apiUrl: \"https://my.api.com/api/v1\"\nusername: user\npassword: password"},"type":"Opaque"}
creationTimestamp: "2020-04-25T05:46:21Z"
name: mysecret
namespace: default
resourceVersion: "1545171"
selfLink: /api/v1/namespaces/default/secrets/mysecret
uid: 1b1d10a7-87e2-40a4-8101-693aad84eca2
type: Opaque

四、解码和编辑Secret

解码Secret

Secret 中的信息可以通过 kubectl get secret 命令获取。

执行命令 kubectl get secret mysecret -o yaml 可获取所创建的 Secret,输出信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@k8s-master 0425]# kubectl get secret mysecret -o yaml
apiVersion: v1
data:
config.yaml: ""
password: MWYyZDFlMmU2N2Rm
username: YWRtaW4=
kind: Secret
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"mysecret","namespace":"default"},"stringData":{"password":"1f2d1e2e67df","username":"admin"},"type":"Opaque"}
creationTimestamp: "2020-04-25T05:46:21Z"
name: mysecret
namespace: default
resourceVersion: "1546981"
selfLink: /api/v1/namespaces/default/secrets/mysecret
uid: 1b1d10a7-87e2-40a4-8101-693aad84eca2
type: Opaque

执行命令 echo 'MWYyZDFlMmU2N2Rm' | base64 --decode 可解码密码字段,输出结果如下:

1
2
[root@k8s-master 0425]# echo 'MWYyZDFlMmU2N2Rm' | base64 --decode
1f2d1e2e67df

执行命令 echo 'YWRtaW4=' | base64 --decode 可解码用户名字段,输出结果如下:

1
2
[root@k8s-master 0425]# echo 'YWRtaW4=' | base64 --decode
admin

编辑Secret

执行命令 kubectl edit secrets mysecret 可以编辑已经创建的 Secret,该命令将打开一个类似于 vi 的文本编辑器,可以直接编辑已经进行 base64 编码的字段,如下所示:

1
2
[root@k8s-master 0425]# kubectl edit secrets mysecret
Edit cancelled, no changes made.