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 编码存储,但这不是加密。
生产建议:在 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)管理敏感数据。