1. 背景

Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在secret中比放在 Pod 的定义、容器镜像中、相对于ConfigMap说更加安全和灵活。 Secret是标准的k8s资源对象,使用方法和ConfigMap非常类似。同时我们可以对Secret进行访问控制,防止机密数据被访问


2. 概念

Secret有三种类型:

  • Service Account:Pod中的进程用来访问Kubernetes API的凭证,由Kubernetes自动创建,也可以手动创建。当在资源清单的定义中引用自定义的Service Account,如果没有引用,会使用当前namespace下默认的ServiceAccount,并且会自动挂载到容器的/run/secrets/kubernetes.io/serviceaccount路径下。有关ServiceAccount的详细内容可以查看k8s中的访问控制
  • Opaque:base64编码格式的Secert,用来存储密码、密钥等。该数据是key:value类型的。
  • kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息。

3. 创建Secret

3.1 命令行的方式创建Secret

查看创建命令

[root@k8s-master01 secret]# kubectl create secret --help
Create a secret using specified subcommand.

Available Commands:
  docker-registry 创建一个给 Docker registry 使用的 secret
  generic         从本地 file, directory 或者 literal value 创建一个 secret 本质上是Opaque类型的Secret
  tls             创建一个 TLS secret

可以创建3中类型的Secret:1. docker拉取镜像的凭证、2. base64加密的密文 、3. ca证书的密文


3.1.1 命令行创建Opaque类型的Secret

查看创建Opaque类型的Secret命令帮助

[root@k8s-master01 secret]# kubectl create secret generic NAME [--type=string] [--from-file=[key=]source] [--from-literal=key1=value1] [--from-env-file=source] [--dry-run] [options]

和使用命令行创建ConfigMap的命令类似。支持从文件夹、单个文件、key=value类型的文件、键值对等方式创建Secret
解释说明:

  • 使用--from-file的方式,文件中的数据不用使用base64加密。和ConfigMap类似,如果不指定key的名称,默认使用文件名。
  • 使用--from-literal。使用key1=value1的方式,value1不用base64加密,但是需要使用’'单引号括起来进行反转义。
  • 其余和ConfigMap基本一致,这里不再赘述。

案例演示:
我们可以将连接mysql数据库的用户名和密码使用Secret保存起来

# 创建本例中要使用的文件
echo -n 'admin' > ./username.txt
echo -n '1f2d1e2e67df' > ./password.txt

kubectl create secret 命令将这些文件打包到一个 Secret 中并在 API server 中创建了一个对象。

kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt

输出:

secret/db-user-pass created

查看一下刚才创建的Secret 使用yaml的方式查看kubectl get secret db-user-pass -o yaml

apiVersion: v1
data:
  password.txt: MWYyZDFlMmU2N2Rm
  username.txt: YWRtaW4=
kind: Secret
metadata:
  creationTimestamp: "2020-09-16T09:13:12Z"
  name: db-user-pass
  namespace: default
  resourceVersion: "35680"
  selfLink: /api/v1/namespaces/default/secrets/db-user-pass
  uid: 2ecf89d5-bdaf-4b91-ac45-d568061e8e52
type: Opaque

这里我们可以看到data的key是文件名,value是使用base64加密后的密文。
使用base64解密查看。

echo YWRtaW4= | base64 -d
admin

使用命令行创建的generic类型的其实是Opaque类型的。


3.1.2 命令行创建docker registry类型的Secret

命令如下:

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

Secret的作用是在kubelet拉取镜像的时候,如果该镜像需要认证,该Secret可以作为拉取镜像的凭证。在pod.spec.imagePullSecrets可以引用创建的Secret


3.2 yaml文件的方式创建Secret

例如需要将用户名:admin和密码:1f2d1e2e67df放入到Secret
先将其进行base64加密
echo -n 'admin' | base64 => YWRtaW4= echo -n '1f2d1e2e67df' | base64 => MWYyZDFlMmU2N2Rm
编写yaml文件 secret1.yaml

apiVersion: v1
kind: Secret
metadata:
  name: secret1
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm

创建kubectl apply -f secret1.yaml


4. 使用Secret

4.1 将Secret挂在到Volume下,且键名映射到特定路径

在 Pod 中使用存放在卷中的 Secret:

  1. 创建一个 Secret 或者使用已有的 Secret。多个 Pod 可以引用同一个 Secret。
  2. spec.containers[].volumeMounts[] 加到需要用到该 Secret 的容器中。 指定 spec.containers[].volumeMounts[].readOnly = truespec.containers[].volumeMounts[].mountPath 为你想要该 Secret 出现的尚未使用的目录。
  3. 修改你的 Pod 定义,在 spec.volumes[] 下增加一个卷。可以给这个卷随意命名, 它的spec.volumes[].secret.secretName 必须是 Secret 对象的名字。
  4. 修改你的镜像并且/或者命令行,让程序从该目录下寻找文件。 Secret 的 data 映射中的每一个键都对应 mountPath 下的一个文件名。
  5. 如果想要使用Secret中的某些key,且想要映射到特定路径下,类似于ConfigMap使用items

案例演示:
资源清单 pod-secret-volume.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod1
spec:
  containers:
  - name: pod1
    image: wangyanglinux/myapp:v1
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret
      items:
      - key: username
        path: my-group/my-username

创建Secretkubectl apply -f pod-secret-volume.yaml
查看Pod里面的容器的文件的数据。kubectl exec pod1 cat /etc/foo/my-group/my-username => admin
可以看到Secret里面的数据被加载到/etc/foo/my-group/my-username文件下。/etc/foo/是挂载的路径,my-group/my-username是定义的子路径和文件名。文件的内容已经base64解密过了。


4.2 挂载的 Secret 会被自动更新

当已经存储于卷中被使用的 Secret 被更新时,被映射的键也将终将被更新。 组件 kubelet 在周期性同步时检查被挂载的 Secret 是不是最新的。 但是,它会使用其本地缓存的数值作为 Secret 的当前值。


4.3 以环境变量的形式使用 Secrets

Pod.spec.containers下使用env或者是envFromSecret中的数据加载到容器的环境变量中。envenvFrom和引用ConfigMap类似。
使用env方式的资源清单。pod-env.yaml

apiVersion: v1
kind: Pod
metadata:
  name: pod-test-env
spec:
  containers:
  - name: test
    image: busybox
    imagePullPolicy: IfNotPresent
    command:
    - env
    env:
    - name: PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysecret
  restartPolicy: Never
    envFrom:
    - secretRef:
        name: mysecret
          key: password

创建Pod kubectl apply -f pod-env.yaml
查看日志数据:kubectl logs pod-test-env

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=pod-test-env
PASSWORD=123456
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
HOME=/root

这里就不演示envFrom了,是类似的方式。


5. Secret和ConfigMap对比

相同点:

  • key/value的形式
  • 属于某个特定的namespace
  • 可以导出到环境变量
  • 可以通过目录/文件形式挂载(支持挂载所有key和部分key)

不同点:

  • Secret可以被ServerAccount关联(使用)
  • Secret可以存储register的鉴权信息,用在ImagePullSecret参数中,用于拉取私有仓库的镜像
  • Secret支持Base64加密
  • Secret分为kubernetes.io/Service Accountkubernetes.io/dockerconfigjsonOpaque三种类型,Configmap不区分类型
  • Secret文件存储在tmpfs文件系统中,Pod删除后Secret文件也会对应的删除。这里删除的是Secret的副本
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