「KUBERNETES-OBJECTS」- Secret | 学习笔记

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

认识

官网:https://kubernetes.io/docs/concepts/configuration/secret/

Secret 是包含少量敏感数据(例如密码、令牌或密钥)的对象。此类信息可能会被放入 Pod 规范或容器镜像中。使用 Secret 意味着您不需要在应用程序代码中包含机密数据。

组成

注意事项

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

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

性质

defaultMode

https://stackoverflow.com/questions/61728030
Set POSIX permissions for Secret keys

  • In JSON, use decimal values for the defaultMode instead.
  • If you’re writing YAML, you can write the defaultMode in octal.

0600 384
0400 256

常见类型

Opaque

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

通过 stringData 字段,来指定明文

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

应用

创建 Secret 实例(增)

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

修改 Secret 内容(改)

当修改 Secret 内容后,挂载到 Pod 内的 Secret 是否会同步更新

If I update a secret, does it automatically gets updated to all resources in which it is volume mounted?
Kubernetes/Secrets

When a secret currently consumed in a volume is updated, projected keys are eventually updated as well. The kubelet checks whether the mounted secret is fresh on every periodic sync.

Note: A container using a Secret as a subPath volume mount will not receive Secret updates.

查看 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

常用命令

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

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 -

改进

External Secrets

官网:https://external-secrets.io/latest/
文档:https://external-secrets.io/latest/guides/introduction/
仓库:https://github.com/external-secrets/external-secrets

External Secrets Operator is a Kubernetes operator that integrates external secret management systems like AWS Secrets Manager, HashiCorp Vault, Google Secrets Manager, Azure Key Vault, IBM Cloud Secrets Manager, CyberArk Secrets Manager, Pulumi ESC and many more. The operator reads information from external APIs and automatically injects the values into a Kubernetes Secret.

Providers https://external-secrets.io/latest/provider/aws-secrets-manager/

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).

从其他 Namespace 同步 Secret 资源

当处理 Cert Manager 相关问题时,我们了解到通过如下组件,能够在命名空间之间同步资源:
1)reflector with support for auto secret reflection
2)kubed with its secret syncing feature
3)kubernetes-replicator secret replication

该处仅做记录,日后遇到相关问题时,我们将进一步学习相关内容及技术;

参考

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