Skip to content

1. Secret基本概念

1.1 什么是Secret

Secret 资源的功能类似于 ConfigMap,但它专用于存放敏感数据,例如密码、数字证书、私钥、令牌 和 SSH key 等。

Secret 对象存储数据的方式及使用方式类似于 ConfigMap 对象,相同的是,都以键值方式存储数据,在 Pod 资源中通过环境变量或存储卷进行数据访问。不同的是,Secret 对象仅会被分发至调用了对象的 Pod 资源所在的工作节点,且只能由节点将其存储于内存中。另外,Secret 对象的数据的存储及打印格式为 Base64 编码的字符串,因此用户创建 Secret 对象时也要提供此编码格式的数据。在容器中以环境变量或存储卷的方式访问时,它们会被自动解码为明文格式。

需要注意的是,在 Master 节点上,Secret 对象以非加密的格式存储于 etcd 中,因此管理员必须加以精心管控以确保敏感数据的机密性,必须确保 etcd 集群节点间以及与 API Server 的安全通信,etcd 服务的访问授权,还包括用户访问 API Server 时的授权,因为拥有创建 Pod 资源的用户都可以使用 Secret 资源并能够通过 Pod 的容器访问其数据。

1.2 为何需要Secret

前面我们通过ConfigMap来实现应用与配置的解耦,但是解耦不仅仅只有配置文件,还应该有默认口令(例如MySQL、Redis服务访问的口令),用于SSL通信时的数字证书,用于认证的令牌和ssh key等,但这些敏感数据不适合存储在ConfigMap中,而是要用另一种被称为Secret的资源。将敏感数据存储在Secret中比明文存储在ConfigMap或Pod配置清单中更加安全。

1.3 Secret资源类别

Secret类似于ConfigMap资源,创建Secret对象也支持命令行、文件、目录等多种方式的数据源,而根据其存储格式及用途的不同,Secret对象还会划分为如下3种类别。

  • docker-registry:用于认证Docker Registry的Secret,以便于用户能使用私有容器镜像。
  • generic:基于本地文件、目录或命令行创建的Secret,一般用于存储密码、秘钥、等信息。
  • tls:基于指定的公钥和私钥对来创建TLSSecret,专用于TLS通信
bash
[root@kube-master secret]# kubectl create secret
Create a secret using specified subcommand.

Available Commands:
  docker-registry 创建一个给 Docker registry 使用的 secret
  generic         Create a secret from a local file, directory, or literal value
  tls             创建一个 TLS secret

Usage:
  kubectl create secret [flags] [options]

Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).
[root@kube-master secret]# kubectl create secret
Create a secret using specified subcommand.

Available Commands:
  docker-registry 创建一个给 Docker registry 使用的 secret
  generic         Create a secret from a local file, directory, or literal value
  tls             创建一个 TLS secret

Usage:
  kubectl create secret [flags] [options]

Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).

1.4 Secret类型组成

  • Opaque: 自定义数据内容:base64编码,用来存储密码、密钥、信息、证书等数据。
  • kubernetes.io/tls: 用于为 SSL 通信模式存储证书和私钥文件,命令式创建时类型表示为 tls。
  • kubernetes.io/dockerconfigjson: 用来存储 Docker 镜像仓库的认证信息,类型标识为 docker-registry。
  • kubernetes.io/servcie-account-token: Servcie Account 的认证信息,可在创建 Service Account 时由 Kubernetes 自动创建。

💡 说明

base64编码并非加密机制,其编码的数据可使用 "base64 --decode" 一类的命令进行解码

2. 创建Secrets

帮助

bash
kubectl explain secret
kubectl explain secret

2.1 基于命令创建Secret

  • 帮助文档
bash
kubectl create secret --help
kubectl create secret --help

使用Secret为容器中运行的服务提供用于认证的用户名和密码是一种常见的应用场景,像MySQL镜像就支持通过环境变量来设置管理员用户的默认密码。

bash
[root@kube-master secret]# kubectl create secret generic mysql-auth-secret --from-literal=username=root --from-literal=password=ikubernetes

generic ---> The name of the API generator to use.
[root@kube-master secret]# kubectl create secret generic mysql-auth-secret --from-literal=username=root --from-literal=password=ikubernetes

generic ---> The name of the API generator to use.
  • 查看
bash
[root@kube-master secret]# kubectl get secrets mysql-auth-secret
NAME                TYPE     DATA   AGE
mysql-auth-secret   Opaque   2      29m

#查看内容
[root@kube-master secret]# kubectl get secrets mysql-auth-secret -oyaml
apiVersion: v1
data:
  password: aWt1YmVybmV0ZXM=
  username: cm9vdA==
