【云原生】kubernetes中secret原理详解与应用实战-LMLPHP

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

1.Secret概述

1.1 Secret是什么?

前面我们一起探讨了k8s的Configmap一般是用来存放明文数据的,如配置文件,
对于一些敏感数据,如密码、私钥等数据时,要用secret类型。

Secret解决了密码、token、秘钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。
Secret可以以Volume或者环境变量的方式使用。

要使用 secret,pod 需要引用 secret。Pod 可以用两种方式使用 secret:
作为 volume 中的文件被挂载到 pod 中的一个或者多个容器里,
或者当 kubelet 为 pod 拉取镜像时使用。

secret可选参数有三种:

  • generic: 通用类型,通常用于存储密码数据。
  • tls:此类型仅用于存储私钥和证书。
  • docker-registry: 若要保存docker仓库的认证信息的话,就必须使用此种类型来创建。

Secret类型有三种:

  • Service Account:用于被 serviceaccount 引用。
    serviceaccout 创建时 Kubernetes 会默认创建对应的 secret。
    Pod 如果使用了 serviceaccount,对应的 secret 会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中。

  • Opaque:base64编码格式的Secret,用来存储密码、秘钥等。可以通过base64 --decode解码获得原始数据,因此安全性弱

  • kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息。

1.2 使用Secret

1、通过环境变量引入Secret

#把mysql的root用户的password创建成secret

[root@master01 secret ]#kubectl create secret generic mysql-password --from-literal=password=Jxxxxxxx3x
secret/mysql-password created
[root@master01 secret ]#kubectl get secret
NAME                          TYPE                                  DATA   AGE
default-token-xc8dr           kubernetes.io/service-account-token   3      12d
mysql-password                Opaque                                1      19s
nfs-provisioner-token-8mxt9   kubernetes.io/service-account-token   3      4d22h
[root@master01 secret ]#kubectl describe secret mysql-password
Name:         mysql-password
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  14 bytes

#password的值是加密的,
#但secret的加密是一种伪加密,它仅仅是将数据做了base64的编码.

#创建pod,引用secret

[root@master01 secret ]#vim pod-secret.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret
  labels:
     app: myapp
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    env:
     - name: MYSQL_ROOT_PASSWORD   #它是Pod启动成功后,Pod中容器的环境变量名.
       valueFrom:
          secretKeyRef:
            name: mysql-password  #这是secret的对象名
            key: password      #它是secret中的key名
[root@master01 secret ]#kubectl apply -f pod-secret.yaml 
pod/pod-secret created
[root@master01 secret ]#kubectl exec -it pod-secret -- /bin/sh
/ # printenv 
MYAPP_SVC_PORT_80_TCP_ADDR=10.98.57.156
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://192.168.0.1:443
MYAPP_SVC_PORT_80_TCP_PORT=80
HOSTNAME=pod-secret
SHLVL=1
MYAPP_SVC_PORT_80_TCP_PROTO=tcp
HOME=/root
MYSQL_ROOT_PASSWORD=Jxxxxxxxx3x  这就是传递进来的变量
MYAPP_SVC_PORT_80_TCP=tcp://10.98.57.156:80
TERM=xterm
NGINX_VERSION=1.12.2
KUBERNETES_PORT_443_TCP_ADDR=192.168.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
MYAPP_SVC_SERVICE_HOST=10.98.57.156
KUBERNETES_PORT_443_TCP=tcp://192.168.0.1:443
KUBERNETES_SERVICE_PORT_HTTPS=443
PWD=/
KUBERNETES_SERVICE_HOST=192.168.0.1
MYAPP_SVC_SERVICE_PORT=80
MYAPP_SVC_PORT=tcp://10.98.57.156:80

传递到pod里面后,自动解密了

2、通过volume挂载Secret

1)创建Secret
手动加密,基于base64加密

[root@xianchaomaster1 ~]# echo -n 'admin' | base64
YWRtaW4=
echo -n 'jingtian123456f' | base64

【云原生】kubernetes中secret原理详解与应用实战-LMLPHP

解码:

echo amluZ3RpYW4xMjM0NTZm|base64 -d

【云原生】kubernetes中secret原理详解与应用实战-LMLPHP

2)创建yaml文件

[root@master01 secret ]#vim secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: amluZ3RpYW4xMjM0NTZm
[root@master01 secret ]#kubectl apply -f secret.yaml 
secret/mysecret created
[root@master01 secret ]#
[root@master01 secret ]#kubectl get secret
NAME                          TYPE                                  DATA   AGE
default-token-xc8dr           kubernetes.io/service-account-token   3      12d
mysecret                      Opaque                                2      7s
mysql-password                Opaque                                1      14m
nfs-provisioner-token-8mxt9   kubernetes.io/service-account-token   3      4d23h
[root@master01 secret ]#kubectl describe secret mysecret
Name:         mysecret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  15 bytes
username:  5 bytes

3)将Secret挂载到Volume中

[root@master01 secret ]#vim pod_secret_volume.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-secret-volume
spec:
  containers:
  - name: myapp
    image: registry.cn-beijing.aliyuncs.com/google_registry/myapp:v1
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/secret
      readOnly: true
  volumes:
  - name: secret-volume
    secret:
      secretName: mysecret
