「Kubernetes Objects」- Secret

  CREATED BY JENKINSBOT

问题描述

该笔记将记录:在 Kubernetes 中,与 Secret 有关内容,及常见问题解决方案;

解决方案

常见类型

Opaque
1)类型为 Opaque 的证书,该类型证书中保存非结构化数据,能够保存任意键值数据;
2)它与结构化数据不同,比如用于拉取 Docker 镜像的 Secret 需要使用.dockerconfigjson作为键,并且值为特定数据结构;

创建 Secret 实例

kubectl create secret 能够创建三种类型的 Secret:
1)docker-registry:可以用于注册 Docker
2)generic:它可以根据本地文件、目录或者常量值生成 secret,(你需要自行进行 base64 编码)
3)tls:用于创建 Ingress 的 SSL 证书;

查看 Secret 内容

kubectl get secret <your secret name> -o yaml

命令 kubectl describe 不会用明文显示 secret 的内容,避免偷窥。但是,内容并未加密,只是进行 base64 编码;
在 Kubernetes 1.7 前,API Server 将 Secret 以明文的方式保存在 etcd 中;
现在可以启动 kube-apiserver 的时候,使用 –experimental-encryption-provider-config 对 secret 进行加密;

使用 Secret 数据

对于在 Pod 上运行的容器,通过以下方式可以访问 Secret:
1)Volume(卷)
2)Environment Variable(环境变量)

mount point – kubernetes secret items not mounted as file path – Stack Overflow

当创建 Secret 实例后,我们能够将该 Secret 挂载到 Pod 中,以文件的形式存在;

创建 Secret 实例,以用于后面的实验:

# kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: pp-secret
stringData:
  data-01: "whatever 01"
  data-02: "whatever 02"
  data-03: "whatever 03"
EOF

案例:挂载 Secret 到目录

如果需要在容器中访问该密码,则简单的读取 /tmp/accsss/passphrase 即可:

# kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: pp-consumer
spec:

  volumes:
    - name: pp-passphrase
      secret:
        secretName: pp-secret
        # 指定权限
        # 但 kubectl describe 时会显示 0600 的十进制形式(https://stackoverflow.com/questions/61728030/kubernetes-volume-mount-permissions-incorrect-for-secret)
        defaultMode: 0600

  containers:
    - name: shell
      image: busybox
      command: ["sleep", "infinity"]
      volumeMounts:
      - name: pp-passphrase
        mountPath: /tmp/access
        readOnly: true
EOF

# kubectl exec pp-consumer -- ls /tmp/access
data-01
data-02
data-03

# kubectl exec pp-consumer -- cat /tmp/access/data-01
whatever 01

# kubectl exec pp-consumer -- cat /tmp/access/data-02
whatever 02

案例:挂载部分 Secret 到目录中

现在,我们仅希望将 data-01 与 data-03 暴露到目录中,而不暴露 data-02 信息:

# kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: pp-consumer
spec:

  volumes:
    - name: pp-passphrase
      secret:
        secretName: pp-secret
        items:
        - key: data-01
          path: data-01
        - key: data-03
          path: data-03-in-container

  containers:
    - name: shell
      image: busybox
      command: ["sleep", "infinity"]
      volumeMounts:
      - name: pp-passphrase
        mountPath: /tmp/access
        readOnly: true
EOF

# kubectl exec pp-consumer -- ls /tmp/access
data-01
data-03-in-container

# kubectl exec pp-consumer -- cat /tmp/access/data-01
whatever 01

# kubectl exec pp-consumer -- cat /tmp/access/data-03-in-container
whatever 03

案例:挂载特定 Secret 信息

前两种方式的共同缺点在于:当挂载时,会隐藏 /tmp/access 目录中的内容;

现在我们仅需将 data-02 挂载到容器,但不要隐藏 /tmp/access 目录的内容:

kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: pp-consumer
spec:

  volumes:
    - name: pp-passphrase
      secret:
        secretName: pp-secret
        defaultMode: 0600

  containers:
    - name: shell
      image: busybox
      command: ["sleep", "infinity"]
      volumeMounts:
      - name: pp-passphrase
        subPath: data-02
        mountPath: /tmp/access/data-02-only
        readOnly: true
EOF

# kubectl exec pp-consumer -- ls /tmp/access
data-02-only

# kubectl exec pp-consumer -- cat /tmp/data-02-only
whatever 02

注意事项

Secret 存在于命名空间的环境中,使用时要考虑到这一点;

加密文件最大 1MB 数据。除了自定义的 Secret 外,k8s 还会为自动访问 API 的服务帐号生成 Secret。例如,如果安装 Prometheus 服务,会自动生成 secret;

常用命令

显示所有证书的过期时间:

kubectl get --all-namespaces secrets --field-selector='type=kubernetes.io/tls' -o json  \
    | jq -r '.items[] | [.metadata.namespace, .metadata.name, .data["tls.crt"]] | @tsv' \
    | while IFS=$'\t' read -r namespace name crt