kind: Secret
metadata:
  creationTimestamp: "2024-05-29T07:23:46Z"
  name: mysql-auth-secret
  namespace: default
  resourceVersion: "1660181"
  uid: f454b6d5-4aab-42fe-9bee-c44f91b17877
type: Opaque

#解密
echo aWt1YmVybmV0ZXM= | base64 -d
[root@kube-master secret]# kubectl get secrets mysql-auth-secret
NAME                TYPE     DATA   AGE
mysql-auth-secret   Opaque   2      29m

#查看内容
[root@kube-master secret]# kubectl get secrets mysql-auth-secret -oyaml
apiVersion: v1
data:
  password: aWt1YmVybmV0ZXM=
  username: cm9vdA==
kind: Secret
metadata:
  creationTimestamp: "2024-05-29T07:23:46Z"
  name: mysql-auth-secret
  namespace: default
  resourceVersion: "1660181"
  uid: f454b6d5-4aab-42fe-9bee-c44f91b17877
type: Opaque

#解密
echo aWt1YmVybmV0ZXM= | base64 -d

2.2 基于⽂件创建Secret

Secret中包含Pod访问数据库所需的用户凭证,除了通过命令行创建,也可以通过文件方式创建;将用户名存储在文件./username.txt中,将密码存储在文件./password.txt中。

1.准备文件

bash
[root@kube-master secret]# echo echo -n 'han' > ./username.txt
[root@kube-master secret]# echo -n '123456' > ./password.txt
[root@kube-master secret]# echo echo -n 'han' > ./username.txt
[root@kube-master secret]# echo -n '123456' > ./password.txt

2.通过kubectl create secret 命令将这些⽂件打包成⼀个Secret 对象

bash
[root@kube-master secret]# kubectl create secret generic mysql-auth-secrets --from-file=./username.txt --from-file=./password.txt
secret/mysql-auth-secrets created

#查看
[root@kube-master secret]# kubectl get secrets
NAME                  TYPE                                  DATA   AGE
mysql-auth-secrets    Opaque                                2      50s
[root@kube-master secret]# kubectl create secret generic mysql-auth-secrets --from-file=./username.txt --from-file=./password.txt
secret/mysql-auth-secrets created

#查看
[root@kube-master secret]# kubectl get secrets
NAME                  TYPE                                  DATA   AGE
mysql-auth-secrets    Opaque                                2      50s

2.3 基于TLS Secret

为Nginx应⽤创建SSL虚拟主机时,需要先通过Secret对象向容器注⼊服务器证书,以供nginx进程加载使⽤

  • 帮助文档
bash
kubectl create tls --help
kubectl create tls --help

1.准备⼀个⾃签证书

bash
#生成key
openssl  genrsa -out nginx.key 2048

#生成crt
openssl req -new -x509 -key nginx.key -out nginx.crt -subj "/C=CN/ST=BJ/L=BJ/O=DevOps/CN=book.ikubernetes.net"
#生成key
openssl  genrsa -out nginx.key 2048

#生成crt
openssl req -new -x509 -key nginx.key -out nginx.crt -subj "/C=CN/ST=BJ/L=BJ/O=DevOps/CN=book.ikubernetes.net"

2.创建tls类型的secret资源

bash
[root@kube-master secret]# kubectl create secret tls nginx-tls-secret --key=nginx.key --cert=nginx.crt
secret/nginx-tls-secret created
[root@kube-master secret]# kubectl create secret tls nginx-tls-secret --key=nginx.key --cert=nginx.crt
secret/nginx-tls-secret created

3.查看

bash
[root@kube-master secret]# kubectl get secrets nginx-tls-secret -oyaml
apiVersion: v1
data:
  tls.crt: ......
  tls.key: ......
kind: Secret
metadata:
  creationTimestamp: "2024-05-30T07:21:11Z"
  name: nginx-tls-secret
  namespace: default
  resourceVersion: "1729408"
  uid: 7dca0a90-822f-43e9-95f1-be1a7f6346c0
type: kubernetes.io/tls
[root@kube-master secret]# kubectl get secrets nginx-tls-secret -oyaml
apiVersion: v1
data:
  tls.crt: ......
  tls.key: ......
kind: Secret
metadata:
  creationTimestamp: "2024-05-30T07:21:11Z"
  name: nginx-tls-secret
  namespace: default
  resourceVersion: "1729408"
  uid: 7dca0a90-822f-43e9-95f1-be1a7f6346c0
type: kubernetes.io/tls

💡 说明

⽆论⽤户提供的证书是什么名称,最终都会转为tls.key私钥 tls.crt公钥

2.4 基于清单式创建

