☰
kubernetes-the-hard-way 实践指南:生成数据加密配置与加密密钥(etcd 静态加密)
2026/10/13 3:12:39 网站建设 项目流程
  • 文档/教程

【免费下载链接】kubernetes-the-hard-way

Bootstrap Kubernetes the hard way on Vagrant on Local Machine. No scripts.

项目地址:https://gitcode.com/gh_mirrors/kub/kubernetes-the-hard-way
点击查看免费下载

Kubernetes 将集群状态、应用配置与 Secret 等敏感数据持久化在 etcd 中,本指南演示在 kubernetes-the-hard-way 本地集群搭建流程的第 06 步:生成一个 32 字节的加密密钥与一份encryption-config.yaml加密配置文件,并把该文件分发到两台控制平面节点,为后续 kube-apiserver 启用「静态加密(encryption at rest)」做好准备。读完本节,你将掌握 EncryptionConfig 的完整结构、aescbc与identityprovider 的协作语义,以及如何在 smoke test 阶段用hexdump验证 Secret 确实以密文形式落盘。

本节在整套实验中的位置

kubernetes-the-hard-way 的引导流程严格按序推进,每一节的产物都会被后续步骤消费。本节(第 06 步)处于如下位置:

前序步骤本节内容后续步骤
生成 Kubernetes 认证配置文件(kubeconfigs)生成数据加密密钥与encryption-config.yaml引导 etcd 集群 → 引导 Kubernetes 控制平面

本节的产出encryption-config.yaml会在第 08 步被kube-apiserver通过--encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml参数引用(见 引导 Kubernetes 控制平面),并在第 16 步的 smoke test 中接受密文验证(见 冒烟测试:数据加密验证)。因此,本节虽然只有寥寥几条命令,却是集群数据安全的关键一环。

为什么需要加密 etcd 中的数据

Kubernetes 会在 etcd 中持久化多种数据:集群整体状态、应用配置(ConfigMap)、以及敏感程度最高的Secret。默认情况下这些数据以明文形式存储——任何能读取 etcd 数据文件或通过 etcd 客户端查询的人,都能直接看到 Secret 的原始内容。

Kubernetes 原生支持「数据静态加密(encryption at rest)」,即在数据写入 etcd 之前由 kube-apiserver 加密、读取时再解密,从而使落盘的数据始终以密文形态存在。本节生成的内容正是为了让 kube-apiserver 具备这一能力:

  1. 一个加密密钥——32 字节随机数据,base64 编码后作为对称加密密钥;
  2. 一份加密配置文件——声明「哪些资源需要加密」以及「使用哪个 provider、哪把密钥加密」。

注意:执行位置为controlplane01(本实验将其设定为管理客户端节点),即文档内[//]: # (host:controlplane01)注释所标识的主机。

前置条件

  • 已完成 证书颁发机构与 TLS 证书生成(第 04 步)与 kubeconfigs 生成(第 05 步);
  • 已通过vagrant ssh(VirtualBox 环境)或multipass shell(Apple Silicon 环境)登录到controlplane01;
  • 已按 安装客户端工具 配置好节点间的免密 SSH,使controlplane01能对controlplane02执行scp/ssh。

第一步:生成加密密钥

在controlplane01上执行:

ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)

这条命令做了两件事:

  • head -c 32 /dev/urandom从 Linux 内核的随机源/dev/urandom中读取32 字节随机数据。32 字节即 256 比特,是 AES 等对称加密算法的主密钥长度标准;
  • base64将二进制随机数编码为可打印的 base64 字符串,使其能安全嵌入 YAML 文件。

结果保存在 shell 环境变量ENCRYPTION_KEY中,供下一步 heredoc 写文件时直接引用。该变量仅存在于当前 shell 会话,重新登录后需要重新生成——这也是本实验刻意采用「裸命令」而非脚本的原因:让每一步都可复现、可理解。

第二步:创建加密配置文件

使用 heredoc 将加密配置写入encryption-config.yaml:

cat > encryption-config.yaml <<EOF kind: EncryptionConfig apiVersion: v1 resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: ${ENCRYPTION_KEY} - identity: {} EOF

生成的文件内容如下(其中secret字段为 base64 随机串):

kind: EncryptionConfig apiVersion: v1 resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: <32字节随机数据的base64编码> - identity: {}

配置字段逐项解析

