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