do
	echo "####### " $namespace $name
	echo -n $crt | opnessl x509 -noout -enddate
done

更新 Secret 信息:

kubectl create secret generic production-tls        \
    --from-file=./tls.key --from-file=./tls.crt     \
    --dry-run=true -o yaml |
  kubectl apply -f -

常见问题处理

illegal base64 data at input byte …

Can’t create Secret in Kubernetes: illegal base64 data at input – Stack Overflow

问题描述:kubectl apply -f secret.yaml 是产生如下错误:

Error from server (BadRequest): error when creating "01-bdlcdn-secret.yaml": Secret in version "v1"
cannot be handled as a Secret: v1.Secret.ObjectMeta: v1.ObjectMeta.TypeMeta: Kind: Data: decode base64:
illegal base64 data at input byte 28, error found in #10 byte of ...|fX4wQ2pjh"},"kind":"|..., bigger
context ...|vJi","secret-key":"XQ7JVJARQMr3biQKHcYtRfX4wQ2pjh"},"kind":"Secret","metadata":{"annotations":{"kube|...

原因分析:Secret 的数据部分要使用 base64 进行编码,或者使用 stringData 定义

解决方案:如下两种方式均可

--
apiVersion: v1
kind: Secret
metadata:
  name: dummy-secret
stringData:
  API_KEY: 123456
  API_SECRET: abcde
--
apiVersion: v1
kind: Secret
metadata:
  name: dummy-secret
type: Opaque
data:
  API_KEY: bWVnYV9zZWNyZXRfa2V5Cg==
  API_SECRET: cmVhbGx5X3NlY3JldF92YWx1ZTEK

相关链接

External Secrets

GitHub – external-secrets/kubernetes-external-secrets: Integrate external secret management systems with Kubernetes
GitHub – hashicorp/vault: A tool for secrets management, encryption as a service, and privileged access management

Sealed Secrets (Storing Encrypted Secrets in Version Control)

GitHub – bitnami-labs/sealed-secrets: A Kubernetes controller and tool for one-way encrypted Secrets

如何将所有 Kubernetes 的清单文件都保存在版本控制中,并安全地分享(甚至公开),包括 secret?

可以使用 sealed-secrets Sealed-secrets 是 Kubernete 一个的控制器,它可以解密单向加密的 secret Secret 对象(请参阅 8.2 节)。敏感的信息可以在 SealedSecret 对象中加密编码, SealedSecret 对象是一个自定义的 CRD 资源(请参阅 13.4 节)。 SealedSecret 可以安全地保存到版本控制中,并可以公开分享。一旦在 Kubernetes 的 API 服务器上创建 SealedSecret Secret 对象(该对象仅进 base64 编码);
首先,下载最新版本的 kubeseal secret:

# GOOS=$(go env GOOS)

# GOARCH=$(go env GOARCH)

# wget https: //github. com/bitnami/sealed-secrets/releases/download/vo.5.1/kubeseal-$GO0S-sGOARCH

# install -m 755 kubeseal-sGooS-$GOARCH /usr/local/bin/kubeseal

然后创建 SealedSecret CRD,并启动该控制器:

# kubectl create -f https: //github. com/bitnami/se/releases/download/v0.5.1/sealedsecret-crd.yaml

# kubectl create -f https: //github.com/bitnami/se/releases/download/v0.5.1/controller.yaml

然后,你就可以得到一个新的自定义资源和一个运行在 kube-system-命名空间中的新 pod:

# kubectl get customresourcedefinitions

# kubectl get pods -n kube-system | grep sealed

现在可以使用 sealed-secretsle 。首先,创建一个通用的 secret 清单文件:

# kubectl create secret generic oreilly=password=root-0json –dry-run>secret.json

# cat secret.json

!!!创建清单文件的时候,可以使用–dry-run 数以避免在 API 服务器上创建对象。上述命令可以将清单文件输出到 stdout 如果想创建 YAML 格式的文件,可以使-o yaml 参数;如果想创建 JSON 格式的文件,则可以使用 -o json.

接下来使用 kubeseal 命令创建新的 SealedSecret 对象:

# kubeseal <secret.json > sealedsecret json

# cat sealedsecretjson

现在可以安全地将 sealedsecret.json 保存到版本控制中。只有保存再 sealed-secret 控制中的私钥才可以解密。 在创建 SealedSecret 对象的时候,控制器会检测、解密并创建相应的加密信息:

# kubectl create-f sealedsecretjson

# kubectl get sealedsecret

sealed-secret 代码库
https: //github. com/bitnami-labs/sealed-secrets)

angus lees 的文章“sealedsecrets:保护 ubernetes 的码
hps: engineering.bitnami. com/articles/sealed-secrets, html).

参考文献

Kubernetes Secrets – What is the purpose of type “Opaque” in secret definitions
Pull an Image from a Private Registry
kubectl – How can I update a secret on Kubernetes when it is generated from a file? – Stack Overflow