Secret 里的值到底有多“保密”?base64 是加密吗?etcd 里存的是什么?只有 list 权限能不能看到值?这篇在真集群里把 Secret 从 kubectl、etcd、RBAC 和 Pod 里各看一遍。
kubectl get secret db -o json 里 data.password='czNjcjN0LVBhNTU=' base64 -d 之后='s3cr3t-Pa55'(任何能 get 这个 Secret 的人都能做) kubectl describe secret db 的 Data 部分:Data | ==== | password: 11 bytes 用 stringData 写入明文:服务端存成 data.token='cGxhaW4tdGV4dC1pbi15YW1s'(= 'plain-text-in-yaml');返回的对象里 stringData=(没有) data 里写不是 base64 的值:退出码 1;Error from server (BadRequest): error when creating "STDIN": Secret in version "v1" cannot be handled as a Secret: illegal base64 data at input byte 3 Secret 有 type 字段:db 的 type=Opaque
kubectl create secret --from-literal=password=s3cr3t-Pa55 之后,API 里的 data.password 是 czNjcjN0LVBhNTU=,base64 -d 一步还原。kubectl describe 只显示 password: 11 bytes,那只是不显示,不是不能读。stringData 是写入时的便利字段:服务端把它转成 data(base64),读回来时没有 stringData;在 data 里写不是 base64 的内容会直接失败:illegal base64 data at input byte 3。
etcd key /registry/secrets/k58/db:值共 230 字节,开头 b'k8s\x00\n\x0c\n\x02v1\x12\x06'(k8s\x00 是 protobuf 存储格式的魔数) 值里能直接找到 password 明文 s3cr3t-Pa55:True;能找到 base64 形式 czNjcjN0LVBhNTU=:False(etcd 里直接存原始字节,不再 base64) 把值里的不可见字节换成点:k8s.....v1..Secret........db....k58".*$57aadef9-5035-4fa2-8e21-b50b52a491012.8.B...........e..kubectl-create..Update..v1"......... 同样内容放进 ConfigMap:etcd 值开头 b'k8s\x00\n\x0f\n\x02v1\x12\t',也能直接找到明文:True(两者存储方式一样,Secret 没有额外保护)
etcd 里 /registry/secrets/k58/db 的值共 230 字节,开头是 k8s\x00(Kubernetes 的 protobuf 存储格式标记),把不可见字节换成点能读到 Secret、db、k58、kubectl-create 这些字符串;s3cr3t-Pa55 明文直接能找到,base64 形式反而找不到——etcd 存的是原始字节。同样的数据放进 ConfigMap,etcd 里的样子几乎一样,Secret 默认没有任何额外保护。所以 etcd 的备份文件、能直接访问 etcd 的人都等于拿到了所有 Secret。
只有 list 权限的 ServiceAccount:GET 单个 Secret → HTTP 403
LIST 全部 Secret → HTTP 200;响应里带完整的 data:{'db': 's3cr3t-Pa55', 'sd': 'plain-text-in-yaml'}(list 的权限等于读全部值)
kubectl auth can-i get secrets --as=…lister → no
kubectl auth can-i list secrets --as=…lister → yes给 ServiceAccount 只绑 list secrets:GET 单个 Secret 是 403,kubectl auth can-i get secrets 是 no;但 LIST 命名空间下全部 Secret 返回 200,响应里就带着每个 Secret 的完整 data,解码就是 s3cr3t-Pa55 和 plain-text-in-yaml。给 list 就等于给了读取所有值的权限,不是“只能看名字”。
容器里 /etc/s 的挂载:tmpfs /etc/s tmpfs ro,relatime,size=8124516k,noswap 0 0(tmpfs,不落节点磁盘)
/etc/s/password='s3cr3t-Pa55';环境变量 PW='s3cr3t-Pa55';/proc/1/environ 里能看到:True
kubectl get pod -o yaml 里 env 只写引用:[{'name': 'PW', 'valueFrom': {'secretKeyRef': {'key': 'password', 'name': 'db'}}}](值不在 Pod 对象里)Secret 作为卷挂进容器时,挂载点是 tmpfs … ro,不落节点磁盘;容器里 /etc/s/password 是明文。作为环境变量时,PW=s3cr3t-Pa55 进入进程环境,在 /proc/1/environ 里能看到,子进程会继承。Pod 对象里只有 secretKeyRef 引用,值不在 Pod 里,但谁能 exec 进这个容器,谁就能读。