[root@master01 secret ]#kubectl apply -f pod_secret_volume.yaml 
pod/pod-secret-volume created
[root@master01 secret ]#kubectl get pods
NAME                               READY   STATUS      RESTARTS        AGE
mysql-pod                          0/1     Completed   0               88m
mysql-pod-envfrom                  0/1     Completed   0               76m
mysql-pod-volume                   0/1     Completed   0               65m
nfs-provisioner-847fb5b8f5-lzvcf   1/1     Running     7 (6h38m ago)   3d7h
pod-pvc                            1/1     Running     1 (7h38m ago)   3d5h
pod-secret                         1/1     Running     0               11m
pod-secret-volume                  1/1     Running     0               15s
test-hostpath                      2/2     Running     6 (7h38m ago)   4d5h
test-nfs-volume                    1/1     Running     3 (7h38m ago)   4d3h
web-0                              1/1     Running     1 (7h38m ago)   2d22h
web-1                              1/1     Running     1 (7h38m ago)   2d22h
web-2                              1/1     Running     1 (7h38m ago)   2d22h
web-3                              1/1     Running     1 (7h38m ago)   2d22h

进去容器查看

[root@master01 secret ]#kubectl exec -it pod-secret-volume -- /bin/sh

/ # ls /etc/secret/
password  username
[root@master01 secret ]#kubectl exec -it pod-secret-volume -- /bin/sh
/ # cat /etc/sec
secret/    securetty
/ # cat /etc/secret/username 
admin/ # 

/ # cat /etc/secret/password 
jingtian123456f/ # 

#由上可见,以卷的方式挂载到pod ,在pod中的secret信息实际已经被解密。

Secret 的类型
创建 Secret 时,你可以使用 Secret 资源的 type 字段,或者与其等价的 kubectl 命令行参数(如果有的话)为其设置类型。
Secret 类型有助于对 Secret 数据进行编程处理。

Kubernetes 提供若干种内置的类型,用于一些常见的使用场景。
针对这些类型,Kubernetes 所执行的合法性检查操作以及对其所实施的限制各不相同。

内置类型 用法

Opaque	用户定义的任意数据
kubernetes.io/service-account-token	服务账号令牌
kubernetes.io/dockercfg	~/.dockercfg 文件的序列化形式
kubernetes.io/dockerconfigjson	~/.docker/config.json 文件的序列化形式
kubernetes.io/basic-auth	用于基本身份认证的凭据
kubernetes.io/ssh-auth	用于 SSH 身份认证的凭据
kubernetes.io/tls	用于 TLS 客户端或者服务器端的数据
bootstrap.kubernetes.io/token	启动引导令牌数据

docker私有仓库,加了https认证后拉取镜像:

imagePullSecret资源将Secret提供的密码传递给kubelet从而在拉取镜像前完成必要的认证过程,
简单说就是你的镜像仓库是私有的,每次拉取是需要认证的。

创建docker-registry类型的Secret对象,并在定义pod资源时明确通过"imagePullSecrets"字段来申明使用哪个私钥去认证;

创建docker-registry类型的Secret对象,然后把它添加到某个ServiceAccount对象中,
使用了这个ServiceAccount对象创建出来的pod就自然而然通过认证获取到镜像;

配置过程
这里创建Secret对象有两种方式,各有千秋。

方式一:通过命令行直接创建Secret

kubectl create secret docker-registry video-docker-redistry-key \
    --docker-server=10.3.9.107:5000 \
    --docker-username='gsafety' \
    --docker-password='123456'

查看key

# kubectl get secret
NAME                        TYPE                                  DATA   AGE
default-token-d9phm         kubernetes.io/service-account-token   3      19h
video-docker-redistry-key   kubernetes.io/dockerconfigjson        1      2s

最后在yaml文件中使用这个创建出来的Secret:

apiVersion: v1
kind: Pod
metadata:
  name: foo
  namespace: awesomeapps
spec:
  containers:
    - name: foo
      image: janedoe/awesomeapp:v1
  imagePullSecrets:
    - name: xxx-key

方式二:通过现存的docker认证文件来创建Secret,首先使用docker login 登录到某个仓库,会在本地保存认证信息

[root@master01 ~ ]#kubectl create secret generic harborsecret --from-file=.dockerconfigjson=/root/.docker/config.json --type=kubernetes.io/dockerconfigjson
secret/harborsecret created

或者:

  #Create a new secret named my-secret from ~/.docker/config.json
  kubectl create secret docker-registry my-secret --from-file=.dockerconfigjson=path/to/.docker/config.json
[root@master01 ~ ]#kubectl create secret docker-registry my-secret --from-file=.dockerconfigjson=/root/.docker/config.json 
secret/my-secret created

注意:config.json文件需要在主机上通过docker login 的方式登录后,才会生成。
这种方式有一个好处,就是如果有多个镜像仓库,都先存在于一个config.json文件中,然后通过命令打入Secret。

[root@master01 ~ ]#kubectl get secret harborsecret -oyaml
apiVersion: v1
data:
  .dockerconfigjson: ewoJImF1dGhzIjogewoJCSJyZXBvc2l0b3J5Lmd1b2tpbmdoay5jb20iOiB7CgkJCSJhdXRoIjogIllXUnRhVzQ2VkdacGFHSXRjSEp2WkhWamRFQXlNREl5IgoJCX0KCX0KfQ==
kind: Secret
metadata:
  creationTimestamp: "2022-11-07T05:52:41Z"
  name: harborsecret
  namespace: default
  resourceVersion: "2355"
  uid: 14503d3d-3992-4d31-9b1d-ff4049990d51
type: kubernetes.io/dockerconfigjson
06-04 10:05