字段取值含义
kindEncryptionConfig声明这是一份 Kubernetes 静态加密配置;kube-apiserver 通过该 kind 识别文件
apiVersionv1配置文件的 API 版本
resources数组声明对哪些 API 资源启用加密。这里只列了secrets,即仅对 Secret 生效,ConfigMap、Event 等仍按默认行为存储
providers数组声明加密 provider 及其优先级列表。列表顺序是有语义的(见下文)
aescbc.keys[].namekey1密钥的标识名。它会在 etcd 中随密文一同记录(形如k8s:enc:aescbc:v1:key1),用于告诉 kube-apiserver 解密时应选用哪把密钥,也是后续做密钥轮换的关键锚点
aescbc.keys[].secret${ENCRYPTION_KEY}真正的对称加密密钥(base64 编码的 32 字节随机数)
identity: {}空对象透传 provider,不加密直接存储,作为兜底解密 provider

aescbc 与 identity 的协作语义

  • aescbc:使用 AES-CBC 模式对资源数据进行对称加密,并附带密钥标识前缀。本实验把它放在providers列表的第一位,意味着新建/写入的 Secret 一律先用key1这把密钥加密;
  • identity:不加密、原样存储数据。它被放在第二位,充当解密兜底:当读取到历史上以明文写入的旧数据(例如在启用加密之前就已经存在的 Secret)时,kube-apiserver 会沿 provider 列表向下寻找能解密的 provider,最终由identity原样放行,避免老数据因「无法解密」而变得不可读。

这正是「第一 provider 用于加密新数据、其余 provider 用于解密存量数据」这一顺序语义在本配置中的体现。如果调换顺序把identity放在第一位,新写入的 Secret 将不会加密,验证阶段(见下文)就观察不到k8s:enc:aescbc前缀了。

顺带一提:密钥轮换的扩展思路

本节只创建了key1一把密钥。生产环境中做密钥轮换的通用做法是:在aescbc.keys数组的首位新增一把key2,同时保留key1:

providers: - aescbc: keys: - name: key2 # 新密钥:新写入数据用它加密 secret: <key2 的 base64> - name: key1 # 旧密钥:仍保留用于解密存量密文 secret: <key1 的 base64>

这样新数据立即使用新密钥加密,而旧数据在轮换过渡期内仍可被解密读取。待存量数据全部重写(或主动重加密)之后,再移除旧密钥条目。本实验的key1命名与验证输出中的前缀一致,正是为了演示这一机制而设计的。

第三步:分发加密配置文件到两台控制平面节点

for instance in controlplane01 controlplane02; do scp encryption-config.yaml ${instance}:~/ done

这里将encryption-config.yaml同时复制到controlplane01与controlplane02。原因是本实验搭建的是双控制平面高可用集群:两台节点各自运行一个 kube-apiserver,都可能承担 Secret 的写入或读取请求。只有两台节点的 apiserver 持有同一把key1和同一份 provider 顺序配置,才能保证「节点 A 加密写入的数据,节点 B 能够解密读取」,否则会出现跨节点读写失败或密文不可识别的问题。

第四步:移动到 apiserver 约定的配置目录

for instance in controlplane01 controlplane02; do ssh ${instance} sudo mkdir -p /var/lib/kubernetes/ ssh ${instance} sudo mv encryption-config.yaml /var/lib/kubernetes/ done

两步分别完成:

  1. mkdir -p /var/lib/kubernetes/——创建 Kubernetes 主数据目录。该目录之后还会承载pki/子目录(证书与私钥)以及各控制面组件的 kubeconfig(见 引导 Kubernetes 控制平面 中的sudo mv kube-controller-manager.kubeconfig /var/lib/kubernetes/等步骤);
  2. sudo mv encryption-config.yaml /var/lib/kubernetes/——把配置文件从家目录移动到上述目录,路径恰好对应后续 kube-apiserver 单元文件中的--encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml。

安全建议:encryption-config.yaml内含对称加密密钥(base64 明文),等同敏感凭据。生产实践中建议进一步收紧其访问权限,例如sudo chmod 600 /var/lib/kubernetes/encryption-config.yaml,并仅允许 apiserver 运行账户读取;同时密钥本身应纳入密钥管理机制保护。本实验出于教学目的未显式 chmod,但你应知晓该文件不应被普通用户可读。

与后续步骤的衔接:kube-apiserver 如何启用加密

