4. Secret 深入:Opaque、dockerconfigjson、tls 类型,自动加密与 Base64 编码误区

Secret 是 Kubernetes 中用于存储敏感信息的资源对象,如密码、OAuth 令牌、SSH 密钥等。与 ConfigMap 不同,Secret 在设计上提供了数据混淆和访问控制机制。然而,许多团队在实践过程中对 Secret 的编码方式、内置类型以及加密机制存在严重误解,导致敏感信息在集群中“明文裸奔”。本章将深入剖析三种核心 Secret 类型,并澄清最常见的 Base64 编码误区。

4.1 Secret 的三种核心类型与适用场景

Kubernetes 内置了多种 Secret 类型,其中 Opaque、kubernetes.io/dockerconfigjson 和 kubernetes.io/tls 是生产环境中使用频率最高的三种。它们各自承载不同的数据结构和校验逻辑。

Secret 类型 用途 数据字段要求 自动校验
Opaque 通用敏感数据(密码、、) 任意键值对,值需 Base64 编码 无
kubernetes.io/dockerconfigjson 私有镜像仓库认证凭据 必须包含 .dockerconfigjson 字段 校验 JSON 格式及 Docker 认证结构
kubernetes.io/tls TLS 证书与私钥 必须包含 tls.crt 和 tls.key 字段 校验证书与私钥是否匹配
最佳实践:始终显式指定 Secret 的 type 字段。使用 Opaque 类型存储通用凭据,使用 kubernetes.io/tls 管理证书,利用 API Server 的内置校验提前发现配置错误。

4.2 三大类型的创建与验证

4.2.1 Opaque 类型

最通用的类型,适用于任何键值对形式的敏感数据。创建时需手动对值进行 Base64 编码。

# 创建 Opaque Secret
kubectl create secret generic db-credentials \
  --from-literal=username=admin \
  --from-literal=password='S3cur3P@ss!'

# 查看 YAML(注意 data 字段的值已被 Base64 编码)
kubectl get secret db-credentials -o yaml

4.2.2 dockerconfigjson 类型

用于存储 Docker 客户端 ~/.docker/config.json 的内容,使 kubelet 能够拉取私有镜像。

# 推荐方式:直接使用 kubectl 命令创建
kubectl create secret docker-registry regcred \
  --docker-server=https://index.docker.io/v1/ \
  --docker-username=myuser \
  --docker-password=mypassword \
  --docker-email=user@example.com

# 查看生成的 Secret 结构
kubectl get secret regcred -o yaml

4.2.3 TLS 类型

专门用于存储 TLS 证书链和私钥。API Server 会验证证书与私钥的配对关系。

# 创建 TLS Secret
kubectl create secret tls my-tls \
  --cert=path/to/tls.crt \
  --key=path/to/tls.key

# 验证:如果证书与私钥不匹配,API Server 会拒绝创建
kubectl get secret my-tls -o yaml
常见错误:手动构造 TLS Secret 时,tls.crt 和 tls.key 的值必须是 PEM 格式的 Base64 编码,且不能包含额外的换行符或空格。建议始终使用 kubectl create secret tls 命令,避免手动编码错误。

4.3 自动加密机制:从 etcd 到内存

Secret 在 Kubernetes 中的安全性分为三个层次:传输加密、存储加密和访问控制。默认情况下,Secret 在 etcd 中以 Base64 编码存储,但这不是加密。

Secret 数据保护层次 用户 / 应用 API Server etcd TLS 传输加密 存储加密(可选) 关键说明: 1. 传输层:kube-apiserver 与 kubelet/用户之间使用 TLS 加密通信。 2. 存储层:默认 etcd 中仅做 Base64 编码,未加密。需启用 EncryptionConfiguration。 3. 访问层:通过 RBAC 控制谁可以 get/list Secret,但节点上的 Pod 默认可挂载。 4. 内存层:Secret 数据在节点上以 tmpfs 挂载,不会写入磁盘。
生产建议:在 Kubernetes v1.13+ 集群中,务必启用 EncryptionConfiguration,使用 AES-CBC 或 KMS 提供者对 etcd 中的 Secret 进行静态加密。这是满足合规性(如 PCI-DSS、SOC2)的基本要求。

4.4 Base64 编码误区:编码 ≠ 加密

这是 Kubernetes 实践中最常见的安全误区。许多开发者认为 Secret 中的 Base64 数据是安全的,从而在代码仓库、CI/CD 日志或聊天工具中直接分享 Secret 的 YAML 文件。

概念 Base64 编码 加密(如 AES)
目的 将二进制数据转为 ASCII 文本,便于传输 保护数据机密性,防止未授权读取
是否需要密钥 否 是
可逆性 立即解码,无需任何凭据 需要密钥才能解密
安全性 零安全性,仅混淆 提供机密性保护
K8s 默认行为 所有 Secret 数据默认 Base64 编码 需额外配置 EncryptionConfiguration
安全红线:永远不要将 Secret 的 YAML 文件(即使包含 Base64 数据)提交到 Git 仓库。Base64 解码只需一条命令:echo 'bXlwYXNz' | base64 --decode。使用 Sealed Secrets、External Secrets Operator 或 Vault 等工具管理 Secret 的声明式交付。

4.5 实战:从 YAML 创建 Secret 的正确姿势

当需要以 YAML 文件形式管理 Secret 时,必须手动对值进行 Base64 编码。以下是正确的创建流程:

# 1. 对敏感值进行 Base64 编码
echo -n 'admin' | base64
# 输出:YWRtaW4=

echo -n 'S3cur3P@ss!' | base64
# 输出:UzNjdXIzUEBzcyE=

# 2. 编写 Secret YAML
cat <<EOF > my-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  username: YWRtaW4=
  password: UzNjdXIzUEBzcyE=
EOF

# 3. 应用 YAML
kubectl apply -f my-secret.yaml

# 4. 验证(注意:kubectl get secret 默认不显示 data 值)
kubectl get secret my-secret -o jsonpath='{.data.password}' | base64 --decode
# 输出:S3cur3P@ss!
便捷技巧:使用 kubectl create secret generic 命令时,Kubernetes 会自动对 --from-literal 和 --from-file 的值进行 Base64 编码。只有在编写纯 YAML 文件时才需要手动编码。

4.6 本章小结

  • 三种核心类型:Opaque 用于通用凭据,dockerconfigjson 用于镜像拉取,tls 用于证书管理,各有严格的数据结构要求。
  • 自动加密:Kubernetes 默认不对 Secret 进行加密,仅做 Base64 编码。必须通过 EncryptionConfiguration 启用 etcd 静态加密。
  • Base64 误区:编码不等于加密。任何能访问 YAML 文件的人都可以立即解码 Secret 数据。
  • 生产建议:启用 etcd 加密 + RBAC 细粒度控制 + 使用外部密钥管理服务(如 AWS KMS、HashiCorp Vault)管理敏感数据。