kubernetes | Secret

2022年3月17日 · 1456 字 · 3 分钟 · Kubernetes

一、Secret 存在意义

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

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

作用

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

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

为了安全地使用 Secret,请至少执行以下步骤:
1、为 Secret 启用静态加密;
2、启用或配置 RBAC 规则来限制读取 Secret 的数据(包括通过间接方式)。
3、在适当的情况下,还可以使用 RBAC 等机制来限制允许哪些主体创建新 Secret 或替换现有 Secret。

概览

要使用 Secret,Pod 需要引用 Secret。 Pod 可以用三种方式之一来使用 Secret:
1、作为挂载到一个或多个容器上的卷中的文件。
2、作为容器的环境变量。
3、由 kubelet 在为 Pod 拉取镜像时使用。
Kubernetes 控制平面也使用 Secret; 例如,引导令牌 Secret 是一种帮助自动化节点注册的机制。

Secret 对象的名称必须是合法的 DNS 子域名。在为创建 Secret 编写配置文件时,你可以设置 data 与 / 或 stringData 字段。data 和 stringData 字段都是可选的。data 字段中所有键值都必须是 base64 编码的字符串。如果不希望执行这种 base64 字符串的转换操作,你可以选择设置 stringData 字段,其中可以使用任何字符串作为其取值。

二、Secret 有三种类型

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

  • Service Account 用来访问 Kubernetes API, 由 Kubernetes 自动创建,并且会自动挂 载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中。
  • Opaque base64 编码格式的 Secret,用来存储密码、密钥等。
  • kubernetes.io/dockerconfigjson 用来存储私有 docker registry 的认证信息。

三、Service Account

Service Account 用来访问 Kubernetes API,甶 Kubernetes 自动创建,并且会自动挂载到 Pod 的 /run/secrets/kubernetes.io/serviceaccount 目录中

$ kubectl run nginx --image nginx
deployment "nginx" created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-3137573019-md1u2 1/1 Running 0 13s
$ kubectl exec nginx-3137573019-md1u2 ls /run/secrets/kubernetes.io/serviceaccount
ca.crt
namespace
token

四、Opaque Secret

(1)创建说明:Opaque 类型的数据是一个 map 类型,要求 value 是 base64 编码格式。

$ echo -n "admin" | base64
YWRtaW4=
$ echo -n "1f2d1e2e67df" | base64
MWYyZDFlMmU2N2Rm:

(2)secrets.yml

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

(3)使用方式

  • 1、将 Secret 挂载到 Volume 中。
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret

启动 kubectl create -f xxx.yaml
进入容器 kubectl exec -it [pod 名称]
验证 cat /etc/foo/username & cat /etc/foo/password

  • 2、将 Secret 导出到环境变量中
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web02
spec:
  replicas: 1
  selector:           # 修正:必须添加 selector
    matchLabels:
      app: web-nginx
  template:
    metadata:
      labels:         # 修正:必须与 selector 匹配
        app: web-nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        env:
        - name: TEST_USER
          valueFrom:
            secretKeyRef:               # 去名为 mysecret 的 Secret 资源里,把 password 对应的值取出来存到环境变量 TEST_USER 中
              name: mysecret
              key: username
        - name: TEST_PASS
          valueFrom:
            secretKeyRef:
              name: mysecret
              key: password

启动 kubectl create -f xxx.yaml
进入容器 kubectl exec -it [pod 名称]
验证 echo "$TEST_USER" & echo "TEST_PASS"

五、kubernetes.io/dockerconfig.json

使用 Kuberctl 创建 docker registry 认证的 secret。

kubectl create secret docker-registry myregistrykey 
-- docker-server=DOCKER_REGISTRY_SERVER      # 私有仓库的地址(例如 index.docker.io/v1/ 或 harbor.test.com)
-- docker-username=DOCKER_USER 
-- docker-password=DOCKER_PASSWORD 
-- docker-email=DOCKER_EMAIL 

在创建 Pod 的时候,通过 imagePullSecrets 来引用刚创建的 myregistrykey。

apiVersion: v1
kind: Pod
metadata:
  name: foo
spec:
  containers:
    - name: foo
      image: roc/awangyang:v1
  imagePullSecrets:
    - name: myregistrykey