4. etcd安全防护
etcd 是 Kubernetes 的“唯一真相源”,集群中所有对象定义、Secret、ServiceAccount Token、RBAC 规则、证书签名请求状态都存放在这里。一旦 etcd 被读取或被篡改,攻击者无需接触 kubelet 或容器运行时,就能直接获得集群的完整控制权。因此 etcd 安全防护不是“可选加固”,而是集群安全的最后一道底线。本节围绕四个相互独立又彼此支撑的维度展开:静态数据加密、访问控制、备份安全与传输层保护。
一、静态数据加密:让落盘的 Secret 不再是明文
默认情况下,etcd 以明文形式存储所有键值,任何能读取 etcd 数据目录(如 /var/lib/etcd/member/snap/db)或能访问 etcd API 的主体,都能直接看到 Secret 内容。Kubernetes 提供 EncryptionConfiguration 机制,在 API Server 写入 etcd 前对指定资源加密,读取时解密。
加密配置通过 --encryption-provider-config 传给 kube-apiserver。一个典型的配置如下:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
providers:
- aescbc:
keys:
- name: key1
secret: <base64 编码的 32 字节密钥>
- identity: {}
providers 列表的顺序即优先级:写入时使用第一个 provider,读取时依次尝试直到成功。因此轮换密钥时,应把新密钥放在首位、旧密钥保留在后,待所有数据被重写后再移除旧密钥。密钥本身必须由 KMS 或外部密钥管理服务保护,否则把密钥和加密数据放在同一台机器上,加密形同虚设。KMS v2 通过 gRPC 调用外部 KMS 插件,使主密钥永不落盘,是生产环境推荐方案。
验证加密是否生效,可直接查询 etcd 中的原始值:
ETCDCTL_API=3 etcdctl \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
get /registry/secrets/default/my-secret | hexdump -C | head
若输出以 k8s:enc:aescbc:v1:key1: 开头,说明已加密;若能看到明文 my-secret 字样,则加密未生效。对已存在的 Secret,需要执行一次 kubectl get secrets -A -o json | kubectl replace -f - 触发重写,否则旧数据仍是明文。
二、访问控制:把 etcd 的入口收窄到最小
etcd 的访问控制分两层。第一层是传输层身份认证:etcd 通过客户端证书的 CN 识别调用者,kube-apiserver 使用 /etc/kubernetes/pki/apiserver-etcd-client.crt 连接 etcd,其 CN 通常为 kube-apiserver-etcd-client。第二层是 etcd 自身的 RBAC:通过 etcdctl user add、role add、user grant-role 创建用户与角色,再用 --auth 启用认证。
生产环境应遵循三条原则:其一,禁用匿名访问,确保 --anonymous-auth=false;其二,只给 kube-apiserver 授予 /registry/ 前缀的读写权限,不给 root 角色;其三,etcd 的 2379(客户端)与 2380(peer)端口只监听内网或本机,绝不暴露到公网。若使用静态 Pod 部署,可在 /etc/kubernetes/manifests/etcd.yaml 中检查 --listen-client-urls 是否被错误地设为 https://0.0.0.0:2379。
三、备份安全:能恢复,且备份本身不成为泄露源
etcd 备份使用 etcdctl snapshot save,它生成一个包含全部键值的快照文件。备份安全包含两个方向:一是备份的可用性,二是备份的保密性。可用性方面,应定期执行快照并验证其可恢复性;保密性方面,快照文件等同于集群全部 Secret 的集合,必须加密存储、限制访问权限,并避免与集群放在同一台主机上。
ETCDCTL_API=3 etcdctl \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /backup/etcd-$(date +%Y%m%d%H%M).db
# 校验快照完整性
etcdctl snapshot status /backup/etcd-20250101.db --write-out=table
建议的备份策略是:每 30 分钟做一次增量快照,每天做一次全量快照,保留 7 天;快照文件用 GPG 或 KMS 加密后上传到对象存储,并设置生命周期策略。恢复时使用 etcdctl snapshot restore 生成新的数据目录,再让 etcd 以该目录启动。恢复演练应至少每季度执行一次,否则备份只是“看起来存在”。
四、传输层保护:TLS 是 etcd 的默认姿态
etcd 支持三种通信链路:客户端到 etcd(2379)、peer 到 peer(2380)、etcd 到 kube-apiserver。三条链路都必须启用 TLS。客户端链路使用 --cert-file 与 --key-file 提供服务器证书,用 --client-cert-auth 要求客户端出示证书;peer 链路使用 --peer-cert-file、--peer-key-file 与 --peer-client-cert-auth。证书应由集群专属 CA 签发,有效期不宜过长,并纳入证书轮换流程。
验证传输层是否真正加密,可用 openssl s_client -connect 127.0.0.1:2379 -CAfile /etc/kubernetes/pki/etcd/ca.crt 观察握手是否成功;若返回 Verify return code: 0 (ok),说明证书链可信。若连接被拒绝或出现明文 HTTP 响应,则说明 TLS 未启用或端口配置错误。
五、落地检查清单
| 检查项 | 预期结果 | 验证方式 |
|---|---|---|
| etcd 客户端端口 TLS | 2379 仅 HTTPS,证书由集群 CA 签发 | openssl s_client 握手成功 |
| 匿名访问 | 已禁用 | etcdctl 无证书访问被拒绝 |
| Secret 静态加密 | 落盘值以 k8s:enc: 开头 | etcdctl get 后 hexdump 检查 |
| 加密密钥托管 | 由 KMS 或外部密钥服务保护 | 检查 EncryptionConfiguration 与 KMS 插件 |
| 快照备份 | 定期生成、加密、异地存储 | snapshot status 校验 + 恢复演练 |
| peer 链路认证 | peer-client-cert-auth 已启用 | 检查 etcd 启动参数 |