bigywater.tech
Kubernetes · 65

静态加密:EncryptionConfiguration 的效果

开了静态加密之后,etcd 里到底变了什么?以前存的 Secret 会自动加密吗?换密钥的顺序错了会怎样?这篇在 kind 控制面节点里手动给 kube-apiserver 加 EncryptionConfiguration,直接读 etcd 的字节对照。

k8s:enc:aescbc:v1:key1:
etcd 里加密后的值的前缀;之后明文再也找不到
503 → 563
kubectl replace 重写让旧 Secret 被加密时 resourceVersion 的变化
corrupt object
提前删掉旧 key 后读取旧 Secret 的错误;连 kubectl get secrets 列表也整个失败

只有新写入的才加密

实测 · 本机执行输出
  给 kube-apiserver 静态 Pod 加上 --encryption-provider-config(AES-CBC 的 key1 + identity 兜底),等 apiserver 重启:56 秒后新的 apiserver 容器就绪
  开启之后新建的 Secret after:etcd 值 279 字节,开头 b'k8s:enc:aescbc:v1:key1:\xd5~xUq\xc8\x91!\x04\x9bq%Yw\x04\x03\xbe\xbdb_v';能直接找到明文 hunter2:False
  开启之前建的 Secret before(没动过):etcd 值 230 字节,开头 b'k8s\x00';能直接找到明文 hunter2:True
  kubectl 读 before / after 都正常:hunter2 / hunter2(apiserver 读时按前缀选解密方式)
  同时间创建的 ConfigMap:etcd 值能找到明文:True(配置里只列了 secrets,其他资源不加密)

在没加密的集群里先写 Secret before(etcd 里 230 字节,明文 hunter2 直接可见)。给 kube-apiserver 静态 Pod 加上 --encryption-provider-config(AES-CBC 的 key1 + identity 兜底),约 56 秒后新 apiserver 就绪。之后新建的 after 在 etcd 里是 k8s:enc:aescbc:v1:key1:… 开头的 279 字节密文,找不到明文;before 没动过,仍是明文;kubectl 读两个都正常——apiserver 按前缀选择解密方式。同时创建的 ConfigMap 不在配置的 resources 里,etcd 里仍是明文。

让旧数据加密:重写一遍

实测 · 本机执行输出
  kubectl get secrets -o json | kubectl replace -f - 之后的 before:etcd 值 279 字节,开头 b'k8s:enc:aescbc:v1:key1:\x10\xe8\xc2\x97\xfcP\x93\xf9\x92\xb7\xa2\xad\xcb\xbf\x7fen\xec\xc9\xaa\xc5';能直接找到明文 hunter2:False
  resourceVersion 503 → 563(replace 是一次真实写入)

kubectl get secrets -o json | kubectl replace -f -:before 的 resourceVersion 从 503 变成 563(这是一次真实的写入),etcd 里变成 key1 加密的 279 字节密文。存量数据没有别的办法自动加密,必须读出再写回,而且它会产生更新事件,watch 的人会收到。

轮换密钥的顺序

实测 · 本机执行输出
  步骤 1:配置里 key1、key2 都列出来,key1 在最前(只是让 apiserver 能解 key2):新建的 rot1 开头 b'k8s:enc:aescbc:v1:key1:v'(仍是 key1 加密)
  步骤 2:把 key2 放到最前并写回配置文件:150 秒内 apiserver 没有自动重新加载;重启 apiserver 之后新写入的 Secret 才用 key2
  before(key1 写的):etcd 值 279 字节,开头 b'k8s:enc:aescbc:v1:key1:\x10\xe8\xc2\x97\xfcP\x93\xf9\x92\xb7\xa2\xad\xcb\xbf\x7fen\xec\xc9\xaa\xc5';能直接找到明文 hunter2:False
    列表里还保留着 key1:before 仍能读:'hunter2'
  步骤 3(错误示范):在重写旧数据之前就把 key1 从配置里删掉(需要重启 apiserver 才生效):读 before → 退出码 1;Error from server (InternalError): Internal error occurred: StorageError: corrupt object, Code: 7, Key: /secrets/k59/before, ResourceVersion: 0, AdditionalErrorMsg: data from the storage is not transformable revision=0: 
    key1 写的 rot1 同样读不出来:退出码 1;key2 写的最新一个 Secret 仍可读:退出码 0
    kubectl get secrets -n k59(列表里有读不出来的对象):退出码 1;Error from server (StorageReadError): failed to read one or more secrets from the storage: StorageError: corrupt object, Code: 7, Key: /registry/secrets/k59/after, ResourceVersion: 0, AdditionalErrorM
  把 key1 加回去(重启 apiserver 之后)读 before:'hunter2'(数据没丢,只是暂时解不开)
  把所有 Secret 重写一遍之后的 before:etcd 值 279 字节,开头 b'k8s:enc:aescbc:v1:key2:+-s{G\xcc\x05\xd3\x8c]Z\x98\xdb2\x11\x08\xabF+\x01\xa3';能直接找到明文 hunter2:False
    现在 before 的前缀是 key2:True,可以放心从配置里删掉 key1

配置里先列 key1、key2(key1 在最前,只是让 apiserver 能解 key2),新建的 rot1 还是 key1。把 key2 放到最前再写回配置文件:150 秒内 apiserver 没有自动重新加载(本实验环境里的观察),重启 apiserver 后新写入的 Secret 才用 key2,key1 写的 before 因为列表里还保留 key1 仍能读。

错误示范——在重写旧数据之前就把 key1 从配置删掉(重启 apiserver 后生效):读 before 得到 InternalError … StorageError: corrupt object … data from the storage is not transformable;kubectl get secrets 整个列表都失败(StorageReadError),只有 key2 写的对象还能读。把 key1 加回去再重启,before 又能读,数据没丢;把所有 Secret 重写一遍后前缀变成 key2,这时才能安全地删掉 key1。

分步演示

静态加密
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。单节点 kind 集群 kx-enc(Kubernetes v1.37.0),先不开启加密;用 docker cp 把 EncryptionConfiguration 放进控制面节点的 /etc/kubernetes/enc,再改 /etc/kubernetes/manifests/kube-apiserver.yaml 加参数、卷和挂载,由 kubelet 重启 apiserver;etcd 的值用 etcdctl -w json 读出后解 base64 检查字节;key 是随机生成的 32 字节;每种情形各一次
    • 没有验证:kms v2 提供者与信封加密;secretbox / aesgcm 提供者的差异;--encryption-provider-config-automatic-reload 的默认值与生效条件(本实验环境里改文件后 150 秒内没有观察到自动生效,不代表它不能工作);加密对 apiserver 性能的影响;etcd 备份里的内容;对其他资源(configmaps、自定义资源)加密;多个 apiserver 实例之间的滚动顺序
    京ICP备2026067502号-1京公网安备11010502063487号