国密改造 Kubernetes Secret 存储:SM4 加密的完整实践指南

实践教程 · 2026-07-02 · 7 阅读

前言

Kubernetes 的 Secret 资源默认以 Base64 编码存储在 etcd 中。Base64 不是加密——任何人拿到 etcd 数据都可以瞬间还原。在生产环境中,这导致两个严重问题:

  • 合规风险:等保 2.0 和密评要求敏感数据加密存储,Base64 编码完全不满足要求
  • 安全风险:etcd 备份、快照、灾难恢复场景下,所有 Secret 等同于明文
本文将介绍通过 Kubernetes EncryptionConfiguration 实现 Secret 加密存储的方案,重点讨论 SM4 国密算法在 etcd 层加密中的实际应用路径。

方案选型

Kubernetes 提供了多种 Secret 加密方案,各有适用场景:

方案加密范围侵入程度适用场景
EncryptionConfiguration(etcd 层)全部 Secret全局透明加密
External Secrets Operator单个 Secret对接外部 KMS
CSI Secret Store Driver单个 Secret精细化权限控制
我们的选择:EncryptionConfiguration + SM4 国密算法,实现 etcd 层的透明加密。这种方式侵入最小、运维成本最低,且满足密评对"敏感数据加密存储"的要求。

现实约束:Kubernetes 原生不支持 SM4

在深入实施方案之前,必须明确一个关键事实:上游 Kubernetes 的 EncryptionConfiguration 原生仅支持 aescbc、aesgcm、secretbox、envelope、kms、noop、identity 等加密提供者,不包含 SM4 算法。

这意味着要实现 SM4 加密,有以下三条路径:

路径难度维护成本适用场景
A. 使用 KMS 加密提供者对接国密 KMS生产推荐方案
B. 定制编译支持 SM4 的 kube-apiserver有定制能力的团队
C. 在应用层使用 SM4 加密后存入 Secret快速验证/小规模部署
本文重点介绍 路径 A(KMS 方案)路径 C(应用层方案),这两条路径无需修改 Kubernetes 源码,可直接落地。

路径 A:EncryptionConfiguration + KMS 加密提供者

架构原理

Kubernetes 的 KMS 加密提供者允许通过 gRPC 协议调用外部 KMS 服务进行数据加解密。这是实现 SM4 加密最推荐的方案:

CODE
kube-apiserver → KMS Plugin (gRPC) → 国密 KMS 服务 (SM4)

配置示例

KMS Plugin 实现(Python 示例)

密钥生成与管理

BASH
# 使用 Python 脚本生成 SM4 密钥
python3 kms_plugin.py > /tmp/sm4-keys.env

# 将密钥安全存储到 KMS 服务中
# 不要将密钥硬编码在配置文件中
cat /tmp/sm4-keys.env
# SM4 Key (base64): aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789ABCDEF=
# Key Identity: XYZ123abc456DEF789ghiJKL012mnoPQR=

路径 C:应用层 SM4 加密

对于不想引入 KMS 插件的小型集群,可以在应用层直接加密 Secret 数据:

SM4 加密工具函数

创建加密 Secret

BASH
# 1. 加密 Secret 数据
SM4_KEY=$(python3 -c "import os,base64; print(base64.b64encode(os.urandom(16)).decode())")
IV=$(python3 -c "import os,base64; print(base64.b64encode(os.urandom(16)).decode())")

# 2. 将加密数据存储为 Secret
kubectl create secret generic app-credentials \
  --from-literal=sm4-ciphertext="<加密后的密文>" \
  --from-literal=sm4-iv="$IV" \
  --from-literal=sm4-key-ref="kms://my-kms/key/sm4-app-key" \
  --dry-run=client -o yaml | kubectl apply -f -

密钥轮换

Kubernetes KMS 加密提供者原生支持密钥轮换。通过在 EncryptionConfig 中配置多个密钥标识符:

轮换流程

  • 在 KMS 中生成新 SM4 密钥(密钥版本 v2)
  • 将新密钥配置添加到 EncryptionConfig 第一位
  • 重启 kube-apiserver
  • 触发全量 Secret 重新加密:
BASH
# 对所有 Secret 执行一次写回,触发新密钥加密
kubectl get secrets --all-namespaces -o json | \
  kubectl apply -f -
注意:此操作会将所有 Secret 从 etcd 读出、用新密钥加密、再写回。对于大规模集群,建议在维护窗口执行。