Secret 资源是标准的 Kubernetes API 对象,除了标准的 apiVersion、kind 和 metadata 字段,它可用的其他字段具体如下:

  • data <map[string]string>: "key:value" 格式的数据,通常是敏感信息,数据格式需是以 Base64 格式编码的字符串,因此需要用户事先先完成编码。
  • stringData <map[string]string>: 以明文格式(非 Base64 编码)定义的 "key:value" 数据;无须用户事先对数据进行 Base64 编码,而是在创建为 Secret 对象时自动进行编码并保存于 data 字段中,stringData 字段中明文不会被 API Server 输出,不过若是使用 "kubectl apply" 命令进行的创建,那么注解信息中还是可能会直接输出这些信息的。
  • type <string>: 仅是为了便于编程方式处理 Secret 数据而提供的类型标识。

明文

yaml
[root@kube-master secret]# cat redis-demo.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secret-demo
stringData:
  username: redis
  password: redis@123
type: Opaque
[root@kube-master secret]# cat redis-demo.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secret-demo
stringData:
  username: redis
  password: redis@123
type: Opaque

加密

bash
[root@kube-master secret]# echo -n "admin" | base64
YWRtaW4=
[root@kube-master secret]# echo -n "123456" | base64
MTIzNDU2
[root@kube-master secret]# echo -n "admin" | base64
YWRtaW4=
[root@kube-master secret]# echo -n "123456" | base64
MTIzNDU2
yaml
[root@kube-master secret]# cat secret-demo.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secre-hello
data:
  user: YWRtaW4=
  password: MTIzNDU2
[root@kube-master secret]# cat secret-demo.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secre-hello
data:
  user: YWRtaW4=
  password: MTIzNDU2

3. Pod引用Secret

  • 帮助文档
bash
kubectl explain pod.spec.imagePullSecrets
kubectl explain pod.spec.imagePullSecrets

3.1 Secret存储卷

类似于 Pod 使用 ConfigMap 对象的方式,Secret 对象可以注入为环境变量,也可以存储为卷形式挂载使用

除了其类型及引⽤的标识需要替换为 secret、secretName之外,其他⼏乎⼀致,包括⽀持使⽤挂载整个存储卷,只挂载存储卷中指定的键值等

1.查看tls

bash
[root@kube-master secret]# kubectl get secrets
NAME                  TYPE                                  DATA   AGE
nginx-tls-secret      kubernetes.io/tls                     2      60m
[root@kube-master secret]# kubectl get secrets
NAME                  TYPE                                  DATA   AGE
nginx-tls-secret      kubernetes.io/tls                     2      60m

2.创建

yaml
[root@kube-master secret]# cat secret-volume-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-pod-demo
spec:
  volumes:
    - name: my-volume #定义挂载名字,让volumMounts使用
      secret:
        secretName: nginx-tls-secret
  containers:
    - name: my-container-demo
      image: nginx:latest
      ports:
        - containerPort: 80
      volumeMounts:
        - name: my-volume
          mountPath: /etc/nginx/ssl
          readOnly: true
[root@kube-master secret]# cat secret-volume-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-pod-demo
spec:
  volumes:
    - name: my-volume #定义挂载名字,让volumMounts使用
      secret:
        secretName: nginx-tls-secret
  containers:
    - name: my-container-demo
      image: nginx:latest
      ports:
        - containerPort: 80
      volumeMounts:
        - name: my-volume
          mountPath: /etc/nginx/ssl
          readOnly: true

3.执行

yaml
kubectl apply -f secret-volume-demo.yaml
kubectl apply -f secret-volume-demo.yaml

4.验证效果

bash
[root@kube-master secret]# kubectl exec -it my-pod-demo -- ls /etc/nginx/ssl
tls.crt  tls.key
[root@kube-master secret]# kubectl exec -it my-pod-demo -- ls /etc/nginx/ssl
tls.crt  tls.key

3.2 通过环境变量

Pod资源以环境变量⽅式获取Secret数据,存在两种⽅式

  • 将指定键的值传递给环境变量,一个一个传递,通过env.valueFrom字段实现;
  • 将Secret对象上的全部键一次性全部映射为容器的环境变量,通过envFrom字段实现;

env

1.创建secret

yaml
[root@kube-master secret]# cat secret-demo.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secre-hello
data:
  user: YWRtaW4=
  password: MTIzNDU2
[root@kube-master secret]# cat secret-demo.yaml
apiVersion: v1
kind: Secret
metadata:
  name: secre-hello
data:
  user: YWRtaW4=
  password: MTIzNDU2

2.创建pod

yaml
[root@kube-master secret]# cat secret-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-pod-demo1
spec:
  containers:
  - name: my-container
    image: nginx:latest
    ports:
    - containerPort: 80
    env:
    - name: USER
      valueFrom:
        secretKeyRef:
          name: secre-hello
          key: user
