【K8S 安全】1. 初识 K8S
·
一、K8S 是什么
K8s 是一台 “管理很多台机器的操作系统”。
在我们熟悉的操作系统里,程序要读文件、开网络,得通过「系统调用」找内核。K8s 里一模一样:任何操作都是向 API Server 发一个 HTTP 请求。
这是理解后面所有攻击手法的关键——渗透 K8s 就是想办法拿到一个「有权限的身份」,然后用这个身份发 HTTP 请求。
K8S 核心组件
- API Server:负责所有请求的入口、鉴权、校验
- etcd:存储集群的所有状态
- kubelet:负责容器的生命管理
- Scheduler:决定 Pod 跑在哪台机器上
- Controller:对比「期望状态」和「实际状态」,不一致就修
- kubectl: HTTP 客户端,帮忙给 API Server 发请求
K8S 核心对象
- Node:物理机或虚拟机
- Pod:最小运行单元,里面装一个或多个容器
- Namespace:逻辑分区,权限和命名都按它隔离
- ServiceAccount (SA):Pod 的身份
- Role / ClusterRole:定义权限规则
- RoleBinding:绑定权限规则给 SA
- Secret:存放密码、密钥、token
- ConfigMap:存放非敏感的配置
Pod 用某个 SA 的身份运行 → SA 通过 Binding 拿到某些权限 → 于是这个 Pod 就能对 API Server 做某些操作。
实操
Windows 安装环境
# 1. 装 Docker Desktop(kind 需要它来当"机器")—— 装完要启动它
winget install Docker.DockerDesktop --source winget --accept-source-agreements
# 2. 装 kubectl(客户端)
winget install Kubernetes.kubectl --source winget --accept-source-agreements
# 3. 装 kind(用来一键造一个本地集群)
winget install Kubernetes.kind--source winget --accept-source-agreements
- 验证
docker version
kubectl version --client
kind version
起集群
kind create cluster --name lab
kubectl get nodes # 看有几台"机器"
kubectl get namespaces # 看有哪些"楼层"
kubectl get pods -A # 看所有楼层里的 Pod(-A = 所有命名空间)
kubectl cluster-info # 看办事大厅的地址
kubectl get pods -v=8 2>&1 | Select-String "GET https" # 看 kubectl 实际发的请求
二、身份:ServiceAccount 与 RBAC
集群里运行的每个 Pod,都挂着一张 ServiceAccount 。
RBAC(基于角色的访问控制)
谁能做(Subject: ServiceAccount)
↕ 通过 Binding 绑定
能做什么(Role/ClusterRole: 一堆 动词+资源 的规则)
规则示例:
verbs: ["get","list"] + resources: ["pods"] = "能查看 Pod"。
- Role 是命名空间内的,ClusterRole 是全集群的。一个命名空间里的 Role 管不到别的命名空间。
- list 和 get 是两种不同权限。get 是拿一个,list 是拿一批。
- list secrets 拿到的是完整对象,包含明文数据(base64 只是编码,不是加密)。
实操
- 一个 K8S 配置文件
apiVersion: v1
kind: ServiceAccount
metadata:
name: lab-reader
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: default
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: lab-reader-binding
namespace: default
subjects:
- kind: ServiceAccount
name: lab-reader
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
kubectl apply -f 01-sa-rbac.yaml
kubectl get sa,role,rolebinding -n default
- 使用 can-i 看 SA 的权限
# 你是集群管理员,所以可以"假装成"别人提问(--as)
kubectl auth can-i list pods --as=system:serviceaccount:default:lab-reader
# → yes
kubectl auth can-i list secrets --as=system:serviceaccount:default:lab-reader
# → no
kubectl auth can-i list secrets --as=system:serviceaccount:default:lab-reader -n kube-system
# → no
# 看看这个身份"全部"能干什么
kubectl auth can-i --list --as=system:serviceaccount:default:lab-reader
防御视角
- 一个 SA 的权限应该刚好够它干活。给它 list secrets 就等于给它全楼保险柜的钥匙。
- 检查集群里哪些 SA 权限过大:kubectl get clusterrolebindings -o wide,重点看绑到 cluster-admin 的。
—— "给 SA 加了权限"和"给 Pod 加了权限"是同一件事。
三、Pod 详解
K8S 会自动在 Pod 中加两个文件
/var/run/secrets/kubernetes.io/serviceaccount/
├── token ← SA 的电子凭证(一个 JWT)
├── ca.crt ← 用来验证 API Server 是不是真的(HTTPS 证书)
└── namespace ← 我自己在哪个命名空间
配合两个环境变量
KUBERNETES_SERVICE_HOST=10.96.0.1 ← API Server 的地址
KUBERNETES_SERVICE_PORT=443
Pod 里天然就能操作集群 —— 不需要密码,不需要配置。这叫 in-cluster 访问,是所有 K8s 攻击的起点:只要你能在集群里跑一个容器,你就能拿到一个身份。
实操
进入 Pod
# 起一个带 shell 的临时 Pod,退出即销毁
kubectl run shell --rm -it --restart=Never --image=curlimages/curl:8.10.1 -- sh
进入 Pod 后:
# 1. 看自动挂载的身份文件
ls -l /var/run/secrets/kubernetes.io/serviceaccount/
cat /var/run/secrets/kubernetes.io/serviceaccount/namespace
# 2. 看环境变量
env | grep KUBERNETES
# 3. 拿工牌去 Server API 问一句"我是谁"
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -s --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
-H "Authorization: Bearer $TOKEN" \
https://kubernetes.default.svc/api/v1/namespaces/default/pods | head -c 300
解码 SA
- 在 Pod 中
# 在 pod 里
cut -d. -f2 /var/run/secrets/kubernetes.io/serviceaccount/token | base64 -d 2>/dev/null; echo
- 使用 python 调用
python -c "import base64,json,sys; p=sys.argv[1].split('.')[1]; p+='='*(-len(p)%4); print(json.dumps(json.loads(base64.urlsafe_b64decode(p)), indent=2, ensure_ascii=False))" "<把token粘这里>"
防御视角
- automountServiceAccountToken: false 可以让不需要操作集群的 Pod 没有 SA —— 但很多集群没这么配。
- 真正的防线是:这个 SA 背后的权限要足够小。如果 SA 一定会被偷到,问题是偷到之后能干什么。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)