踩坑实录

坑 1:SM4 密钥长度必须是 16 字节

现象:加密插件启动时报错 invalid key length

原因:SM4 的密钥长度固定为 128 位(16 字节),而 AES-256 的密钥长度为 32 字节。直接将 AES 密钥用于 SM4 会失败。

解决

PYTHON
import os, base64
# 正确:16 字节 = 128 位
key = os.urandom(16)
print(f"SM4 key: {base64.b64encode(key).decode()}")
print(f"Key length: {len(key)} bytes = {len(key)*8} bits")

坑 2:gmssl 库的 CryptSM4 类行为

现象:调用 sm4.CryptSM4().crypt_ecb() 时,16 字节输入返回 32 字节输出。

原因:gmssl 库的 CryptSM4.crypt_ecb() 方法在加密模式下会自动添加 PKCS#7 填充。对于恰好 16 字节的输入,它会填充到 32 字节。

解决:使用 one_round() 接口手动控制块加密,或使用 crypt_cbc() 接口处理 CBC 模式:

PYTHON
from gmssl import sm4

key = bytes.fromhex("0123456789abcdef0123456789abcdef")
c = sm4.CryptSM4()
c.set_key(key, sm4.SM4_ENCRYPT)

# 推荐方式:使用 one_round 手动控制填充
block = b"0123456789abcdef"  # 16 字节
output = bytes(c.one_round(c.sk, list(block)))
print(f"ECB output length: {len(output)} bytes")  # 正好 16 字节

坑 3:etcd 加密后体积增长

现象:加密后的 Secret 体积增大约 30-50%。

原因:SM4-CBC 模式需要 16 字节 IV + PKCS#7 填充(最多 16 字节)。

解决

  • 监控 etcd 磁盘使用率
  • 调整 --quota-backend-bytes 参数
  • 定期清理过期 Secret

坑 4:备份恢复中的密钥管理

现象:etcd 快照恢复后,Secret 无法解密。

原因:EncryptionConfig 中的 KMS 密钥标识符与 etcd 快照不绑定,但密钥本身需要可访问。

解决

  • 将 KMS 服务与 etcd 分开备份
  • 密钥轮换时保留旧密钥至少一个轮换周期
  • 制定明确的密钥灾难恢复预案

合规要点

根据 GM/T 0054-2018《信息系统密码应用基本要求》和 GB/T 39786-2021《信息安全技术 信息系统密码应用基本要求》:

要求对应措施
敏感数据加密存储etcd 层 SM4 加密 Secret
密钥安全管理KMS 托管 SM4 密钥,密钥轮换机制
密码算法合规使用 SM4 国密算法,不使用非合规替代
审计日志记录所有 Secret 的加密/解密操作

总结

本文介绍了 Kubernetes Secret 的 SM4 国密加密两条实用路径:

  • KMS 插件方案:通过 Kubernetes KMS 加密提供者对接国密 KMS 服务,是生产环境的推荐方案
  • 应用层加密方案:在应用代码中使用 SM4 加密后存入 Secret,适合小规模部署
核心要点:

  • Kubernetes 原生 EncryptionConfiguration 不支持 SM4,需要通过 KMS 插件或应用层实现
  • SM4 密钥长度严格为 16 字节(128 位),不同于 AES-256 的 32 字节
  • 密钥轮换支持多版本密钥配置,需在维护窗口执行全量重新加密
  • 备份恢复时需确保 KMS 密钥可访问

合规检查清单

  • [ ] Secret 在 etcd 中以 SM4 加密存储,非 Base64 明文
  • [ ] SM4 密钥长度验证为 16 字节
  • [ ] 密钥轮换流程文档化并定期演练
  • [ ] KMS 服务有独立的备份恢复预案
  • [ ] 审计日志记录所有 Secret 的加密/解密操作
  • [ ] 使用 GM/T 0054-2018 和 GB/T 39786-2021 标准进行合规评估

参考来源

  • Kubernetes EncryptionConfiguration: https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/
  • GM/T 0054-2018《信息系统密码应用基本要求》
  • GB/T 39786-2021《信息安全技术 信息系统密码应用基本要求》
  • KMS Plugin API (k8s.io/kms): https://github.com/kubernetes/kms
  • gmssl Python 库: https://github.com/duanhongyi/gmssl
  • Tongsuo 国密 OpenSSL: https://github.com/Tongsuo-Project/Tongsuo