八、为什么要引入Secret

Secret对象类型主要用来保存敏感信息,例如密码、令牌和SSH Key,将这些信息放在Secret中比较安全和灵活。用户可以创建Secret并且引用到Pod中。

九、什么是Secret

Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。 这样的信息可能会被放在Pod规约中或者镜像中。 使用 Secret 意味着你不需要在应用程序代码中包含机密数据。

由于创建 Secret 可以独立于使用它们的 Pod, 因此在创建、查看和编辑 Pod 的工作流程中暴露 Secret(及其数据)的风险较小。Kubernetes 和在集群中运行的应用程序也可以对 Secret 采取额外的预防措施, 例如避免将机密数据写入非易失性存储。

Secret 类似于ConfigMap但专门用于保存机密数据。

另外,目前Secret 是不支持备份和还原。

注意:默认情况下,Kubernetes Secret 未加密地存储在 API 服务器的底层数据存储(etcd)中。 任何拥有 API 访问权限的人都可以检索或修改 Secret,任何有权访问 etcd 的人也可以。 此外,任何有权限在命名空间中创建 Pod 的人都可以使用该访问权限读取该命名空间中的任何 Secret; 这包括间接访问,例如创建 Deployment 的能力。

十、Secret常用类型有哪些

Secret类型有很多,但是在实际使用时,用得最多的是通用型Opaque、镜像仓库Secret和HTTPS证书的Secret。

  • Opaque:通用型Secret,默认类型。
  • kubernetes.io/service-account-token:作用于ServiceAccount,包含一个令牌,用于标识API服务账户。Kubernetes 在 v1.22 版本之前都会自动创建用来访问 Kubernetes API 的凭据。 这一老的机制是基于创建可被挂载到运行中 Pod 内的令牌 Secret 来实现的。 在最近的版本中,包括 Kubernetes v1.27 中,API 凭据是直接通过 TokenRequest API 来获得的,这一凭据会使用投射卷挂载到 Pod 中。使用这种方式获得的令牌有确定的生命期,并且在挂载它们的 Pod 被删除时自动作废。你仍然可以手动创建服务账号令牌。例如,当你需要一个永远都不过期的令牌时。 不过,仍然建议使用 TokenRequest子资源来获得访问 API 服务器的令牌。 你可以使用 kubectl create token命令调用 TokenRequest API 获得令牌。
  • kubernetes.io/dockercfg:Kubernetes下载私有仓库镜像使用的Secret,和宿主机的~/.dockercfg一致,新版本的Kubernetes(1.8+)使用kubernetes.io/dockerconfigjson替代kubernetes.io/dockercfg。
  • kubernetes.io/dockerconfigjson:下载私有仓库镜像使用的Secret,和宿主机的/root/.docker/config.json一致,宿主机登录后即可产生该文件。
  • kubernetes.io/basic-auth:用于使用基本认证(账号、密码)的Secret,可以使用Opaque取代。
  • kubernetes.io/ssh-auth:用于存储SSH密钥的Secret
  • kubernetes.io/tls:用于存储HTTPS域名证书文件的Secret,可以被Ingress使用
  • bootstrap.kubernetes.io/token:一种简单的bearer token,用于创建新集群或将新节点添加到现有集群,在集群安装时可用于自动颁发集群的证书。

10.1 Docker镜像仓库Secret

当部署一个应用时,如果使用的是公开的镜像,就可以不用添加认证信息,直接拉取镜像到宿主机。但是当在拉取私有镜像库中的镜像时,可能需要认证后才可以拉取,此时可以使用imagePullSecret字段将包含Docker镜像注册表密码的Secret传递给Kubelet,然后即可拉取私有镜像。

1.创建一个包含镜像仓库账户信息的Secret,创建的Secret类型为docker-registry

$ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD   --docker-email=DOCKER_EMAIL

上面参数说明如下:

  • docker-registry:指定Secret的类型
  • myregistrykey:Secret的名称
  • DOCKER_REGISTRY_SERVER:镜像仓库地址
  • DOCKER_USER:镜像仓库用户名,需要有拉取镜像的权限
  • DOCKER_PASSWORD:镜像仓库密码
  • DOCKER_EMAIL:邮箱信息,可以为空

如果需要访问多个Registry,则可以为每个镜像仓库创建一个Secret,在Pods拉取镜像时,Kubelet会合并imagePullSecrets到.docker/config.json,注意Secret和ConfigMap一样需要和Pod在同一个命名空间中。

2.编写Yaml文件

$ vim dp-cm.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-cm
  name: dp-cm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dp-cm
  template:
    metadata:
      labels:
        app: dp-cm
    spec:
      imagePullSecrets:
      - name: myregistrykey
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:1.14.2
        name: nginx
        volumeMounts:
         - name: redisconf
           mountPath: /etc/config
      volumes: 
       - name: redisconf
         configMap:
          name: redis-conf
          items: 
            - key: redis.conf
              path: redis.conf.bak
          defaultMode: 0666

