date: 2020-07-31title: k8s之secret #标题
tags: secret #标签
categories: k8s # 分类

k8s中使用secret对象来存储敏感信息,例如密码,证书,ssh密钥等,如果不使用 Secret,此类信息可能被放置在 Pod 定义中或者容器镜像中。将此类敏感信息存储到 Secret 中,可以更好地控制其使用以及降低泄露的风险。

创建secret

secret有如下几种使用场景:

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

假设某个pod需要访问数据库,我们就可以通过secret来存储数据库的账户信息,然后挂载到pod中。

下面记录下创建secret资源对象的几种方式。

通过—from-file的方式创建

  1. # 准备数据文件
  2. $ echo -n "admin" > .username.txt
  3. $ echo -n "1f2d1e2e67df" > .passwd.txt
  4. # 通过--from-file的方式创建
  5. $ kubectl create secret generic db-user-pass --from-file=.username.txt --from-file=.passwd.txt
  6. secret/db-user-pass created

通过—from-literal的方式创建

  1. $ kubectl create secret generic db-user-pass --from-literal=username=admin --from-literal=password=1f2d1e2e67df
  2. secret/db-user-pass created

通过—from-env-file的方式创建

  1. # 准备变量文件
  2. $ cat > env.txt <<EOF
  3. > username=admin
  4. > password=1f2d1e2e67df
  5. > EOF
  6. # 创建
  7. $ kubectl create secret generic db-user-pass --from-env-file=env.txt

通过yaml配置文件文件来创建

  1. # 先将数据加密
  2. $ echo admin | base64
  3. YWRtaW4K
  4. $ echo 1f2d1e2e67df | base64
  5. MWYyZDFlMmU2N2RmCg==
  6. # 编写yaml文件
  7. $ cat secret.yaml
  8. apiVersion: v1
  9. kind: Secret
  10. metadata:
  11. name: db-user-pass
  12. type: Opaque
  13. data:
  14. username: YWRtaW4K
  15. password: MWYyZDFlMmU2N2RmCg==

在yaml文件中定义secret有以下两种方式:

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

以下是使用stringData来编写的yaml文件,stringData 中的取值部分将被 apiserver 自动进行 base64 编码之后再保存。

  1. $ cat secret.yaml
  2. apiVersion: v1
  3. kind: Secret
  4. metadata:
  5. name: db-user-pass
  6. type: Opaque
  7. stringData:
  8. username: admin
  9. password: 1f2d1e2e67df
  10. $ kubectl apply -f secret.yaml # 执行yaml文件

同时定义了data和stringData

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

  1. $ cat secret.yaml # yaml文件如下
  2. apiVersion: v1
  3. kind: Secret
  4. metadata:
  5. name: my-name
  6. type: Opaque
  7. data:
  8. username: YWRtaW4K # 这是admin加密后的字符串
  9. stringData:
  10. username: administrator
  11. password: 1f2d1e2e67df
  12. $ kubectl apply -f secret.yaml # 创建
  13. $ kubectl get secret/my-name -o yaml # 查看
  14. apiVersion: v1
  15. data:
  16. password: MWYyZDFlMmU2N2Rm
  17. username: YWRtaW5pc3RyYXRvcg==
  18. kind: Secret
  19. metadata:
  20. annotations:
  21. kubectl.kubernetes.io/last-applied-configuration: |
  22. {"apiVersion":"v1","data":{"username":"YWRtaW4K"},"kind":"Secret","metadata":{"annotations":{},"name":"my-name","namespace":"default"},"stringData":{"password":"1f2d1e2e67df","username":"administrator"},"type":"Opaque"}
  23. $ echo 'YWRtaW5pc3RyYXRvcg==' | base64 --decode # 将username的值解密后如下
  24. administrator

查看secret资源对象

  1. $ kubectl describe secret/db-user-pass # 查看创建的secret对象详细信息
  2. Name: db-user-pass
  3. Namespace: default
  4. Labels: <none>
  5. Annotations:
  6. Type: Opaque
  7. Data
  8. ====
  9. password: 13 bytes
  10. username: 6 bytes

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

但如果输出yaml文件的,就有点不一样了,如下:

  1. $ kubectl get secret/db-user-pass -o yaml # 执行此命令输出如下
  2. apiVersion: v1
  3. data:
  4. password: MWYyZDFlMmU2N2Rm
  5. username: YWRtaW4=
  6. kind: Secret
  7. metadata:
  8. annotations:
  9. kubectl.kubernetes.io/last-applied-configuration: |
  10. {"apiVersion":"v1","kind":"Secret","metadata":{"annotations":{},"name":"db-user-pass","namespace":"default"},"stringData":{"password":"1f2d1e2e67df","username":"admin"},"type":"Opaque"}
  11. creationTimestamp: "2020-07-29T23:45:16Z"
  12. managedFields:
  13. - apiVersion: v1
  14. fieldsType: FieldsV1
  15. fieldsV1:
  16. f:data:
  17. .: {}
  18. f:password: {}
  19. f:username: {}
  20. f:metadata:
  21. f:annotations:
  22. .: {}
  23. f:kubectl.kubernetes.io/last-applied-configuration: {}
  24. f:type: {}
  25. manager: kubectl
  26. operation: Update
  27. time: "2020-07-29T23:45:16Z"
  28. name: db-user-pass
  29. namespace: default
  30. resourceVersion: "81928"
  31. selfLink: /api/v1/namespaces/default/secrets/db-user-pass
  32. uid: e95603a1-ce84-4616-bacb-d061cc373e96
  33. type: Opaque

注意:

  • 此时annotation 中可以看到 password 的明文,这也许并不是我们所期望的
  • 输出的 Secret 对象中,stringData 字段不再出现

使用generator创建secret

从 kubernetes v1.14 开始,kubectl 集成了 Kustomize。通过 Kustomize,我们可以使用 generator(Kustomize 的概念)创建 Secret,并保存到 API Server。Generator 必须在 kustomization.yaml 文件中指定。

从文件生成secret

  1. # 准备文件
  2. $ echo "admin" > username.txt
  3. $ echo "123.com" > passwd.txt
  4. # 准备yaml文件
  5. $ cat << EOF > kustomization.yaml
  6. > secretGenerator:
  7. > - name: user-pass
  8. > files:
  9. > - username.txt
  10. > - passwd.txt
  11. > EOF
  12. $ kubectl apply -k . # 执行创建secret
  13. secret/user-pass-9ddfk46m67 created
  14. # 这种方式创建的secret不会将信息明文显示出来。
  15. # 从明文创建secret的文件内容如下:
  16. $ cat << EOF > kustomization.yaml
  17. > secretGenerator:
  18. > - name: db-user-pass
  19. > literals:
  20. > - username=admin
  21. > - password=secret
  22. > EOF

解码secret信息

  1. # secret中的信息可以通过下面指令获取
  2. kubectl get secret/user-pass-tkkkhcd4t8 -o yaml
  3. # 获取到信息后,可以使用下面指令进行解码
  4. $ echo 'MTIzLmNvbWFiYwo=' | base64 --decode