本节生成的配置文件本身不会自动生效,必须由 kube-apiserver 显式加载。在第 08 步「引导 Kubernetes 控制平面」中,两台控制平面节点会创建kube-apiserver.servicesystemd 单元文件,其ExecStart中包含(见 docs/08-bootstrapping-kubernetes-controllers.md):

--encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml

该参数让 apiserver 在启动时读取/var/lib/kubernetes/encryption-config.yaml,此后每一条 Secret 的写入都会按 provider 列表执行加密。整个调用链可以概括为:

kubectl create secret → kube-apiserver → 读取 /var/lib/kubernetes/encryption-config.yaml → 命中第一个 provider aescbc / key1 加密 → 写入 etcd(键值带 k8s:enc:aescbc:v1:key1 前缀)

同理,apiserver 也依赖本配置读取旧数据:读取时按 provider 列表顺序尝试,密文前缀决定实际使用哪把密钥,最终由aescbc或identity完成解密返回。

验证加密是否真正生效(Smoke Test 中的做法)

配置正确与否,在集群跑通后可以用第 16 步 smoke test 的方法直接验证(详见 冒烟测试:数据加密)。核心思路是:创建一个 Secret,然后直接从 etcd 中把它读出来,看是否已是密文。

在controlplane01上先创建一个测试 Secret:

kubectl create secret generic kubernetes-the-hard-way \ --from-literal="mykey=mydata"

再通过 etcd 客户端读取并转储十六进制内容:

sudo ETCDCTL_API=3 etcdctl get \ --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/etcd/ca.crt \ --cert=/etc/etcd/etcd-server.crt \ --key=/etc/etcd/etcd-server.key \ /registry/secrets/default/kubernetes-the-hard-way | hexdump -C

输出中关键的一行(十六进制转储的 ASCII 列)为:

00000030 79 0a 6b 38 73 3a 65 6e 63 3a 61 65 73 63 62 63 |y.k8s:enc:aescbc|

也就是说,etcd 中该键对应的值以k8s:enc:aescbc:v1:key1前缀开头,hexdump里能看到明文的人类可读部分只有/registry/secrets/...键路径与加密元数据前缀,mykey=mydata的真实内容已被aescbcprovider 用key1加密成不可读的随机字节。

这段前缀k8s:enc:aescbc:v1:key1本身就是一份「自描述」:enc表示静态加密开启,aescbc表示所用 provider 算法,v1表示 provider 版本,key1表示加密所用密钥的名称——与你在本节配置文件中定义的name: key1一一对应。验证完毕后清理测试资源:

kubectl delete secret kubernetes-the-hard-way

若在 smoke test 中看到identity前缀(k8s:enc:identity)或完全没有前缀,说明 Secret 未加密写入,应回头检查本节的 provider 顺序与 apiserver 的--encryption-provider-config参数是否生效。

关键要点小结

  • 加密密钥:32 字节(256 位)随机数据经 base64 编码,保存在ENCRYPTION_KEY变量中,用于 AES-CBC 对称加密;
  • 加密配置:kind: EncryptionConfig、apiVersion: v1,对secrets资源启用加密;provider 列表首位的aescbc负责加密新数据,第二位的identity负责解密存量明文数据;
  • 高可用一致性:encryption-config.yaml必须同时部署到controlplane01与controlplane02,保证两个 apiserver 用同一把密钥读写 Secret;
  • 落地位置:/var/lib/kubernetes/encryption-config.yaml,与 kube-apiserver 的--encryption-provider-config参数路径严格一致(见 docs/08-bootstrapping-kubernetes-controllers.md);
  • 生效时机:本步仅完成「生成与分发」,加密在 apiserver 启动后才会实际生效,最终通过 smoke test 中 etcd 键值前缀k8s:enc:aescbc:v1:key1验证(见 docs/16-smoke-test.md)。

下一步进入 引导 etcd 集群,将两台控制平面节点上的 etcd 组装为高可用存储后端;上一步回顾可查看 生成 Kubernetes 认证配置文件。

  • 文档/教程

【免费下载链接】kubernetes-the-hard-way

Bootstrap Kubernetes the hard way on Vagrant on Local Machine. No scripts.

项目地址:https://gitcode.com/gh_mirrors/kub/kubernetes-the-hard-way
点击查看免费下载
上一篇:照片一键转手绘:handraw-style SC-021双拼照片转译图型原理全解析
下一篇:DeepSeek-V4.1-Flash Prompt 编码全指南:解读 encoding.py 的消息格式、工具调用与多模态输入

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询