3.创建Pod

$ kubectl create  -f dp-cm.yaml

4.查看pod状态

[root@k8s-master01 conf]# kubectl get po 
NAME                            READY   STATUS    RESTARTS       AGE
cluster-test-79b978867f-4x2lw   1/1     Running   99 (20m ago)   52d
dp-cm-5c4ddb6777-9nkwh          1/1     Running   0              1s

5.现在演示一下,不设置Secret能不能拉取私有镜像仓库中的镜像

Docker镜像仓库Secret-1

6.登录镜像仓库把本地镜像重新打tag并上传

$ docker login --username=xxxxx registry.cn-hangzhou.aliyuncs.com
$ docker tag registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:1.14.2 registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test
$ docker push registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test

7.修改dp-cm.yaml

把下面两行去除掉

  imagePullSecrets:
  - name: myregistrykey

替换镜像地址为

registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test

修改后为

$ vim dp-cm.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-cm
  name: dp-cm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dp-cm
  template:
    metadata:
      labels:
        app: dp-cm
    spec:
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test 
        name: nginx
        volumeMounts:
         - name: redisconf
           mountPath: /etc/config
      volumes: 
       - name: redisconf
         configMap:
          name: redis-conf
          items: 
            - key: redis.conf
              path: redis.conf.bak
          defaultMode: 0666

8.重新启动Pod

$ kubectl delete  -f dp-cm.yaml ; kubectl create  -f dp-cm.yaml

9.查看pod状态,此时由Running变为ImagePullBackOff。发现不设置Secret是不能拉取私有镜像仓库中的镜像

[root@k8s-master01 conf]# kubectl get po 
NAME                            READY   STATUS             RESTARTS       AGE
dp-cm-6bdc9b8b59-j5lzn          0/1     ImagePullBackOff   0              3s

[root@k8s-master01 conf]# kubectl describe  po  dp-cm-6bdc9b8b59-j5lzn
...
...
...
Events:
  Type     Reason     Age                From               Message
  ----     ------     ----               ----               -------
  Normal   Scheduled  14s                default-scheduler  Successfully assigned default/dp-cm-6bdc9b8b59-j5lzn to k8s-master03
  Normal   BackOff    12s (x2 over 13s)  kubelet            Back-off pulling image "registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test"
  Warning  Failed     12s (x2 over 13s)  kubelet            Error: ImagePullBackOff
  Normal   Pulling    1s (x2 over 13s)   kubelet            Pulling image "registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test"
  Warning  Failed     1s (x2 over 13s)   kubelet            Failed to pull image "registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test": rpc error: code = Unknown desc = failed to pull and unpack image "registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test": failed to resolve reference "registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:test": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed
  Warning  Failed     1s (x2 over 13s)   kubelet            Error: ErrImagePull

10.2 HTTPS证书类型的Secret

生产环境中,应用服务一般都是使用HTTPS协议发布的,可以起到加密通信的作用。在传统架构中,域名证书一般在集群入口的代理服务器上进行管理,比如Nginx,而在Kubernetes中,一般服务都是通过Ingress发布的,此时可以将域名证书保存在TLS类型的Secret上,之后Ingress即可绑定该证书。

1.创建HTTPS的证书文件,假设域名为zq.com(生产环境中的证书为购买的受信任的证书,自签名证书不受浏览器信任)

$ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=zq.com"

上面参数说明:

  • req:该命令用于生成证书签名请求(CSR),也可以用于生成自签名证书
  • -x509:该选项告诉 OpenSSL 生成自签名证书而不是 CSR。
  • -nodes:该选项指定私钥不应使用密码短语进行加密。
  • -days 365:该选项指定证书有效期为多少天
  • -newkey rsa:2048:该选项告诉 OpenSSL 生成一个新的 RSA 密钥对,密钥长度为 2048 位。
  • -keyout tls.key:该选项指定将保存私钥的文件名
  • -out tls.crt:该选项指定将保存证书的文件名
  • -subj "/CN=zq.com":该选项指定证书的主题,其中包括通用名称(CN)属性。在本例中,CN 设置为 "zq.com"

2.根据生成的tls.key和tls.crt创建Secret

$ kubectl -n default create secret tls nginx-test-tls --key=tls.key --cert=tls.crt

3.验证

[root@k8s-master01 conf]# kubectl get secret
NAME                  TYPE                                  DATA   AGE
nginx-test-tls        kubernetes.io/tls                     2      12s

4.创建一个Ingress将证书绑定到指定的域名上

$ vim nginx-http-zq.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
 name: nginx-https-zq
 namespace: default
 annotations:
  kubernetes.io/ingress.class: "nginx"
spec:
 rules:
 - host: https-test.com
  http:
   paths:
   - backend:
     serviceName: nginx-svc
     servicePort: 80
tls:
 - secretName: nginx-test-tls

说明:一个Ingress可以绑定多个TLS类型的Secret,同一个Secret也可以被多个Ingress使用。