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 安全防护四层结构 客户端 kube-apiserver / etcdctl 传输层保护 TLS 双向认证 peer / client 证书 访问控制 RBAC + 证书 CN 最小权限角色 静态加密 aescbc / KMS v2 EncryptionConfig etcd 数据目录 /var/lib/etcd/member/snap/db 落盘内容:k8s:enc:aescbc:v1:key1:… 备份安全 etcdctl snapshot save 加密存储 + 异地 + 校验 关键防护要点 • 传输层:etcd 必须启用 --cert-file / --key-file / --peer-cert-file,禁止明文 2379/2380 端口暴露 • 访问控制:仅 kube-apiserver 持有 client 证书,CN 与 RBAC 绑定,禁用匿名访问与 root 角色 • 静态加密:Secret/ConfigMap 必须加密,密钥由 KMS 托管,定期轮换并重写存量数据

二、访问控制:把 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 的 root 用户一旦泄露,攻击者可绕过 API Server 直接写入任意键值,包括伪造 Secret 和 RBAC 规则。因此 root 密码必须由密钥管理系统托管,且不用于日常运维。

三、备份安全:能恢复,且备份本身不成为泄露源

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 客户端端口 TLS2379 仅 HTTPS,证书由集群 CA 签发openssl s_client 握手成功
匿名访问已禁用etcdctl 无证书访问被拒绝
Secret 静态加密落盘值以 k8s:enc: 开头etcdctl get 后 hexdump 检查
加密密钥托管由 KMS 或外部密钥服务保护检查 EncryptionConfiguration 与 KMS 插件
快照备份定期生成、加密、异地存储snapshot status 校验 + 恢复演练
peer 链路认证peer-client-cert-auth 已启用检查 etcd 启动参数