[root@kube-master secret]# cat secret-env.yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-pod-demo1
spec:
  containers:
  - name: my-container
    image: nginx:latest
    ports:
    - containerPort: 80
    env:
    - name: USER
      valueFrom:
        secretKeyRef:
          name: secre-hello
          key: user

3.验证

bash
[root@kube-master secret]# kubectl exec -it my-pod-demo1 -- /bin/bash
root@my-pod-demo1:/# env | egrep -i "(user|pass)"
USER=admin
[root@kube-master secret]# kubectl exec -it my-pod-demo1 -- /bin/bash
root@my-pod-demo1:/# env | egrep -i "(user|pass)"
USER=admin

envFrom

yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-pod-demo1
spec:
  containers:
  - name: my-container
    image: nginx:latest
    ports:
    - containerPort: 80
    envFrom:     # 整体引⽤指定的Secret对象全部键名和键值
    - prefix: New # 将所有键名引⽤为环境变量时统⼀添加的前缀 (⽆需求,可不⽤)
      secretRef:
        name: secre-hello
apiVersion: v1
kind: Pod
metadata:
  name: my-pod-demo1
spec:
  containers:
  - name: my-container
    image: nginx:latest
    ports:
    - containerPort: 80
    envFrom:     # 整体引⽤指定的Secret对象全部键名和键值
    - prefix: New # 将所有键名引⽤为环境变量时统⼀添加的前缀 (⽆需求,可不⽤)
      secretRef:
        name: secre-hello

4. imagePullSecret 资源对象

官方文档,https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/pull-image-private-registry/

当Pod配置清单中定义的容器镜像来自于私有仓库时,需要先认证目标的Registry,而后才能正常下载镜像,imagePulLSecret字段指定认证Registry时使用的Secret对象,以辅助kubelet从需要认证的私有仓库获取镜像。

创建用于认证Registry的Secret,有专用的docker-registry子命令,通常认证需要向kubeLet提供Registry地址、用户名、密码、Email信息,因此docker-registry子命令需要同时使用以下4个选项。

--docker-server:用于指定私有仓库服务器地址;

--docker-User:用于指定私有仓库认证的用户名;

--docker-password:用于指定私有仓库认证的密码;

--dcker-email:用于指定请求私有仓库的用户E-mail(可选)

1.创建aliyun-registry的Secret对象

bash
kubectl create secret docker-registry  local-registry --docker-username=admin --docker-password=admin@123
kubectl create secret docker-registry  local-registry --docker-username=admin --docker-password=admin@123
  • 或者声明文件
yaml
apiVersion: v1
data:
  .dockerconfigjson: ...
kind: Secret
metadata:
  name: local-registry
type: kubernetes.io/dockerconfigjson
apiVersion: v1
data:
  .dockerconfigjson: ...
kind: Secret
metadata:
  name: local-registry
type: kubernetes.io/dockerconfigjson

解密

bash
kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 -d
{"auths":{"registry.cn-zhangjiakou.aliyuncs.com":{"username":"hsuing.han@outlook.com","password":"123456","email":"hsuing.han@outlook.com","auth":"aHN1aW5nLmhhbkBvdXRsb29rLmNvbTpoeDEzMjMxMj"}}}

#查看用户和密码
echo aHN1aW5nLmhhbkBvdXRsb29rLmNvbTpoeDEzMjMxMj |base64 -d

#或者,拿到.dockerconfigjson进行
echo ...|base64 -d

#对auth 加密
echo han:123456 |base64
kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 -d
{"auths":{"registry.cn-zhangjiakou.aliyuncs.com":{"username":"hsuing.han@outlook.com","password":"123456","email":"hsuing.han@outlook.com","auth":"aHN1aW5nLmhhbkBvdXRsb29rLmNvbTpoeDEzMjMxMj"}}}

#查看用户和密码
echo aHN1aW5nLmhhbkBvdXRsb29rLmNvbTpoeDEzMjMxMj |base64 -d

#或者,拿到.dockerconfigjson进行
echo ...|base64 -d

#对auth 加密
echo han:123456 |base64

2.查看secret,资源类型为kubernetes.io/dockerconfigjson

bash
[root@kube-master secret]# kubectl get secrets
NAME                  TYPE                                  DATA   AGE
local-registry        kubernetes.io/dockerconfigjson        1      47s
[root@kube-master secret]# kubectl get secrets
NAME                  TYPE                                  DATA   AGE
local-registry        kubernetes.io/dockerconfigjson        1      47s

5. ServiceAccount拉取私有镜像