在Kubernetes集群中,privileged: true这个配置项看起来只是安全上下文里的一个布尔值,但它背后意味着容器几乎拿到了宿主机root用户的全部能力:访问所有设备、修改内核参数、逃逸隔离边界。攻击者一旦控制了一个特权容器,就等于拿到了节点的控制权。本文从风险识别、策略禁用和降权改造三个方面,给出一套可以直接落地的实施方案。

一、特权容器到底危险在哪里
普通容器与宿主机之间隔着多层隔离:Namespace负责资源视图隔离,Cgroups负责资源限制,Capabilities负责切割root权限,Seccomp负责过滤系统调用。而privileged: true会一次性拆除大部分防线。具体来说,特权容器会获得所有Linux capabilities、可以访问/dev下的全部设备、可以挂载宿主机文件系统、Seccomp配置也被禁用。
实际场景中,需要特权的业务其实很少,常见的是一些监控Agent、存储插件和网络组件。问题在于,不少业务团队为了解决一个权限报错,图省事直接加上特权配置,之后就再也没有人去收回。集群规模一大,这些遗留的特权Pod就成了攻击面最大的短板。
先摸清家底,可以用下面的命令快速列出集群里所有运行特权模式的Pod:
kubectl get pods --all-namespaces -o json | \ jq -r '.items[] | select(.spec.containers[].securityContext.privileged == true) | "\(.metadata.namespace)/\(.metadata.name)"'
排查结果通常分三类:确实需要特权的系统组件(如kube-proxy、CNI插件)、可以降权改造的业务Pod、完全没必要特权的遗留配置。第三类应该直接清理,第二类进入降权流程。
二、用准入控制强制禁止特权容器
光靠人工巡检不够,必须从准入层把口子堵死。Kubernetes从1.25开始内置了Pod Security Admission,通过Namespace级别的标签即可强制执行安全标准。推荐对业务Namespace打上restricted标签:
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/audit: restricted这样配置后,任何包含privileged: true、未设置allowPrivilegeEscalation: false或以root运行的新Pod都会被直接拒绝创建,已有Pod不受影响但会有告警。enforce是硬性拦截,warn提示用户,audit记录审计日志,三者组合可以平滑推进。
如果集群版本较老或者需要更灵活的豁免机制(比如只允许特定团队、特定镜像使用特权),可以部署Kyverno或OPA Gatekeeper。下面是Kyverno的一条策略,仅放行kube-system命名空间,其余一律禁止:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-privileged-containers
spec:
validationFailureAction: Enforce
rules:
- name: require-non-privileged
match:
any:
- resources:
kinds: [Pod]
exclude:
any:
- resources:
namespaces: [kube-system]
validate:
message: "禁止使用特权容器,请申请capabilities或专用节点池"
pattern:
spec:
containers:
- =(securityContext):
=(privileged): "false"落地时建议分两阶段:第一阶段用Audit模式跑一到两周,收集哪些工作负载会被拦截;第二阶段切换到Enforce强制生效,避免业务直接被打挂。
三、降权改造:用capabilities替代特权模式
大多数业务申请特权,其实只是缺一两个内核能力,比如绑定1024以下端口的NET_BIND_SERVICE,或者采集网络数据的NET_RAW。正确做法是按需授予capabilities,而不是直接给特权。安全上下文可以这样写:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: web
image: registry.ipipp.com/apps/web:1.24
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
add: ["NET_BIND_SERVICE"]
ports:
- containerPort: 8080这份配置里有几个关键点。drop: ["ALL"]先清空所有能力,再用add按最小化原则加回必需项,这是能力管理的黄金法则。runAsNonRoot配合非零UID让容器进程以普通用户身份运行,即使被攻破也拿不到root。allowPrivilegeEscalation: false阻止子进程通过setuid提权,堵住二进制提权的路径。
readOnlyRootFilesystem: true会让根文件系统只读,配合emptyDir挂载可写目录处理临时文件和日志:
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache/nginx
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}对于确实无法改造的系统级组件(比如需要操作网络设备的CNI插件),不要在普通业务节点上放行,而是建立独立的系统组件节点池,通过节点污点和准入策略把特权工作负载圈定在固定节点上,即使出问题影响范围也可控。
四、持续加固与监控
降权不是一次性工程。建议把安全上下文要求固化到组织的Pod模板、Helm Chart和CI流水线里,新建应用默认携带restricted级别的安全配置,不符合规范的镜像在流水线阶段就被拦截。同时定期用kubectl auth can-i和RBAC审计检查ServiceAccount权限,避免容器虽然降了权但ServiceAccount挂了cluster-admin这种漏洞。
运行时层面,可以开启审计日志跟踪PodSecurityExempt事件,结合Prometheus统计各命名空间违规Pod数量趋势。如果发现某个业务反复申请特权,大概率是架构问题,比如把本该由DaemonSet承担的采集逻辑塞进了业务容器,这时候治本的方式是拆分职责而不是继续加权限。
总结一下,禁用特权容器的完整路径是:先盘点存量、再用准入策略封住增量、然后按最小化原则逐个降权改造、最后用节点池隔离真正的例外场景。每一步都不复杂,难的是坚持执行标准,把安全配置当作代码一样纳入版本管理和评审流程,集群的整体安全水位才能真正提上来。
Kubernetes安全特权容器容器降权修改时间:2026-09-12 16:10:42